Merge "New InboxStyle template for expanded notifications."
diff --git a/Android.mk b/Android.mk
index 4e3929c..3b2d32d 100644
--- a/Android.mk
+++ b/Android.mk
@@ -60,7 +60,7 @@
 ## READ ME: ########################################################
 LOCAL_SRC_FILES += \
 	core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl \
-	core/java/android/accessibilityservice/IEventListener.aidl \
+	core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl \
 	core/java/android/accounts/IAccountManager.aidl \
 	core/java/android/accounts/IAccountManagerResponse.aidl \
 	core/java/android/accounts/IAccountAuthenticator.aidl \
@@ -329,7 +329,10 @@
 	 )
 
 # include definition of libcore_to_document
-include $(LOCAL_PATH)/../../libcore/Docs.mk
+include libcore/Docs.mk
+
+# include definition of junit_to_document
+include external/junit/Common.mk
 
 non_base_dirs := \
 	../../external/apache-http/src/org/apache/http
@@ -353,7 +356,8 @@
 # Common sources for doc check and api check
 common_src_files := \
 	$(call find-other-html-files, $(html_dirs)) \
-	$(addprefix ../../libcore/, $(call libcore_to_document, $(LOCAL_PATH)/../../libcore))
+	$(addprefix ../../libcore/, $(call libcore_to_document, $(LOCAL_PATH)/../../libcore)) \
+	$(addprefix ../../external/junit/, $(call junit_to_document, $(LOCAL_PATH)/../../external/junit))
 
 # These are relative to frameworks/base
 framework_docs_LOCAL_SRC_FILES := \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 1cd5d01..939c117 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -126,6 +126,9 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libRS_intermediates)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libRSDriver_intermediates)
 $(call add-clean-step, rm -rf $(OUT_DIR)/host/$(HOST_PREBUILT_TAG)/obj/STATIC_LIBRARIES/libRS_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/accessibilityservice/IEventListener.java)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/accessibilityservice/IEventListener.P)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/view/accessibility/IAccessibilityManager.P)
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
 # ************************************************
diff --git a/api/16.txt b/api/16.txt
index de99eee..9e9f880 100644
--- a/api/16.txt
+++ b/api/16.txt
@@ -9513,7 +9513,7 @@
     method public abstract void onSensorChanged(int, float[]);
   }
 
-  public class SensorManager {
+  public abstract class SensorManager {
     method public static float getAltitude(float, float);
     method public static void getAngleChange(float[], float[], float[]);
     method public android.hardware.Sensor getDefaultSensor(int);
@@ -15190,11 +15190,11 @@
     method public abstract void released();
   }
 
-  public class Vibrator {
-    method public void cancel();
-    method public boolean hasVibrator();
-    method public void vibrate(long);
-    method public void vibrate(long[], int);
+  public abstract class Vibrator {
+    method public abstract void cancel();
+    method public abstract boolean hasVibrator();
+    method public abstract void vibrate(long);
+    method public abstract void vibrate(long[], int);
   }
 
   public class WorkSource implements android.os.Parcelable {
@@ -24806,7 +24806,7 @@
     enum_constant public static final android.webkit.ConsoleMessage.MessageLevel WARNING;
   }
 
-  public final class CookieManager {
+  public class CookieManager {
     method public synchronized boolean acceptCookie();
     method public static boolean allowFileSchemeCookies();
     method public java.lang.String getCookie(java.lang.String);
@@ -24838,7 +24838,7 @@
     method public abstract void onDownloadStart(java.lang.String, java.lang.String, java.lang.String, java.lang.String, long);
   }
 
-  public final class GeolocationPermissions {
+  public class GeolocationPermissions {
     method public void allow(java.lang.String);
     method public void clear(java.lang.String);
     method public void clearAll();
@@ -24864,8 +24864,6 @@
   public class JsResult {
     method public final void cancel();
     method public final void confirm();
-    method protected final void wakeUp();
-    field protected boolean mResult;
   }
 
   public class MimeTypeMap {
@@ -24958,7 +24956,7 @@
     method public java.lang.String getUrl();
   }
 
-  public final class WebIconDatabase {
+  public class WebIconDatabase {
     method public void close();
     method public static android.webkit.WebIconDatabase getInstance();
     method public void open(java.lang.String);
@@ -25127,7 +25125,7 @@
     enum_constant public static final android.webkit.WebSettings.ZoomDensity MEDIUM;
   }
 
-  public final class WebStorage {
+  public class WebStorage {
     method public void deleteAllData();
     method public void deleteOrigin(java.lang.String);
     method public static android.webkit.WebStorage getInstance();
diff --git a/api/current.txt b/api/current.txt
index 3ba87e6..8d12a56 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -534,6 +534,7 @@
     field public static final int imeSubtypeLocale = 16843500; // 0x10102ec
     field public static final int imeSubtypeMode = 16843501; // 0x10102ed
     field public static final int immersive = 16843456; // 0x10102c0
+    field public static final int importantForAccessibility = 16843698; // 0x10103b2
     field public static final int inAnimation = 16843127; // 0x1010177
     field public static final int includeFontPadding = 16843103; // 0x101015f
     field public static final int includeInGlobalSearch = 16843374; // 0x101026e
@@ -935,7 +936,6 @@
     field public static final int summaryOff = 16843248; // 0x10101f0
     field public static final int summaryOn = 16843247; // 0x10101ef
     field public static final int supportsRtl = 16843688; // 0x10103a8
-    field public static final int supportsSentenceSpellCheck = 16843698; // 0x10103b2
     field public static final int supportsUploading = 16843419; // 0x101029b
     field public static final int switchMinWidth = 16843632; // 0x1010370
     field public static final int switchPadding = 16843633; // 0x1010371
@@ -1993,11 +1993,23 @@
 
   public abstract class AccessibilityService extends android.app.Service {
     ctor public AccessibilityService();
+    method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
     method public abstract void onAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
     method public final android.os.IBinder onBind(android.content.Intent);
+    method protected void onGesture(int);
     method public abstract void onInterrupt();
     method protected void onServiceConnected();
     method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo);
+    field public static final int GESTURE_CLOCKWISE_CIRCLE = 9; // 0x9
+    field public static final int GESTURE_COUNTER_CLOCKWISE_CIRCLE = 10; // 0xa
+    field public static final int GESTURE_SWIPE_DOWN = 2; // 0x2
+    field public static final int GESTURE_SWIPE_DOWN_AND_UP = 8; // 0x8
+    field public static final int GESTURE_SWIPE_LEFT = 3; // 0x3
+    field public static final int GESTURE_SWIPE_LEFT_AND_RIGHT = 5; // 0x5
+    field public static final int GESTURE_SWIPE_RIGHT = 4; // 0x4
+    field public static final int GESTURE_SWIPE_RIGHT_AND_LEFT = 6; // 0x6
+    field public static final int GESTURE_SWIPE_UP = 1; // 0x1
+    field public static final int GESTURE_SWIPE_UP_AND_DOWN = 7; // 0x7
     field public static final java.lang.String SERVICE_INTERFACE = "android.accessibilityservice.AccessibilityService";
     field public static final java.lang.String SERVICE_META_DATA = "android.accessibilityservice";
   }
@@ -2022,6 +2034,7 @@
     field public static final int FEEDBACK_HAPTIC = 2; // 0x2
     field public static final int FEEDBACK_SPOKEN = 1; // 0x1
     field public static final int FEEDBACK_VISUAL = 8; // 0x8
+    field public static final int INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
     field public int eventTypes;
     field public int feedbackType;
     field public int flags;
@@ -2298,6 +2311,8 @@
     ctor public LayoutTransition();
     method public void addChild(android.view.ViewGroup, android.view.View);
     method public void addTransitionListener(android.animation.LayoutTransition.TransitionListener);
+    method public void disableTransitionType(int);
+    method public void enableTransitionType(int);
     method public android.animation.Animator getAnimator(int);
     method public long getDuration(int);
     method public android.animation.TimeInterpolator getInterpolator(int);
@@ -2308,6 +2323,7 @@
     method public void hideChild(android.view.ViewGroup, android.view.View, int);
     method public boolean isChangingLayout();
     method public boolean isRunning();
+    method public boolean isTransitionTypeEnabled(int);
     method public void removeChild(android.view.ViewGroup, android.view.View);
     method public void removeTransitionListener(android.animation.LayoutTransition.TransitionListener);
     method public void setAnimateParentHierarchy(boolean);
@@ -2322,6 +2338,7 @@
     field public static final int APPEARING = 2; // 0x2
     field public static final int CHANGE_APPEARING = 0; // 0x0
     field public static final int CHANGE_DISAPPEARING = 1; // 0x1
+    field public static final int CHANGING = 4; // 0x4
     field public static final int DISAPPEARING = 3; // 0x3
   }
 
@@ -2882,6 +2899,7 @@
   public class ActivityOptions {
     method public void join(android.app.ActivityOptions);
     method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int);
+    method public static android.app.ActivityOptions makeScaleUpAnimation(android.view.View, int, int, int, int);
     method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
     method public android.os.Bundle toBundle();
   }
@@ -3251,6 +3269,7 @@
     method public android.app.DownloadManager.Request addRequestHeader(java.lang.String, java.lang.String);
     method public void allowScanningByMediaScanner();
     method public android.app.DownloadManager.Request setAllowedNetworkTypes(int);
+    method public android.app.DownloadManager.Request setAllowedOverMetered(boolean);
     method public android.app.DownloadManager.Request setAllowedOverRoaming(boolean);
     method public android.app.DownloadManager.Request setDescription(java.lang.CharSequence);
     method public android.app.DownloadManager.Request setDestinationInExternalFilesDir(android.content.Context, java.lang.String, java.lang.String);
@@ -4839,6 +4858,7 @@
     method public android.content.ClipDescription getDescription();
     method public android.content.ClipData.Item getItemAt(int);
     method public int getItemCount();
+    method public static android.content.ClipData newHtmlText(java.lang.CharSequence, java.lang.CharSequence, java.lang.String);
     method public static android.content.ClipData newIntent(java.lang.CharSequence, android.content.Intent);
     method public static android.content.ClipData newPlainText(java.lang.CharSequence, java.lang.CharSequence);
     method public static android.content.ClipData newRawUri(java.lang.CharSequence, android.net.Uri);
@@ -4849,10 +4869,15 @@
 
   public static class ClipData.Item {
     ctor public ClipData.Item(java.lang.CharSequence);
+    ctor public ClipData.Item(java.lang.CharSequence, java.lang.String);
     ctor public ClipData.Item(android.content.Intent);
     ctor public ClipData.Item(android.net.Uri);
     ctor public ClipData.Item(java.lang.CharSequence, android.content.Intent, android.net.Uri);
+    ctor public ClipData.Item(java.lang.CharSequence, java.lang.String, android.content.Intent, android.net.Uri);
+    method public java.lang.String coerceToHtmlText(android.content.Context);
+    method public java.lang.CharSequence coerceToStyledText(android.content.Context);
     method public java.lang.CharSequence coerceToText(android.content.Context);
+    method public java.lang.String getHtmlText();
     method public android.content.Intent getIntent();
     method public java.lang.CharSequence getText();
     method public android.net.Uri getUri();
@@ -4870,6 +4895,7 @@
     method public boolean hasMimeType(java.lang.String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final java.lang.String MIMETYPE_TEXT_HTML = "text/html";
     field public static final java.lang.String MIMETYPE_TEXT_INTENT = "text/vnd.android.intent";
     field public static final java.lang.String MIMETYPE_TEXT_PLAIN = "text/plain";
     field public static final java.lang.String MIMETYPE_TEXT_URILIST = "text/uri-list";
@@ -5707,6 +5733,7 @@
     field public static final int EXTRA_DOCK_STATE_UNDOCKED = 0; // 0x0
     field public static final java.lang.String EXTRA_DONT_KILL_APP = "android.intent.extra.DONT_KILL_APP";
     field public static final java.lang.String EXTRA_EMAIL = "android.intent.extra.EMAIL";
+    field public static final java.lang.String EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT";
     field public static final java.lang.String EXTRA_INITIAL_INTENTS = "android.intent.extra.INITIAL_INTENTS";
     field public static final java.lang.String EXTRA_INSTALLER_PACKAGE_NAME = "android.intent.extra.INSTALLER_PACKAGE_NAME";
     field public static final java.lang.String EXTRA_INTENT = "android.intent.extra.INTENT";
@@ -9001,6 +9028,8 @@
 
   public class SurfaceTexture {
     ctor public SurfaceTexture(int);
+    method public void attachToGLContext(int);
+    method public void detachFromGLContext();
     method public long getTimestamp();
     method public void getTransformMatrix(float[]);
     method public void release();
@@ -9763,7 +9792,7 @@
     method public abstract void onSensorChanged(int, float[]);
   }
 
-  public class SensorManager {
+  public abstract class SensorManager {
     method public static float getAltitude(float, float);
     method public static void getAngleChange(float[], float[], float[]);
     method public android.hardware.Sensor getDefaultSensor(int);
@@ -9779,8 +9808,8 @@
     method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int);
     method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int, android.os.Handler);
     method public static boolean remapCoordinateSystem(float[], int, int, float[]);
-    method public deprecated void unregisterListener(android.hardware.SensorListener, int);
     method public deprecated void unregisterListener(android.hardware.SensorListener);
+    method public deprecated void unregisterListener(android.hardware.SensorListener, int);
     method public void unregisterListener(android.hardware.SensorEventListener, android.hardware.Sensor);
     method public void unregisterListener(android.hardware.SensorEventListener);
     field public static final int AXIS_MINUS_X = 129; // 0x81
@@ -10919,6 +10948,91 @@
     field public static final int STOP_VIDEO_RECORDING = 3; // 0x3
   }
 
+  public final class MediaCodec {
+    method public void configure(java.util.Map<java.lang.String, java.lang.Object>, android.view.Surface, android.media.MediaCrypto, int);
+    method public static android.media.MediaCodec createByCodecName(java.lang.String);
+    method public static android.media.MediaCodec createDecoderByType(java.lang.String);
+    method public static android.media.MediaCodec createEncoderByType(java.lang.String);
+    method public final int dequeueInputBuffer(long);
+    method public final int dequeueOutputBuffer(android.media.MediaCodec.BufferInfo, long);
+    method public final void flush();
+    method public java.nio.ByteBuffer[] getInputBuffers();
+    method public java.nio.ByteBuffer[] getOutputBuffers();
+    method public final java.util.Map<java.lang.String, java.lang.Object> getOutputFormat();
+    method public final void queueInputBuffer(int, int, int, long, int);
+    method public final void queueSecureInputBuffer(int, int, int[], int[], int, byte[], byte[], int, long, int);
+    method public final void release();
+    method public final void releaseOutputBuffer(int, boolean);
+    method public final void start();
+    method public final void stop();
+    field public static int CONFIGURE_FLAG_ENCODE;
+    field public static final int FLAG_CODECCONFIG = 2; // 0x2
+    field public static final int FLAG_EOS = 4; // 0x4
+    field public static final int FLAG_SYNCFRAME = 1; // 0x1
+    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 int MODE_AES_CTR = 1; // 0x1
+    field public static final int MODE_UNENCRYPTED = 0; // 0x0
+  }
+
+  public static final class MediaCodec.BufferInfo {
+    ctor public MediaCodec.BufferInfo();
+    method public void set(int, int, long, int);
+    field public int flags;
+    field public int offset;
+    field public long presentationTimeUs;
+    field public int size;
+  }
+
+  public final class MediaCodecList {
+    method public static final int countCodecs();
+    method public static final android.media.MediaCodecList.CodecCapabilities getCodecCapabilities(int, java.lang.String);
+    method public static final java.lang.String getCodecName(int);
+    method public static final java.lang.String[] getSupportedTypes(int);
+    method public static final boolean isEncoder(int);
+  }
+
+  public static final class MediaCodecList.CodecCapabilities {
+    ctor public MediaCodecList.CodecCapabilities();
+    field public int[] colorFormats;
+    field public android.media.MediaCodecList.CodecProfileLevel[] profileLevels;
+  }
+
+  public static final class MediaCodecList.CodecProfileLevel {
+    ctor public MediaCodecList.CodecProfileLevel();
+    field public int level;
+    field public int profile;
+  }
+
+  public final class MediaCrypto {
+    ctor public MediaCrypto(byte[], byte[]) throws java.lang.RuntimeException;
+    method public static final boolean isCryptoSchemeSupported(byte[]);
+    method public final void release();
+    method public final boolean requiresSecureDecoderComponent(java.lang.String);
+  }
+
+  public final class MediaExtractor {
+    ctor public MediaExtractor();
+    method public boolean advance();
+    method public int countTracks();
+    method public int getSampleFlags();
+    method public long getSampleTime();
+    method public int getSampleTrackIndex();
+    method public java.util.Map<java.lang.String, java.lang.Object> getTrackFormat(int);
+    method public int readSampleData(java.nio.ByteBuffer, int);
+    method public final void release();
+    method public void seekTo(long);
+    method public void selectTrack(int);
+    method public final void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException;
+    method public final void setDataSource(java.lang.String, java.util.Map<java.lang.String, java.lang.String>);
+    method public final void setDataSource(java.lang.String);
+    method public final void setDataSource(java.io.FileDescriptor);
+    method public final void setDataSource(java.io.FileDescriptor, long, long);
+    field public static final int SAMPLE_FLAG_ENCRYPTED = 2; // 0x2
+    field public static final int SAMPLE_FLAG_SYNC = 1; // 0x1
+  }
+
   public class MediaMetadataRetriever {
     ctor public MediaMetadataRetriever();
     method public java.lang.String extractMetadata(int);
@@ -11817,6 +11931,7 @@
     method public deprecated boolean getBackgroundDataSetting();
     method public android.net.NetworkInfo getNetworkInfo(int);
     method public int getNetworkPreference();
+    method public boolean isActiveNetworkMetered();
     method public static boolean isNetworkTypeValid(int);
     method public boolean requestRouteToHost(int, int);
     method public void setNetworkPreference(int);
@@ -12289,6 +12404,86 @@
 
 }
 
+package android.net.nsd {
+
+  public class DnsSdServiceInfo implements android.os.Parcelable {
+    ctor public DnsSdServiceInfo();
+    method public int describeContents();
+    method public java.net.InetAddress getHost();
+    method public int getPort();
+    method public java.lang.String getServiceName();
+    method public java.lang.String getServiceType();
+    method public void setHost(java.net.InetAddress);
+    method public void setPort(int);
+    method public void setServiceName(java.lang.String);
+    method public void setServiceType(java.lang.String);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public class DnsSdTxtRecord implements android.os.Parcelable {
+    ctor public DnsSdTxtRecord();
+    ctor public DnsSdTxtRecord(byte[]);
+    ctor public DnsSdTxtRecord(android.net.nsd.DnsSdTxtRecord);
+    method public boolean contains(java.lang.String);
+    method public int describeContents();
+    method public java.lang.String get(java.lang.String);
+    method public byte[] getRawData();
+    method public int keyCount();
+    method public int remove(java.lang.String);
+    method public void set(java.lang.String, java.lang.String);
+    method public int size();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public class NsdManager {
+    method public void deinitialize(android.net.nsd.NsdManager.Channel);
+    method public void discoverServices(android.net.nsd.NsdManager.Channel, java.lang.String, android.net.nsd.NsdManager.DnsSdDiscoveryListener);
+    method public void initialize(android.content.Context, android.os.Looper, android.net.nsd.NsdManager.ChannelListener);
+    method public void registerService(android.net.nsd.NsdManager.Channel, java.lang.String, java.lang.String, int, android.net.nsd.NsdManager.DnsSdRegisterListener);
+    method public void resolveService(android.net.nsd.NsdManager.Channel, java.lang.String, java.lang.String, android.net.nsd.NsdManager.DnsSdResolveListener);
+    method public void stopServiceDiscovery(android.net.nsd.NsdManager.Channel, android.net.nsd.NsdManager.ActionListener);
+    method public void unregisterService(android.net.nsd.NsdManager.Channel, int, android.net.nsd.NsdManager.ActionListener);
+    field public static final int ALREADY_ACTIVE = 3; // 0x3
+    field public static final int BUSY = 2; // 0x2
+    field public static final int ERROR = 0; // 0x0
+    field public static final int MAX_REGS_REACHED = 4; // 0x4
+    field public static final int UNSUPPORTED = 1; // 0x1
+  }
+
+  public static abstract interface NsdManager.ActionListener {
+    method public abstract void onFailure(int);
+    method public abstract void onSuccess();
+  }
+
+  public static class NsdManager.Channel {
+  }
+
+  public static abstract interface NsdManager.ChannelListener {
+    method public abstract void onChannelConnected(android.net.nsd.NsdManager.Channel);
+    method public abstract void onChannelDisconnected();
+  }
+
+  public static abstract interface NsdManager.DnsSdDiscoveryListener {
+    method public abstract void onFailure(int);
+    method public abstract void onServiceFound(android.net.nsd.DnsSdServiceInfo);
+    method public abstract void onServiceLost(android.net.nsd.DnsSdServiceInfo);
+    method public abstract void onStarted(java.lang.String);
+  }
+
+  public static abstract interface NsdManager.DnsSdRegisterListener {
+    method public abstract void onFailure(int);
+    method public abstract void onServiceRegistered(int, android.net.nsd.DnsSdServiceInfo);
+  }
+
+  public static abstract interface NsdManager.DnsSdResolveListener {
+    method public abstract void onFailure(int);
+    method public abstract void onServiceResolved(android.net.nsd.DnsSdServiceInfo);
+  }
+
+}
+
 package android.net.rtp {
 
   public class AudioCodec {
@@ -12795,15 +12990,26 @@
   }
 
   public class WifiP2pManager {
+    method public void addLocalService(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.nsd.WifiP2pServiceInfo, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+    method public void addServiceRequest(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.nsd.WifiP2pServiceRequest, android.net.wifi.p2p.WifiP2pManager.ActionListener);
     method public void cancelConnect(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+    method public void clearLocalServices(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+    method public void clearServiceRequests(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
     method public void connect(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pConfig, android.net.wifi.p2p.WifiP2pManager.ActionListener);
     method public void createGroup(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
     method public void discoverPeers(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+    method public void discoverServices(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
     method public android.net.wifi.p2p.WifiP2pManager.Channel initialize(android.content.Context, android.os.Looper, android.net.wifi.p2p.WifiP2pManager.ChannelListener);
     method public void removeGroup(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+    method public void removeLocalService(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.nsd.WifiP2pServiceInfo, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+    method public void removeServiceRequest(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.nsd.WifiP2pServiceRequest, android.net.wifi.p2p.WifiP2pManager.ActionListener);
     method public void requestConnectionInfo(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener);
     method public void requestGroupInfo(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.GroupInfoListener);
     method public void requestPeers(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.PeerListListener);
+    method public void setDnsSdResponseListeners(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.DnsSdServiceResponseListener, android.net.wifi.p2p.WifiP2pManager.DnsSdTxtRecordListener);
+    method public void setServiceResponseListener(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ServiceResponseListener);
+    method public void setUpnpServiceResponseListener(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.UpnpServiceResponseListener);
+    method public void stopPeerDiscovery(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
     field public static final int BUSY = 2; // 0x2
     field public static final int ERROR = 0; // 0x0
     field public static final java.lang.String EXTRA_DISCOVERY_STATE = "discoveryState";
@@ -12839,6 +13045,14 @@
     method public abstract void onConnectionInfoAvailable(android.net.wifi.p2p.WifiP2pInfo);
   }
 
+  public static abstract interface WifiP2pManager.DnsSdServiceResponseListener {
+    method public abstract void onDnsSdServiceAvailable(java.lang.String, java.lang.String, android.net.wifi.p2p.WifiP2pDevice);
+  }
+
+  public static abstract interface WifiP2pManager.DnsSdTxtRecordListener {
+    method public abstract void onDnsSdTxtRecordAvailable(java.lang.String, android.net.nsd.DnsSdTxtRecord, android.net.wifi.p2p.WifiP2pDevice);
+  }
+
   public static abstract interface WifiP2pManager.GroupInfoListener {
     method public abstract void onGroupInfoAvailable(android.net.wifi.p2p.WifiP2pGroup);
   }
@@ -12847,6 +13061,53 @@
     method public abstract void onPeersAvailable(android.net.wifi.p2p.WifiP2pDeviceList);
   }
 
+  public static abstract interface WifiP2pManager.ServiceResponseListener {
+    method public abstract void onServiceAvailable(int, byte[], android.net.wifi.p2p.WifiP2pDevice);
+  }
+
+  public static abstract interface WifiP2pManager.UpnpServiceResponseListener {
+    method public abstract void onUpnpServiceAvailable(java.util.List<java.lang.String>, android.net.wifi.p2p.WifiP2pDevice);
+  }
+
+}
+
+package android.net.wifi.p2p.nsd {
+
+  public class WifiP2pDnsSdServiceInfo extends android.net.wifi.p2p.nsd.WifiP2pServiceInfo {
+    method public static android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceInfo newInstance(java.lang.String, java.lang.String, android.net.nsd.DnsSdTxtRecord);
+  }
+
+  public class WifiP2pDnsSdServiceRequest extends android.net.wifi.p2p.nsd.WifiP2pServiceRequest {
+    method public static android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest newInstance();
+    method public static android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest newInstance(java.lang.String);
+    method public static android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest newInstance(java.lang.String, java.lang.String);
+  }
+
+  public class WifiP2pServiceInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int SERVICE_TYPE_ALL = 0; // 0x0
+    field public static final int SERVICE_TYPE_BONJOUR = 1; // 0x1
+    field public static final int SERVICE_TYPE_UPNP = 2; // 0x2
+    field public static final int SERVICE_TYPE_VENDOR_SPECIFIC = 255; // 0xff
+  }
+
+  public class WifiP2pServiceRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.net.wifi.p2p.nsd.WifiP2pServiceRequest newInstance(int, java.lang.String);
+    method public static android.net.wifi.p2p.nsd.WifiP2pServiceRequest newInstance(int);
+    method public void writeToParcel(android.os.Parcel, int);
+  }
+
+  public class WifiP2pUpnpServiceInfo extends android.net.wifi.p2p.nsd.WifiP2pServiceInfo {
+    method public static android.net.wifi.p2p.nsd.WifiP2pUpnpServiceInfo newInstance(java.lang.String, java.lang.String, java.util.List<java.lang.String>);
+  }
+
+  public class WifiP2pUpnpServiceRequest extends android.net.wifi.p2p.nsd.WifiP2pServiceRequest {
+    method public static android.net.wifi.p2p.nsd.WifiP2pUpnpServiceRequest newInstance();
+    method public static android.net.wifi.p2p.nsd.WifiP2pUpnpServiceRequest newInstance(java.lang.String);
+  }
+
 }
 
 package android.nfc {
@@ -12911,6 +13172,8 @@
     method public static android.nfc.NfcAdapter getDefaultAdapter(android.content.Context);
     method public boolean isEnabled();
     method public boolean isNdefPushEnabled();
+    method public void setBeamPushUris(android.net.Uri[], android.app.Activity);
+    method public void setBeamPushUrisCallback(android.nfc.NfcAdapter.CreateBeamUrisCallback, android.app.Activity);
     method public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, android.app.Activity...);
     method public void setNdefPushMessageCallback(android.nfc.NfcAdapter.CreateNdefMessageCallback, android.app.Activity, android.app.Activity...);
     method public void setOnNdefPushCompleteCallback(android.nfc.NfcAdapter.OnNdefPushCompleteCallback, android.app.Activity, android.app.Activity...);
@@ -12922,6 +13185,10 @@
     field public static final java.lang.String EXTRA_TAG = "android.nfc.extra.TAG";
   }
 
+  public static abstract interface NfcAdapter.CreateBeamUrisCallback {
+    method public abstract android.net.Uri[] createBeamUris(android.nfc.NfcEvent);
+  }
+
   public static abstract interface NfcAdapter.CreateNdefMessageCallback {
     method public abstract android.nfc.NdefMessage createNdefMessage(android.nfc.NfcEvent);
   }
@@ -15506,11 +15773,11 @@
     ctor public TransactionTooLargeException();
   }
 
-  public class Vibrator {
-    method public void cancel();
-    method public boolean hasVibrator();
-    method public void vibrate(long);
-    method public void vibrate(long[], int);
+  public abstract class Vibrator {
+    method public abstract void cancel();
+    method public abstract boolean hasVibrator();
+    method public abstract void vibrate(long);
+    method public abstract void vibrate(long[], int);
   }
 
   public class WorkSource implements android.os.Parcelable {
@@ -16004,6 +16271,8 @@
 
   protected static abstract interface CalendarContract.AttendeesColumns {
     field public static final java.lang.String ATTENDEE_EMAIL = "attendeeEmail";
+    field public static final java.lang.String ATTENDEE_IDENTITY = "attendeeIdentity";
+    field public static final java.lang.String ATTENDEE_ID_NAMESPACE = "attendeeIdNamespace";
     field public static final java.lang.String ATTENDEE_NAME = "attendeeName";
     field public static final java.lang.String ATTENDEE_RELATIONSHIP = "attendeeRelationship";
     field public static final java.lang.String ATTENDEE_STATUS = "attendeeStatus";
@@ -16859,7 +17128,7 @@
     method public static android.net.Uri getLookupUri(android.content.ContentResolver, android.net.Uri);
     method public static android.net.Uri getLookupUri(long, java.lang.String);
     method public static android.net.Uri lookupContact(android.content.ContentResolver, android.net.Uri);
-    method public static void markAsContacted(android.content.ContentResolver, long);
+    method public static deprecated void markAsContacted(android.content.ContentResolver, long);
     method public static java.io.InputStream openContactPhotoInputStream(android.content.ContentResolver, android.net.Uri, boolean);
     method public static java.io.InputStream openContactPhotoInputStream(android.content.ContentResolver, android.net.Uri);
     field public static final android.net.Uri CONTENT_FILTER_URI;
@@ -16950,6 +17219,7 @@
 
   public static final class ContactsContract.DataUsageFeedback {
     ctor public ContactsContract.DataUsageFeedback();
+    field public static final android.net.Uri DELETE_USAGE_URI;
     field public static final android.net.Uri FEEDBACK_URI;
     field public static final java.lang.String USAGE_TYPE = "type";
     field public static final java.lang.String USAGE_TYPE_CALL = "call";
@@ -20405,6 +20675,7 @@
   }
 
   public class Html {
+    method public static java.lang.String escapeHtml(java.lang.CharSequence);
     method public static android.text.Spanned fromHtml(java.lang.String);
     method public static android.text.Spanned fromHtml(java.lang.String, android.text.Html.ImageGetter, android.text.Html.TagHandler);
     method public static java.lang.String toHtml(android.text.Spanned);
@@ -22352,6 +22623,7 @@
     method public java.util.List<android.view.InputDevice.MotionRange> getMotionRanges();
     method public java.lang.String getName();
     method public int getSources();
+    method public android.os.Vibrator getVibrator();
     method public boolean isVirtual();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
@@ -23278,6 +23550,7 @@
     method public android.graphics.Canvas lockCanvas(android.graphics.Rect);
     method protected final void onDraw(android.graphics.Canvas);
     method public void setOpaque(boolean);
+    method public void setSurfaceTexture(android.graphics.SurfaceTexture);
     method public void setSurfaceTextureListener(android.view.TextureView.SurfaceTextureListener);
     method public void setTransform(android.graphics.Matrix);
     method public void unlockCanvasAndPost(android.graphics.Canvas);
@@ -23316,6 +23589,7 @@
     ctor public View(android.content.Context);
     ctor public View(android.content.Context, android.util.AttributeSet);
     ctor public View(android.content.Context, android.util.AttributeSet, int);
+    method public void addChildrenForAccessibility(java.util.ArrayList<android.view.View>);
     method public void addFocusables(java.util.ArrayList<android.view.View>, int);
     method public void addFocusables(java.util.ArrayList<android.view.View>, int, int);
     method public void addOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
@@ -23418,6 +23692,7 @@
     method public int getHorizontalFadingEdgeLength();
     method protected int getHorizontalScrollbarHeight();
     method public int getId();
+    method public int getImportantForAccessibility();
     method public boolean getKeepScreenOn();
     method public android.view.KeyEvent.DispatcherState getKeyDispatcherState();
     method public int getLayerType();
@@ -23451,6 +23726,7 @@
     method public int getPaddingStart();
     method public int getPaddingTop();
     method public final android.view.ViewParent getParent();
+    method public android.view.ViewParent getParentForAccessibility();
     method public float getPivotX();
     method public float getPivotY();
     method public int getResolvedLayoutDirection();
@@ -23606,6 +23882,7 @@
     method public void onWindowSystemUiVisibilityChanged(int);
     method protected void onWindowVisibilityChanged(int);
     method protected boolean overScrollBy(int, int, int, int, int, int, int, int, boolean);
+    method public boolean performAccessibilityAction(int);
     method public boolean performClick();
     method public boolean performHapticFeedback(int);
     method public boolean performHapticFeedback(int, int);
@@ -23677,6 +23954,7 @@
     method public void setHorizontalScrollBarEnabled(boolean);
     method public void setHovered(boolean);
     method public void setId(int);
+    method public void setImportantForAccessibility(int);
     method public void setKeepScreenOn(boolean);
     method public void setLayerType(int, android.graphics.Paint);
     method public void setLayoutDirection(int);
@@ -23751,6 +24029,14 @@
     method protected boolean verifyDrawable(android.graphics.drawable.Drawable);
     method public boolean willNotCacheDrawing();
     method public boolean willNotDraw();
+    field public static final int ACCESSIBILITY_FOCUS_BACKWARD = 4097; // 0x1001
+    field public static final int ACCESSIBILITY_FOCUS_DOWN = 4226; // 0x1082
+    field public static final int ACCESSIBILITY_FOCUS_FORWARD = 4098; // 0x1002
+    field public static final int ACCESSIBILITY_FOCUS_IN = 4100; // 0x1004
+    field public static final int ACCESSIBILITY_FOCUS_LEFT = 4113; // 0x1011
+    field public static final int ACCESSIBILITY_FOCUS_OUT = 4104; // 0x1008
+    field public static final int ACCESSIBILITY_FOCUS_RIGHT = 4162; // 0x1042
+    field public static final int ACCESSIBILITY_FOCUS_UP = 4129; // 0x1021
     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
@@ -23772,6 +24058,7 @@
     field protected static final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET;
     field protected static final int[] FOCUSED_STATE_SET;
     field protected static final int[] FOCUSED_WINDOW_FOCUSED_STATE_SET;
+    field public static final int FOCUS_ACCESSIBILITY = 4096; // 0x1000
     field public static final int FOCUS_BACKWARD = 1; // 0x1
     field public static final int FOCUS_DOWN = 130; // 0x82
     field public static final int FOCUS_FORWARD = 2; // 0x2
@@ -23780,6 +24067,9 @@
     field public static final int FOCUS_UP = 33; // 0x21
     field public static final int GONE = 8; // 0x8
     field public static final int HAPTIC_FEEDBACK_ENABLED = 268435456; // 0x10000000
+    field public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0; // 0x0
+    field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 2; // 0x2
+    field public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 1; // 0x1
     field public static final int INVISIBLE = 4; // 0x4
     field public static final int KEEP_SCREEN_ON = 67108864; // 0x4000000
     field public static final int LAYER_TYPE_HARDWARE = 2; // 0x2
@@ -24085,6 +24375,7 @@
     method public android.view.View getFocusedChild();
     method public android.view.animation.LayoutAnimationController getLayoutAnimation();
     method public android.view.animation.Animation.AnimationListener getLayoutAnimationListener();
+    method public int getLayoutMode();
     method public android.animation.LayoutTransition getLayoutTransition();
     method public int getPersistentDrawingCache();
     method public int indexOfChild(android.view.View);
@@ -24132,6 +24423,7 @@
     method public void setDescendantFocusability(int);
     method public void setLayoutAnimation(android.view.animation.LayoutAnimationController);
     method public void setLayoutAnimationListener(android.view.animation.Animation.AnimationListener);
+    method public void setLayoutMode(int);
     method public void setLayoutTransition(android.animation.LayoutTransition);
     method public void setMotionEventSplittingEnabled(boolean);
     method public void setOnHierarchyChangeListener(android.view.ViewGroup.OnHierarchyChangeListener);
@@ -24144,9 +24436,11 @@
     method public void startViewTransition(android.view.View);
     method public void updateViewLayout(android.view.View, android.view.ViewGroup.LayoutParams);
     field protected static final int CLIP_TO_PADDING_MASK = 34; // 0x22
+    field public static final int COMPONENT_BOUNDS = 0; // 0x0
     field public static final int FOCUS_AFTER_DESCENDANTS = 262144; // 0x40000
     field public static final int FOCUS_BEFORE_DESCENDANTS = 131072; // 0x20000
     field public static final int FOCUS_BLOCK_DESCENDANTS = 393216; // 0x60000
+    field public static final int LAYOUT_BOUNDS = 1; // 0x1
     field public static final int PERSISTENT_ALL_CACHES = 3; // 0x3
     field public static final int PERSISTENT_ANIMATION_CACHE = 1; // 0x1
     field public static final int PERSISTENT_NO_CACHE = 0; // 0x0
@@ -24204,6 +24498,7 @@
     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 android.view.ViewParent getParent();
+    method public abstract android.view.ViewParent getParentForAccessibility();
     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 isLayoutRequested();
@@ -24605,6 +24900,8 @@
     field public static final int TYPE_NOTIFICATION_STATE_CHANGED = 64; // 0x40
     field public static final int TYPE_TOUCH_EXPLORATION_GESTURE_END = 1024; // 0x400
     field public static final int TYPE_TOUCH_EXPLORATION_GESTURE_START = 512; // 0x200
+    field public static final int TYPE_VIEW_ACCESSIBILITY_FOCUSED = 32768; // 0x8000
+    field public static final int TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED = 65536; // 0x10000
     field public static final int TYPE_VIEW_CLICKED = 1; // 0x1
     field public static final int TYPE_VIEW_FOCUSED = 8; // 0x8
     field public static final int TYPE_VIEW_HOVER_ENTER = 128; // 0x80
@@ -24645,6 +24942,8 @@
     method public void addChild(android.view.View, int);
     method public int describeContents();
     method public java.util.List<android.view.accessibility.AccessibilityNodeInfo> findAccessibilityNodeInfosByText(java.lang.String);
+    method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
+    method public android.view.accessibility.AccessibilityNodeInfo focusSearch(int);
     method public int getActions();
     method public void getBoundsInParent(android.graphics.Rect);
     method public void getBoundsInScreen(android.graphics.Rect);
@@ -24656,6 +24955,7 @@
     method public android.view.accessibility.AccessibilityNodeInfo getParent();
     method public java.lang.CharSequence getText();
     method public int getWindowId();
+    method public boolean isAccessibilityFocused();
     method public boolean isCheckable();
     method public boolean isChecked();
     method public boolean isClickable();
@@ -24672,6 +24972,7 @@
     method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.accessibility.AccessibilityNodeInfo);
     method public boolean performAction(int);
     method public void recycle();
+    method public void setAccessibilityFocused(boolean);
     method public void setBoundsInParent(android.graphics.Rect);
     method public void setBoundsInScreen(android.graphics.Rect);
     method public void setCheckable(boolean);
@@ -24693,16 +24994,23 @@
     method public void setSource(android.view.View, int);
     method public void setText(java.lang.CharSequence);
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final int ACTION_ACCESSIBILITY_FOCUS = 16; // 0x10
+    field public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 32; // 0x20
     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 = 64; // 0x40
     field public static final int ACTION_FOCUS = 1; // 0x1
     field public static final int ACTION_SELECT = 4; // 0x4
     field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final int FOCUS_ACCESSIBILITY = 2; // 0x2
+    field public static final int FOCUS_INPUT = 1; // 0x1
   }
 
   public abstract class AccessibilityNodeProvider {
     ctor public AccessibilityNodeProvider();
+    method public android.view.accessibility.AccessibilityNodeInfo accessibilityFocusSearch(int, int);
     method public android.view.accessibility.AccessibilityNodeInfo createAccessibilityNodeInfo(int);
+    method public android.view.accessibility.AccessibilityNodeInfo findAccessibilitiyFocus(int);
     method public java.util.List<android.view.accessibility.AccessibilityNodeInfo> findAccessibilityNodeInfosByText(java.lang.String, int);
     method public boolean performAccessibilityAction(int, int);
   }
@@ -25369,9 +25677,8 @@
     method public void close();
     method public void getSentenceSuggestions(android.view.textservice.TextInfo[], int);
     method public android.view.textservice.SpellCheckerInfo getSpellChecker();
-    method public void getSuggestions(android.view.textservice.TextInfo, int);
-    method public void getSuggestions(android.view.textservice.TextInfo[], int, boolean);
-    method public boolean isSentenceSpellCheckSupported();
+    method public deprecated void getSuggestions(android.view.textservice.TextInfo, int);
+    method public deprecated void getSuggestions(android.view.textservice.TextInfo[], int, boolean);
     method public boolean isSessionDisconnected();
     field public static final java.lang.String SERVICE_META_DATA = "android.view.textservice.scs";
   }
@@ -25479,7 +25786,7 @@
     enum_constant public static final android.webkit.ConsoleMessage.MessageLevel WARNING;
   }
 
-  public final class CookieManager {
+  public class CookieManager {
     method public synchronized boolean acceptCookie();
     method public static boolean allowFileSchemeCookies();
     method public java.lang.String getCookie(java.lang.String);
@@ -25511,7 +25818,7 @@
     method public abstract void onDownloadStart(java.lang.String, java.lang.String, java.lang.String, java.lang.String, long);
   }
 
-  public final class GeolocationPermissions {
+  public class GeolocationPermissions {
     method public void allow(java.lang.String);
     method public void clear(java.lang.String);
     method public void clearAll();
@@ -25537,8 +25844,6 @@
   public class JsResult {
     method public final void cancel();
     method public final void confirm();
-    method protected final void wakeUp();
-    field protected boolean mResult;
   }
 
   public class MimeTypeMap {
@@ -25631,7 +25936,7 @@
     method public java.lang.String getUrl();
   }
 
-  public final class WebIconDatabase {
+  public class WebIconDatabase {
     method public void close();
     method public static android.webkit.WebIconDatabase getInstance();
     method public void open(java.lang.String);
@@ -25800,7 +26105,7 @@
     enum_constant public static final android.webkit.WebSettings.ZoomDensity MEDIUM;
   }
 
-  public final class WebStorage {
+  public class WebStorage {
     method public void deleteAllData();
     method public void deleteOrigin(java.lang.String);
     method public static android.webkit.WebStorage getInstance();
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index ddd7f7c..3da35d3 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -19,17 +19,22 @@
 import android.app.Service;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Configuration;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
+import android.util.LocaleUtil;
 import android.util.Log;
+import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityInteractionClient;
 import android.view.accessibility.AccessibilityNodeInfo;
 
 import com.android.internal.os.HandlerCaller;
 
+import java.util.Locale;
+
 /**
  * An accessibility service runs in the background and receives callbacks by the system
  * when {@link AccessibilityEvent}s are fired. Such events denote some state transition
@@ -202,12 +207,65 @@
  * @see android.view.accessibility.AccessibilityManager
  */
 public abstract class AccessibilityService extends Service {
+
+    /**
+     * The user has performed a swipe up gesture on the touch screen.
+     */
+    public static final int GESTURE_SWIPE_UP = 1;
+
+    /**
+     * The user has performed a swipe down gesture on the touch screen.
+     */
+    public static final int GESTURE_SWIPE_DOWN = 2;
+
+    /**
+     * The user has performed a swipe left gesture on the touch screen.
+     */
+    public static final int GESTURE_SWIPE_LEFT = 3;
+
+    /**
+     * The user has performed a swipe right gesture on the touch screen.
+     */
+    public static final int GESTURE_SWIPE_RIGHT = 4;
+
+    /**
+     * The user has performed a swipe left and right gesture on the touch screen.
+     */
+    public static final int GESTURE_SWIPE_LEFT_AND_RIGHT = 5;
+
+    /**
+     * The user has performed a swipe right and left gesture on the touch screen.
+     */
+    public static final int GESTURE_SWIPE_RIGHT_AND_LEFT = 6;
+
+    /**
+     * The user has performed a swipe up and down gesture on the touch screen.
+     */
+    public static final int GESTURE_SWIPE_UP_AND_DOWN = 7;
+
+    /**
+     * The user has performed a swipe down and up gesture on the touch screen.
+     */
+    public static final int GESTURE_SWIPE_DOWN_AND_UP = 8;
+
+    /**
+     * The user has performed a clockwise circle gesture on the touch screen.
+     */
+    public static final int GESTURE_CLOCKWISE_CIRCLE = 9;
+
+    /**
+     * The user has performed a counter clockwise circle gesture on the touch screen.
+     */
+    public static final int GESTURE_COUNTER_CLOCKWISE_CIRCLE = 10;
+
     /**
      * The {@link Intent} that must be declared as handled by the service.
      */
     public static final String SERVICE_INTERFACE =
         "android.accessibilityservice.AccessibilityService";
 
+    private static final int UNDEFINED = -1;
+
     /**
      * Name under which an AccessibilityService component publishes information
      * about itself. This meta-data must reference an XML resource containing an
@@ -233,12 +291,15 @@
         public void onInterrupt();
         public void onServiceConnected();
         public void onSetConnectionId(int connectionId);
+        public void onGesture(int gestureId);
     }
 
     private int mConnectionId;
 
     private AccessibilityServiceInfo mInfo;
 
+    private int mLayoutDirection;
+
     /**
      * Callback for {@link android.view.accessibility.AccessibilityEvent}s.
      *
@@ -264,6 +325,106 @@
     }
 
     /**
+     * Called by the system when the user performs a specific gesture on the
+     * touch screen.
+     *
+     * @param gestureId The unique id of the performed gesture.
+     *
+     * @see #GESTURE_SWIPE_UP
+     * @see #GESTURE_SWIPE_DOWN
+     * @see #GESTURE_SWIPE_LEFT
+     * @see #GESTURE_SWIPE_RIGHT
+     * @see #GESTURE_SWIPE_UP_AND_DOWN
+     * @see #GESTURE_SWIPE_DOWN_AND_UP
+     * @see #GESTURE_SWIPE_LEFT_AND_RIGHT
+     * @see #GESTURE_SWIPE_RIGHT_AND_LEFT
+     * @see #GESTURE_CLOCKWISE_CIRCLE
+     * @see #GESTURE_COUNTER_CLOCKWISE_CIRCLE
+     */
+    protected void onGesture(int gestureId) {
+        // TODO: Describe the default gesture processing in the javaDoc once it is finalized.
+
+        // Cache the id to avoid locking
+        final int connectionId = mConnectionId;
+        if (connectionId == UNDEFINED) {
+            throw new IllegalStateException("AccessibilityService not connected."
+                    + " Did you receive a call of onServiceConnected()?");
+        }
+        AccessibilityNodeInfo root = AccessibilityInteractionClient.getInstance()
+                .findAccessibilityNodeInfoByAccessibilityId(connectionId,
+                        AccessibilityNodeInfo.ACTIVE_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID,
+                        AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS);
+        if (root == null) {
+            return;
+        }
+        AccessibilityNodeInfo current = root.findFocus(View.FOCUS_ACCESSIBILITY);
+        if (current == null) {
+            current = root;
+        }
+        AccessibilityNodeInfo next = null;
+        switch (gestureId) {
+            case GESTURE_SWIPE_UP: {
+                next = current.focusSearch(View.ACCESSIBILITY_FOCUS_OUT);
+            } break;
+            case GESTURE_SWIPE_DOWN: {
+                next = current.focusSearch(View.ACCESSIBILITY_FOCUS_IN);
+            } break;
+            case GESTURE_SWIPE_LEFT: {
+                if (mLayoutDirection == View.LAYOUT_DIRECTION_LTR) {
+                    next = current.focusSearch(View.ACCESSIBILITY_FOCUS_BACKWARD);
+                } else { // LAYOUT_DIRECTION_RTL
+                    next = current.focusSearch(View.ACCESSIBILITY_FOCUS_FORWARD);
+                }
+            } break;
+            case GESTURE_SWIPE_RIGHT: {
+                if (mLayoutDirection == View.LAYOUT_DIRECTION_LTR) {
+                    next = current.focusSearch(View.ACCESSIBILITY_FOCUS_FORWARD);
+                } else { // LAYOUT_DIRECTION_RTL
+                    next = current.focusSearch(View.ACCESSIBILITY_FOCUS_BACKWARD);
+                }
+            } break;
+            case GESTURE_SWIPE_UP_AND_DOWN: {
+                next = current.focusSearch(View.ACCESSIBILITY_FOCUS_UP);
+            } break;
+            case GESTURE_SWIPE_DOWN_AND_UP: {
+                next = current.focusSearch(View.ACCESSIBILITY_FOCUS_DOWN);
+            } break;
+            case GESTURE_SWIPE_LEFT_AND_RIGHT: {
+                next = current.focusSearch(View.ACCESSIBILITY_FOCUS_LEFT);
+            } break;
+            case GESTURE_SWIPE_RIGHT_AND_LEFT: {
+                next = current.focusSearch(View.ACCESSIBILITY_FOCUS_RIGHT);
+            } break;
+        }
+        if (next != null && !next.equals(current)) {
+            next.performAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
+        }
+    }
+
+    /**
+     * Gets the an {@link AccessibilityServiceInfo} describing this
+     * {@link AccessibilityService}. This method is useful if one wants
+     * to change some of the dynamically configurable properties at
+     * runtime.
+     *
+     * @return The accessibility service info.
+     *
+     * @see AccessibilityNodeInfo
+     */
+    public final AccessibilityServiceInfo getServiceInfo() {
+        IAccessibilityServiceConnection connection =
+            AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
+        if (connection != null) {
+            try {
+                return connection.getServiceInfo();
+            } catch (RemoteException re) {
+                Log.w(LOG_TAG, "Error while getting AccessibilityServiceInfo", re);
+            }
+        }
+        return null;
+    }
+
+    /**
      * Sets the {@link AccessibilityServiceInfo} that describes this service.
      * <p>
      * Note: You can call this method any time but the info will be picked up after
@@ -287,19 +448,33 @@
         if (mInfo != null && connection != null) {
             try {
                 connection.setServiceInfo(mInfo);
+                mInfo = null;
+                AccessibilityInteractionClient.getInstance().clearCache();
             } catch (RemoteException re) {
                 Log.w(LOG_TAG, "Error while setting AccessibilityServiceInfo", re);
             }
         }
     }
 
+    @Override
+    public void onCreate() {
+        Locale locale = getResources().getConfiguration().locale;
+        mLayoutDirection = LocaleUtil.getLayoutDirectionFromLocale(locale);
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration configuration) {
+        super.onConfigurationChanged(configuration);
+        mLayoutDirection = LocaleUtil.getLayoutDirectionFromLocale(configuration.locale);
+    }
+
     /**
      * Implement to return the implementation of the internal accessibility
      * service interface.
      */
     @Override
     public final IBinder onBind(Intent intent) {
-        return new IEventListenerWrapper(this, getMainLooper(), new Callbacks() {
+        return new IAccessibilityServiceClientWrapper(this, getMainLooper(), new Callbacks() {
             @Override
             public void onServiceConnected() {
                 AccessibilityService.this.onServiceConnected();
@@ -319,14 +494,19 @@
             public void onSetConnectionId( int connectionId) {
                 mConnectionId = connectionId;
             }
+
+            @Override
+            public void onGesture(int gestureId) {
+                AccessibilityService.this.onGesture(gestureId);
+            }
         });
     }
 
     /**
-     * Implements the internal {@link IEventListener} interface to convert
+     * Implements the internal {@link IAccessibilityServiceClient} interface to convert
      * incoming calls to it back to calls on an {@link AccessibilityService}.
      */
-    static class IEventListenerWrapper extends IEventListener.Stub
+    static class IAccessibilityServiceClientWrapper extends IAccessibilityServiceClient.Stub
             implements HandlerCaller.Callback {
 
         static final int NO_ID = -1;
@@ -334,12 +514,14 @@
         private static final int DO_SET_SET_CONNECTION = 10;
         private static final int DO_ON_INTERRUPT = 20;
         private static final int DO_ON_ACCESSIBILITY_EVENT = 30;
+        private static final int DO_ON_GESTURE = 40;
 
         private final HandlerCaller mCaller;
 
         private final Callbacks mCallback;
 
-        public IEventListenerWrapper(Context context, Looper looper, Callbacks callback) {
+        public IAccessibilityServiceClientWrapper(Context context, Looper looper,
+                Callbacks callback) {
             mCallback = callback;
             mCaller = new HandlerCaller(context, looper, this);
         }
@@ -360,6 +542,11 @@
             mCaller.sendMessage(message);
         }
 
+        public void onGesture(int gestureId) {
+            Message message = mCaller.obtainMessageI(DO_ON_GESTURE, gestureId);
+            mCaller.sendMessage(message);
+        }
+
         public void executeMessage(Message message) {
             switch (message.what) {
                 case DO_ON_ACCESSIBILITY_EVENT :
@@ -387,6 +574,10 @@
                         mCallback.onSetConnectionId(AccessibilityInteractionClient.NO_ID);
                     }
                     return;
+                case DO_ON_GESTURE :
+                    final int gestureId = message.arg1;
+                    mCallback.onGesture(gestureId);
+                    return;
                 default :
                     Log.w(LOG_TAG, "Unknown message type " + message.what);
             }
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 8e53431..e77ed9a 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -25,11 +25,13 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.AttributeSet;
 import android.util.TypedValue;
 import android.util.Xml;
+import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -101,6 +103,37 @@
     public static final int DEFAULT = 0x0000001;
 
     /**
+     * If this flag is set the system will regard views that are not important
+     * for accessibility in addition to the ones that are important for accessibility.
+     * That is, views that are marked as not important for accessibility via
+     * {@link View#IMPORTANT_FOR_ACCESSIBILITY_NO} and views that are marked as
+     * potentially important for accessibility via
+     * {@link View#IMPORTANT_FOR_ACCESSIBILITY_AUTO} for which the system has determined
+     * that are not important for accessibility, are both reported while querying the
+     * window content and also the accessibility service will receive accessibility events
+     * from them.
+     * <p>
+     * <strong>Note:</strong> For accessibility services targeting API version
+     * {@link Build.VERSION_CODES#JELLY_BEAN} or higher this flag has to be explicitly
+     * set for the system to regard views that are not important for accessibility. For
+     * accessibility services targeting API version lower than
+     * {@link Build.VERSION_CODES#JELLY_BEAN} this flag is ignored and all views are
+     * regarded for accessibility purposes.
+     * </p>
+     * <p>
+     * Usually views not important for accessibility are layout managers that do not
+     * react to user actions, do not draw any content, and do not have any special
+     * semantics in the context of the screen content. For example, a three by three
+     * grid can be implemented as three horizontal linear layouts and one vertical,
+     * or three vertical linear layouts and one horizontal, or one grid layout, etc.
+     * In this context the actual layout mangers used to achieve the grid configuration
+     * are not important, rather it is important that there are nine evenly distributed
+     * elements.
+     * </p>
+     */
+    public static final int INCLUDE_NOT_IMPORTANT_VIEWS = 0x0000002;
+
+    /**
      * The event types an {@link AccessibilityService} is interested in.
      * <p>
      *   <strong>Can be dynamically set at runtime.</strong>
@@ -165,6 +198,7 @@
      *   <strong>Can be dynamically set at runtime.</strong>
      * </p>
      * @see #DEFAULT
+     * @see #INCLUDE_NOT_IMPORTANT_VIEWS
      */
     public int flags;
 
@@ -561,6 +595,8 @@
         switch (flag) {
             case DEFAULT:
                 return "DEFAULT";
+            case INCLUDE_NOT_IMPORTANT_VIEWS:
+                return "REGARD_VIEWS_NOT_IMPORTANT_FOR_ACCESSIBILITY";
             default:
                 return null;
         }
diff --git a/core/java/android/accessibilityservice/IEventListener.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
similarity index 86%
rename from core/java/android/accessibilityservice/IEventListener.aidl
rename to core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
index 5536b3c..588728c 100644
--- a/core/java/android/accessibilityservice/IEventListener.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
@@ -20,15 +20,17 @@
 import android.view.accessibility.AccessibilityEvent;
 
 /**
- * Top-level interface to accessibility service component (implemented in Service).
+ * Top-level interface to an accessibility service component.
  *
  * @hide
  */
- oneway interface IEventListener {
+ oneway interface IAccessibilityServiceClient {
 
     void setConnection(in IAccessibilityServiceConnection connection, int connectionId);
 
     void onAccessibilityEvent(in AccessibilityEvent event);
 
     void onInterrupt();
+
+    void onGesture(int gestureId);
 }
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index 8d17325..30da9db 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -41,13 +41,13 @@
      *     to start from the root.
      * @param interactionId The id of the interaction for matching with the callback result.
      * @param callback Callback which to receive the result.
+     * @param flags Additional flags.
      * @param threadId The id of the calling thread.
-     * @param prefetchFlags flags to guide prefetching.
      * @return The current window scale, where zero means a failure.
      */
     float findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
         long accessibilityNodeId, int interactionId,
-        IAccessibilityInteractionConnectionCallback callback, long threadId, int prefetchFlags);
+        IAccessibilityInteractionConnectionCallback callback, int flags, long threadId);
 
     /**
      * Finds {@link android.view.accessibility.AccessibilityNodeInfo}s by View text.
@@ -94,6 +94,48 @@
         long threadId);
 
     /**
+     * Finds the {@link android.view.accessibility.AccessibilityNodeInfo} that has the specified
+     * focus type. The search is performed in the window whose id is specified and starts from
+     * the node whose accessibility id is specified.
+     *
+     * @param accessibilityWindowId A unique window id. Use
+     *     {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID}
+     *     to query the currently active window.
+     * @param accessibilityNodeId A unique view id or virtual descendant id from
+     *     where to start the search. Use
+     *     {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID}
+     *     to start from the root.
+     * @param focusType The type of focus to find.
+     * @param interactionId The id of the interaction for matching with the callback result.
+     * @param callback Callback which to receive the result.
+     * @param threadId The id of the calling thread.
+     * @return The current window scale, where zero means a failure.
+     */
+    float findFocus(int accessibilityWindowId, long accessibilityNodeId, int focusType,
+        int interactionId, IAccessibilityInteractionConnectionCallback callback, long threadId);
+
+    /**
+     * Finds an {@link android.view.accessibility.AccessibilityNodeInfo} to take accessibility
+     * focus in the given direction. The search is performed in the window whose id is
+     * specified and starts from the node whose accessibility id is specified.
+     *
+     * @param accessibilityWindowId A unique window id. Use
+     *     {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID}
+     *     to query the currently active window.
+     * @param accessibilityNodeId A unique view id or virtual descendant id from
+     *     where to start the search. Use
+     *     {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID}
+     *     to start from the root.
+     * @param direction The direction in which to search for focusable.
+     * @param interactionId The id of the interaction for matching with the callback result.
+     * @param callback Callback which to receive the result.
+     * @param threadId The id of the calling thread.
+     * @return The current window scale, where zero means a failure.
+     */
+    float focusSearch(int accessibilityWindowId, long accessibilityNodeId, int direction,
+        int interactionId, IAccessibilityInteractionConnectionCallback callback, long threadId);
+
+    /**
      * Performs an accessibility action on an
      * {@link android.view.accessibility.AccessibilityNodeInfo}.
      *
@@ -113,4 +155,9 @@
     boolean performAccessibilityAction(int accessibilityWindowId, long accessibilityNodeId,
         int action, int interactionId, IAccessibilityInteractionConnectionCallback callback,
         long threadId);
+
+    /**
+     * @return The associated accessibility service info.
+     */
+    AccessibilityServiceInfo getServiceInfo();
 }
diff --git a/core/java/android/accessibilityservice/UiTestAutomationBridge.java b/core/java/android/accessibilityservice/UiTestAutomationBridge.java
index a898c3f..c840bd6 100644
--- a/core/java/android/accessibilityservice/UiTestAutomationBridge.java
+++ b/core/java/android/accessibilityservice/UiTestAutomationBridge.java
@@ -17,7 +17,7 @@
 package android.accessibilityservice;
 
 import android.accessibilityservice.AccessibilityService.Callbacks;
-import android.accessibilityservice.AccessibilityService.IEventListenerWrapper;
+import android.accessibilityservice.AccessibilityService.IAccessibilityServiceClientWrapper;
 import android.content.Context;
 import android.os.HandlerThread;
 import android.os.Looper;
@@ -66,7 +66,7 @@
 
     private volatile int mConnectionId = AccessibilityInteractionClient.NO_ID;
 
-    private IEventListenerWrapper mListener;
+    private IAccessibilityServiceClientWrapper mListener;
 
     private AccessibilityEvent mLastEvent;
 
@@ -133,7 +133,7 @@
         mHandlerThread.start();
         Looper looper = mHandlerThread.getLooper();
 
-        mListener = new IEventListenerWrapper(null, looper, new Callbacks() {
+        mListener = new IAccessibilityServiceClientWrapper(null, looper, new Callbacks() {
             @Override
             public void onServiceConnected() {
                 /* do nothing */
@@ -175,6 +175,11 @@
                     mLock.notifyAll();
                 }
             }
+
+            @Override
+            public void onGesture(int gestureId) {
+                /* do nothing */
+            }
         });
 
         final IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface(
@@ -252,6 +257,7 @@
     public AccessibilityEvent executeCommandAndWaitForAccessibilityEvent(Runnable command,
             Predicate<AccessibilityEvent> predicate, long timeoutMillis)
             throws TimeoutException, Exception {
+        // TODO: This is broken - remove from here when finalizing this as public APIs.
         synchronized (mLock) {
             // Prepare to wait for an event.
             mWaitingForEventDelivery = true;
diff --git a/core/java/android/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java
index 634e4d8..871bb2c 100644
--- a/core/java/android/animation/LayoutTransition.java
+++ b/core/java/android/animation/LayoutTransition.java
@@ -119,6 +119,24 @@
     public static final int DISAPPEARING = 3;
 
     /**
+     * A flag indicating the animation that runs on those items that are changing
+     * due to a layout change not caused by items being added to or removed
+     * from the container. This transition type is not enabled by default; it can be
+     * enabled via {@link #enableTransitionType(int)}.
+     */
+    public static final int CHANGING = 4;
+
+    /**
+     * Private bit fields used to set the collection of enabled transition types for
+     * mTransitionTypes.
+     */
+    private static final int FLAG_APPEARING             = 0x01;
+    private static final int FLAG_DISAPPEARING          = 0x02;
+    private static final int FLAG_CHANGE_APPEARING      = 0x04;
+    private static final int FLAG_CHANGE_DISAPPEARING   = 0x08;
+    private static final int FLAG_CHANGING              = 0x10;
+
+    /**
      * These variables hold the animations that are currently used to run the transition effects.
      * These animations are set to defaults, but can be changed to custom animations by
      * calls to setAnimator().
@@ -127,11 +145,13 @@
     private Animator mAppearingAnim = null;
     private Animator mChangingAppearingAnim = null;
     private Animator mChangingDisappearingAnim = null;
+    private Animator mChangingAnim = null;
 
     /**
      * These are the default animations, defined in the constructor, that will be used
      * unless the user specifies custom animations.
      */
+    private static ObjectAnimator defaultChange;
     private static ObjectAnimator defaultChangeIn;
     private static ObjectAnimator defaultChangeOut;
     private static ObjectAnimator defaultFadeIn;
@@ -143,15 +163,16 @@
     private static long DEFAULT_DURATION = 300;
 
     /**
-     * The durations of the four different animations
+     * The durations of the different animations
      */
     private long mChangingAppearingDuration = DEFAULT_DURATION;
     private long mChangingDisappearingDuration = DEFAULT_DURATION;
+    private long mChangingDuration = DEFAULT_DURATION;
     private long mAppearingDuration = DEFAULT_DURATION;
     private long mDisappearingDuration = DEFAULT_DURATION;
 
     /**
-     * The start delays of the four different animations. Note that the default behavior of
+     * The start delays of the different animations. Note that the default behavior of
      * the appearing item is the default duration, since it should wait for the items to move
      * before fading it. Same for the changing animation when disappearing; it waits for the item
      * to fade out before moving the other items.
@@ -160,12 +181,14 @@
     private long mDisappearingDelay = 0;
     private long mChangingAppearingDelay = 0;
     private long mChangingDisappearingDelay = DEFAULT_DURATION;
+    private long mChangingDelay = 0;
 
     /**
-     * The inter-animation delays used on the two changing animations
+     * The inter-animation delays used on the changing animations
      */
     private long mChangingAppearingStagger = 0;
     private long mChangingDisappearingStagger = 0;
+    private long mChangingStagger = 0;
 
     /**
      * The default interpolators used for the animations
@@ -174,6 +197,7 @@
     private TimeInterpolator mDisappearingInterpolator = new AccelerateDecelerateInterpolator();
     private TimeInterpolator mChangingAppearingInterpolator = new DecelerateInterpolator();
     private TimeInterpolator mChangingDisappearingInterpolator = new DecelerateInterpolator();
+    private TimeInterpolator mChangingInterpolator = new DecelerateInterpolator();
 
     /**
      * These hashmaps are used to store the animations that are currently running as part of
@@ -212,6 +236,13 @@
     private long staggerDelay;
 
     /**
+     * These are the types of transition animations that the LayoutTransition is reacting
+     * to. By default, appearing/disappearing and the change animations related to them are
+     * enabled (not CHANGING).
+     */
+    private int mTransitionTypes = FLAG_CHANGE_APPEARING | FLAG_CHANGE_DISAPPEARING |
+            FLAG_APPEARING | FLAG_DISAPPEARING;
+    /**
      * The set of listeners that should be notified when APPEARING/DISAPPEARING transitions
      * start and end.
      */
@@ -248,6 +279,9 @@
             defaultChangeOut = defaultChangeIn.clone();
             defaultChangeOut.setStartDelay(mChangingDisappearingDelay);
             defaultChangeOut.setInterpolator(mChangingDisappearingInterpolator);
+            defaultChange = defaultChangeIn.clone();
+            defaultChange.setStartDelay(mChangingDelay);
+            defaultChange.setInterpolator(mChangingInterpolator);
 
             defaultFadeIn = ObjectAnimator.ofFloat(null, "alpha", 0f, 1f);
             defaultFadeIn.setDuration(DEFAULT_DURATION);
@@ -260,6 +294,7 @@
         }
         mChangingAppearingAnim = defaultChangeIn;
         mChangingDisappearingAnim = defaultChangeOut;
+        mChangingAnim = defaultChange;
         mAppearingAnim = defaultFadeIn;
         mDisappearingAnim = defaultFadeOut;
     }
@@ -275,18 +310,101 @@
     public void setDuration(long duration) {
         mChangingAppearingDuration = duration;
         mChangingDisappearingDuration = duration;
+        mChangingDuration = duration;
         mAppearingDuration = duration;
         mDisappearingDuration = duration;
     }
 
     /**
+     * Enables the specified transitionType for this LayoutTransition object.
+     * By default, a LayoutTransition listens for changes in children being
+     * added/remove/hidden/shown in the container, and runs the animations associated with
+     * those events. That is, all transition types besides {@link #CHANGING} are enabled by default.
+     * You can also enable {@link #CHANGING} animations by calling this method with the
+     * {@link #CHANGING} transitionType.
+     *
+     * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
+     * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}.
+     */
+    public void enableTransitionType(int transitionType) {
+        switch (transitionType) {
+            case APPEARING:
+                mTransitionTypes |= FLAG_APPEARING;
+                break;
+            case DISAPPEARING:
+                mTransitionTypes |= FLAG_DISAPPEARING;
+                break;
+            case CHANGE_APPEARING:
+                mTransitionTypes |= FLAG_CHANGE_APPEARING;
+                break;
+            case CHANGE_DISAPPEARING:
+                mTransitionTypes |= FLAG_CHANGE_DISAPPEARING;
+                break;
+            case CHANGING:
+                mTransitionTypes |= FLAG_CHANGING;
+                break;
+        }
+    }
+
+    /**
+     * Disables the specified transitionType for this LayoutTransition object.
+     * By default, all transition types except {@link #CHANGING} are enabled.
+     *
+     * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
+     * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}.
+     */
+    public void disableTransitionType(int transitionType) {
+        switch (transitionType) {
+            case APPEARING:
+                mTransitionTypes &= ~FLAG_APPEARING;
+                break;
+            case DISAPPEARING:
+                mTransitionTypes &= ~FLAG_DISAPPEARING;
+                break;
+            case CHANGE_APPEARING:
+                mTransitionTypes &= ~FLAG_CHANGE_APPEARING;
+                break;
+            case CHANGE_DISAPPEARING:
+                mTransitionTypes &= ~FLAG_CHANGE_DISAPPEARING;
+                break;
+            case CHANGING:
+                mTransitionTypes &= ~FLAG_CHANGING;
+                break;
+        }
+    }
+
+    /**
+     * Returns whether the specified transitionType is enabled for this LayoutTransition object.
+     * By default, all transition types except {@link #CHANGING} are enabled.
+     *
+     * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
+     * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}.
+     * @return true if the specified transitionType is currently enabled, false otherwise.
+     */
+    public boolean isTransitionTypeEnabled(int transitionType) {
+        switch (transitionType) {
+            case APPEARING:
+                return (mTransitionTypes & FLAG_APPEARING) == FLAG_APPEARING;
+            case DISAPPEARING:
+                return (mTransitionTypes & FLAG_DISAPPEARING) == FLAG_DISAPPEARING;
+            case CHANGE_APPEARING:
+                return (mTransitionTypes & FLAG_CHANGE_APPEARING) == FLAG_CHANGE_APPEARING;
+            case CHANGE_DISAPPEARING:
+                return (mTransitionTypes & FLAG_CHANGE_DISAPPEARING) == FLAG_CHANGE_DISAPPEARING;
+            case CHANGING:
+                return (mTransitionTypes & FLAG_CHANGING) == FLAG_CHANGING;
+        }
+        return false;
+    }
+
+    /**
      * Sets the start delay on one of the animation objects used by this transition. The
      * <code>transitionType</code> parameter determines the animation whose start delay
      * is being set.
      *
-     * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
-     * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose start
-     * delay is being set.
+     * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
+     * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}, which determines
+     * the animation whose start delay is being set.
      * @param delay The length of time, in milliseconds, to delay before starting the animation.
      * @see Animator#setStartDelay(long)
      */
@@ -298,6 +416,9 @@
             case CHANGE_DISAPPEARING:
                 mChangingDisappearingDelay = delay;
                 break;
+            case CHANGING:
+                mChangingDelay = delay;
+                break;
             case APPEARING:
                 mAppearingDelay = delay;
                 break;
@@ -312,9 +433,9 @@
      * <code>transitionType</code> parameter determines the animation whose start delay
      * is returned.
      *
-     * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
-     * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose start
-     * delay is returned.
+     * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
+     * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}, which determines
+     * the animation whose start delay is returned.
      * @return long The start delay of the specified animation.
      * @see Animator#getStartDelay()
      */
@@ -324,6 +445,8 @@
                 return mChangingAppearingDelay;
             case CHANGE_DISAPPEARING:
                 return mChangingDisappearingDelay;
+            case CHANGING:
+                return mChangingDelay;
             case APPEARING:
                 return mAppearingDelay;
             case DISAPPEARING:
@@ -338,9 +461,9 @@
      * <code>transitionType</code> parameter determines the animation whose duration
      * is being set.
      *
-     * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
-     * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose
-     * duration is being set.
+     * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
+     * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}, which determines
+     * the animation whose duration is being set.
      * @param duration The length of time, in milliseconds, that the specified animation should run.
      * @see Animator#setDuration(long)
      */
@@ -352,6 +475,9 @@
             case CHANGE_DISAPPEARING:
                 mChangingDisappearingDuration = duration;
                 break;
+            case CHANGING:
+                mChangingDuration = duration;
+                break;
             case APPEARING:
                 mAppearingDuration = duration;
                 break;
@@ -366,9 +492,9 @@
      * <code>transitionType</code> parameter determines the animation whose duration
      * is returned.
      *
-     * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
-     * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose
-     * duration is returned.
+     * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
+     * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}, which determines
+     * the animation whose duration is returned.
      * @return long The duration of the specified animation.
      * @see Animator#getDuration()
      */
@@ -378,6 +504,8 @@
                 return mChangingAppearingDuration;
             case CHANGE_DISAPPEARING:
                 return mChangingDisappearingDuration;
+            case CHANGING:
+                return mChangingDuration;
             case APPEARING:
                 return mAppearingDuration;
             case DISAPPEARING:
@@ -389,9 +517,10 @@
 
     /**
      * Sets the length of time to delay between starting each animation during one of the
-     * CHANGE animations.
+     * change animations.
      *
-     * @param transitionType A value of {@link #CHANGE_APPEARING} or @link #CHANGE_DISAPPEARING}.
+     * @param transitionType A value of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING}, or
+     * {@link #CHANGING}.
      * @param duration The length of time, in milliseconds, to delay before launching the next
      * animation in the sequence.
      */
@@ -403,15 +532,19 @@
             case CHANGE_DISAPPEARING:
                 mChangingDisappearingStagger = duration;
                 break;
+            case CHANGING:
+                mChangingStagger = duration;
+                break;
             // noop other cases
         }
     }
 
     /**
-     * Tets the length of time to delay between starting each animation during one of the
-     * CHANGE animations.
+     * Gets the length of time to delay between starting each animation during one of the
+     * change animations.
      *
-     * @param transitionType A value of {@link #CHANGE_APPEARING} or @link #CHANGE_DISAPPEARING}.
+     * @param transitionType A value of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING}, or
+     * {@link #CHANGING}.
      * @return long The length of time, in milliseconds, to delay before launching the next
      * animation in the sequence.
      */
@@ -421,6 +554,8 @@
                 return mChangingAppearingStagger;
             case CHANGE_DISAPPEARING:
                 return mChangingDisappearingStagger;
+            case CHANGING:
+                return mChangingStagger;
         }
         // shouldn't reach here
         return 0;
@@ -431,9 +566,9 @@
      * <code>transitionType</code> parameter determines the animation whose interpolator
      * is being set.
      *
-     * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
-     * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose
-     * duration is being set.
+     * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
+     * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}, which determines
+     * the animation whose interpolator is being set.
      * @param interpolator The interpolator that the specified animation should use.
      * @see Animator#setInterpolator(TimeInterpolator)
      */
@@ -445,6 +580,9 @@
             case CHANGE_DISAPPEARING:
                 mChangingDisappearingInterpolator = interpolator;
                 break;
+            case CHANGING:
+                mChangingInterpolator = interpolator;
+                break;
             case APPEARING:
                 mAppearingInterpolator = interpolator;
                 break;
@@ -459,9 +597,9 @@
      * <code>transitionType</code> parameter determines the animation whose interpolator
      * is returned.
      *
-     * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
-     * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose
-     * duration is being set.
+     * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
+     * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}, which determines
+     * the animation whose interpolator is being returned.
      * @return TimeInterpolator The interpolator that the specified animation uses.
      * @see Animator#setInterpolator(TimeInterpolator)
      */
@@ -471,6 +609,8 @@
                 return mChangingAppearingInterpolator;
             case CHANGE_DISAPPEARING:
                 return mChangingDisappearingInterpolator;
+            case CHANGING:
+                return mChangingInterpolator;
             case APPEARING:
                 return mAppearingInterpolator;
             case DISAPPEARING:
@@ -504,9 +644,9 @@
      * values queried when the transition begins may need to use a different mechanism
      * than a standard ObjectAnimator object.</p>
      *
-     * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
-     * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose
-     * duration is being set.
+     * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
+     * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the
+     * animation whose animator is being set.
      * @param animator The animation being assigned. A value of <code>null</code> means that no
      * animation will be run for the specified transitionType.
      */
@@ -518,6 +658,9 @@
             case CHANGE_DISAPPEARING:
                 mChangingDisappearingAnim = animator;
                 break;
+            case CHANGING:
+                mChangingAnim = animator;
+                break;
             case APPEARING:
                 mAppearingAnim = animator;
                 break;
@@ -530,9 +673,9 @@
     /**
      * Gets the animation used during one of the transition types that may run.
      *
-     * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
-     * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose
-     * duration is being set.
+     * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
+     * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}, which determines
+     * the animation whose animator is being returned.
      * @return Animator The animation being used for the given transition type.
      * @see #setAnimator(int, Animator)
      */
@@ -542,6 +685,8 @@
                 return mChangingAppearingAnim;
             case CHANGE_DISAPPEARING:
                 return mChangingDisappearingAnim;
+            case CHANGING:
+                return mChangingAnim;
             case APPEARING:
                 return mAppearingAnim;
             case DISAPPEARING:
@@ -554,20 +699,44 @@
     /**
      * This function sets up animations on all of the views that change during layout.
      * For every child in the parent, we create a change animation of the appropriate
-     * type (appearing or disappearing) and ask it to populate its start values from its
+     * type (appearing, disappearing, or changing) and ask it to populate its start values from its
      * target view. We add layout listeners to all child views and listen for changes. For
      * those views that change, we populate the end values for those animations and start them.
      * Animations are not run on unchanging views.
      *
-     * @param parent The container which is undergoing an appearing or disappearing change.
-     * @param newView The view being added to or removed from the parent.
-     * @param changeReason A value of APPEARING or DISAPPEARING, indicating whether the
-     * transition is occuring because an item is being added to or removed from the parent.
+     * @param parent The container which is undergoing a change.
+     * @param newView The view being added to or removed from the parent. May be null if the
+     * changeReason is CHANGING.
+     * @param changeReason A value of APPEARING, DISAPPEARING, or CHANGING, indicating whether the
+     * transition is occurring because an item is being added to or removed from the parent, or
+     * if it is running in response to a layout operation (that is, if the value is CHANGING).
      */
     private void runChangeTransition(final ViewGroup parent, View newView, final int changeReason) {
 
-        Animator baseAnimator = (changeReason == APPEARING) ?
-                mChangingAppearingAnim : mChangingDisappearingAnim;
+        Animator baseAnimator = null;
+        Animator parentAnimator = null;
+        final long duration;
+        switch (changeReason) {
+            case APPEARING:
+                baseAnimator = mChangingAppearingAnim;
+                duration = mChangingAppearingDuration;
+                parentAnimator = defaultChangeIn;
+                break;
+            case DISAPPEARING:
+                baseAnimator = mChangingDisappearingAnim;
+                duration = mChangingDisappearingDuration;
+                parentAnimator = defaultChangeOut;
+                break;
+            case CHANGING:
+                baseAnimator = mChangingAnim;
+                duration = mChangingDuration;
+                parentAnimator = defaultChange;
+                break;
+            default:
+                // Shouldn't reach here
+                duration = 0;
+                break;
+        }
         // If the animation is null, there's nothing to do
         if (baseAnimator == null) {
             return;
@@ -575,8 +744,6 @@
 
         // reset the inter-animation delay, in case we use it later
         staggerDelay = 0;
-        final long duration = (changeReason == APPEARING) ?
-                mChangingAppearingDuration : mChangingDisappearingDuration;
 
         final ViewTreeObserver observer = parent.getViewTreeObserver(); // used for later cleanup
         if (!observer.isAlive()) {
@@ -594,8 +761,6 @@
             }
         }
         if (mAnimateParentHierarchy) {
-            Animator parentAnimator = (changeReason == APPEARING) ?
-                    defaultChangeIn : defaultChangeOut;
             ViewGroup tempParent = parent;
             while (tempParent != null) {
                 ViewParent parentParent = tempParent.getParent();
@@ -727,13 +892,20 @@
                     }
                 }
 
-                long startDelay;
-                if (changeReason == APPEARING) {
-                    startDelay = mChangingAppearingDelay + staggerDelay;
-                    staggerDelay += mChangingAppearingStagger;
-                } else {
-                    startDelay = mChangingDisappearingDelay + staggerDelay;
-                    staggerDelay += mChangingDisappearingStagger;
+                long startDelay = 0;
+                switch (changeReason) {
+                    case APPEARING:
+                        startDelay = mChangingAppearingDelay + staggerDelay;
+                        staggerDelay += mChangingAppearingStagger;
+                        break;
+                    case DISAPPEARING:
+                        startDelay = mChangingDisappearingDelay + staggerDelay;
+                        staggerDelay += mChangingDisappearingStagger;
+                        break;
+                    case CHANGING:
+                        startDelay = mChangingDelay + staggerDelay;
+                        staggerDelay += mChangingStagger;
+                        break;
                 }
                 anim.setStartDelay(startDelay);
                 anim.setDuration(duration);
@@ -766,7 +938,8 @@
                     for (TransitionListener listener : mListeners) {
                         listener.startTransition(LayoutTransition.this, parent, child,
                                 changeReason == APPEARING ?
-                                        CHANGE_APPEARING : CHANGE_DISAPPEARING);
+                                        CHANGE_APPEARING : changeReason == DISAPPEARING ?
+                                        CHANGE_DISAPPEARING : CHANGING);
                     }
                 }
             }
@@ -784,7 +957,8 @@
                     for (TransitionListener listener : mListeners) {
                         listener.endTransition(LayoutTransition.this, parent, child,
                                 changeReason == APPEARING ?
-                                        CHANGE_APPEARING : CHANGE_DISAPPEARING);
+                                        CHANGE_APPEARING : changeReason == DISAPPEARING ?
+                                        CHANGE_DISAPPEARING : CHANGING);
                     }
                 }
             }
@@ -902,6 +1076,7 @@
         switch (transitionType) {
             case CHANGE_APPEARING:
             case CHANGE_DISAPPEARING:
+            case CHANGING:
                 if (currentChangingAnimations.size() > 0) {
                     LinkedHashMap<View, Animator> currentAnimCopy =
                             (LinkedHashMap<View, Animator>) currentChangingAnimations.clone();
@@ -1031,21 +1206,48 @@
      * affect CHANGE_APPEARING or CHANGE_DISAPPEARING animations.
      */
     private void addChild(ViewGroup parent, View child, boolean changesLayout) {
-        // Want disappearing animations to finish up before proceeding
-        cancel(DISAPPEARING);
-        if (changesLayout) {
+        if ((mTransitionTypes & FLAG_APPEARING) == FLAG_APPEARING) {
+            // Want disappearing animations to finish up before proceeding
+            cancel(DISAPPEARING);
+        }
+        if (changesLayout && (mTransitionTypes & FLAG_CHANGE_APPEARING) == FLAG_CHANGE_APPEARING) {
             // Also, cancel changing animations so that we start fresh ones from current locations
             cancel(CHANGE_APPEARING);
+            cancel(CHANGING);
         }
-        if (mListeners != null) {
+        if (mListeners != null && (mTransitionTypes & FLAG_APPEARING) == FLAG_APPEARING) {
             for (TransitionListener listener : mListeners) {
                 listener.startTransition(this, parent, child, APPEARING);
             }
         }
-        if (changesLayout) {
+        if (changesLayout && (mTransitionTypes & FLAG_CHANGE_APPEARING) == FLAG_CHANGE_APPEARING) {
             runChangeTransition(parent, child, APPEARING);
         }
-        runAppearingTransition(parent, child);
+        if ((mTransitionTypes & FLAG_APPEARING) == FLAG_APPEARING) {
+            runAppearingTransition(parent, child);
+        }
+    }
+
+    /**
+     * This method is called by ViewGroup when there is a call to layout() on the container
+     * with this LayoutTransition. If the CHANGING transition is enabled and if there is no other
+     * transition currently running on the container, then this call runs a CHANGING transition.
+     * The transition does not start immediately; it just sets up the mechanism to run if any
+     * of the children of the container change their layout parameters (similar to
+     * the CHANGE_APPEARING and CHANGE_DISAPPEARING transitions).
+     *
+     * @param parent The ViewGroup whose layout() method has been called.
+     *
+     * @hide
+     */
+    public void layoutChange(ViewGroup parent) {
+        if ((mTransitionTypes & FLAG_CHANGING) == FLAG_CHANGING  && !isRunning()) {
+            // This method is called for all calls to layout() in the container, including
+            // those caused by add/remove/hide/show events, which will already have set up
+            // transition animations. Avoid setting up CHANGING animations in this case; only
+            // do so when there is not a transition already running on the container.
+            runChangeTransition(parent, null, CHANGING);
+        }
     }
 
     /**
@@ -1097,21 +1299,28 @@
      * affect CHANGE_APPEARING or CHANGE_DISAPPEARING animations.
      */
     private void removeChild(ViewGroup parent, View child, boolean changesLayout) {
-        // Want appearing animations to finish up before proceeding
-        cancel(APPEARING);
-        if (changesLayout) {
+        if ((mTransitionTypes & FLAG_DISAPPEARING) == FLAG_DISAPPEARING) {
+            // Want appearing animations to finish up before proceeding
+            cancel(APPEARING);
+        }
+        if (changesLayout &&
+                (mTransitionTypes & FLAG_CHANGE_DISAPPEARING) == FLAG_CHANGE_DISAPPEARING) {
             // Also, cancel changing animations so that we start fresh ones from current locations
             cancel(CHANGE_DISAPPEARING);
+            cancel(CHANGING);
         }
-        if (mListeners != null) {
+        if (mListeners != null && (mTransitionTypes & FLAG_DISAPPEARING) == FLAG_DISAPPEARING) {
             for (TransitionListener listener : mListeners) {
                 listener.startTransition(this, parent, child, DISAPPEARING);
             }
         }
-        if (changesLayout) {
+        if (changesLayout &&
+                (mTransitionTypes & FLAG_CHANGE_DISAPPEARING) == FLAG_CHANGE_DISAPPEARING) {
             runChangeTransition(parent, child, DISAPPEARING);
         }
-        runDisappearingTransition(parent, child);
+        if ((mTransitionTypes & FLAG_DISAPPEARING) == FLAG_DISAPPEARING) {
+            runDisappearingTransition(parent, child);
+        }
     }
 
     /**
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index c3cceaf..423b02a 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -73,6 +73,18 @@
     public static final String KEY_ANIM_START_Y = "android:animStartY";
 
     /**
+     * Initial width of the animation.
+     * @hide
+     */
+    public static final String KEY_ANIM_START_WIDTH = "android:animStartWidth";
+
+    /**
+     * Initial height of the animation.
+     * @hide
+     */
+    public static final String KEY_ANIM_START_HEIGHT = "android:animStartHeight";
+
+    /**
      * Callback for when animation is started.
      * @hide
      */
@@ -83,7 +95,9 @@
     /** @hide */
     public static final int ANIM_CUSTOM = 1;
     /** @hide */
-    public static final int ANIM_THUMBNAIL = 2;
+    public static final int ANIM_SCALE_UP = 2;
+    /** @hide */
+    public static final int ANIM_THUMBNAIL = 3;
 
     private String mPackageName;
     private int mAnimationType = ANIM_NONE;
@@ -92,6 +106,8 @@
     private Bitmap mThumbnail;
     private int mStartX;
     private int mStartY;
+    private int mStartWidth;
+    private int mStartHeight;
     private IRemoteCallback mAnimationStartedListener;
 
     /**
@@ -127,6 +143,34 @@
     }
 
     /**
+     * Create an ActivityOptions specifying an animation where the new
+     * activity is scaled from a small originating area of the screen to
+     * its final full representation.
+     *
+     * @param source The View that the new activity is animating from.  This
+     * defines the coordinate space for <var>startX</var> and <var>startY</var>.
+     * @param startX The x starting location of the new activity, relative to <var>source</var>.
+     * @param startY The y starting location of the activity, relative to <var>source</var>.
+     * @param startWidth The initial width of the new activity.
+     * @param startWidth The initial height of the new activity.
+     * @return Returns a new ActivityOptions object that you can use to
+     * supply these options as the options Bundle when starting an activity.
+     */
+    public static ActivityOptions makeScaleUpAnimation(View source,
+            int startX, int startY, int startWidth, int startHeight) {
+        ActivityOptions opts = new ActivityOptions();
+        opts.mPackageName = source.getContext().getPackageName();
+        opts.mAnimationType = ANIM_SCALE_UP;
+        int[] pts = new int[2];
+        source.getLocationOnScreen(pts);
+        opts.mStartX = pts[0] + startX;
+        opts.mStartY = pts[1] + startY;
+        opts.mStartWidth = startWidth;
+        opts.mStartHeight = startHeight;
+        return opts;
+    }
+
+    /**
      * Create an ActivityOptions specifying an animation where a thumbnail
      * is scaled from a given position to the new activity window that is
      * being started.
@@ -135,8 +179,8 @@
      * defines the coordinate space for <var>startX</var> and <var>startY</var>.
      * @param thumbnail The bitmap that will be shown as the initial thumbnail
      * of the animation.
-     * @param startX The x starting location of the bitmap, in screen coordiantes.
-     * @param startY The y starting location of the bitmap, in screen coordinates.
+     * @param startX The x starting location of the bitmap, relative to <var>source</var>.
+     * @param startY The y starting location of the bitmap, relative to <var>source</var>.
      * @return Returns a new ActivityOptions object that you can use to
      * supply these options as the options Bundle when starting an activity.
      */
@@ -154,8 +198,8 @@
      * defines the coordinate space for <var>startX</var> and <var>startY</var>.
      * @param thumbnail The bitmap that will be shown as the initial thumbnail
      * of the animation.
-     * @param startX The x starting location of the bitmap, in screen coordiantes.
-     * @param startY The y starting location of the bitmap, in screen coordinates.
+     * @param startX The x starting location of the bitmap, relative to <var>source</var>.
+     * @param startY The y starting location of the bitmap, relative to <var>source</var>.
      * @param listener Optional OnAnimationStartedListener to find out when the
      * requested animation has started running.  If for some reason the animation
      * is not executed, the callback will happen immediately.
@@ -199,6 +243,11 @@
         if (mAnimationType == ANIM_CUSTOM) {
             mCustomEnterResId = opts.getInt(KEY_ANIM_ENTER_RES_ID, 0);
             mCustomExitResId = opts.getInt(KEY_ANIM_EXIT_RES_ID, 0);
+        } else if (mAnimationType == ANIM_SCALE_UP) {
+            mStartX = opts.getInt(KEY_ANIM_START_X, 0);
+            mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
+            mStartWidth = opts.getInt(KEY_ANIM_START_WIDTH, 0);
+            mStartHeight = opts.getInt(KEY_ANIM_START_HEIGHT, 0);
         } else if (mAnimationType == ANIM_THUMBNAIL) {
             mThumbnail = (Bitmap)opts.getParcelable(KEY_ANIM_THUMBNAIL);
             mStartX = opts.getInt(KEY_ANIM_START_X, 0);
@@ -244,6 +293,16 @@
     }
 
     /** @hide */
+    public int getStartWidth() {
+        return mStartWidth;
+    }
+
+    /** @hide */
+    public int getStartHeight() {
+        return mStartHeight;
+    }
+
+    /** @hide */
     public IRemoteCallback getOnAnimationStartListener() {
         return mAnimationStartedListener;
     }
@@ -281,6 +340,13 @@
                 mThumbnail = null;
                 mAnimationStartedListener = null;
                 break;
+            case ANIM_SCALE_UP:
+                mAnimationType = otherOptions.mAnimationType;
+                mStartX = otherOptions.mStartX;
+                mStartY = otherOptions.mStartY;
+                mStartWidth = otherOptions.mStartWidth;
+                mStartHeight = otherOptions.mStartHeight;
+                break;
             case ANIM_THUMBNAIL:
                 mAnimationType = otherOptions.mAnimationType;
                 mThumbnail = otherOptions.mThumbnail;
@@ -316,6 +382,13 @@
                 b.putInt(KEY_ANIM_ENTER_RES_ID, mCustomEnterResId);
                 b.putInt(KEY_ANIM_EXIT_RES_ID, mCustomExitResId);
                 break;
+            case ANIM_SCALE_UP:
+                b.putInt(KEY_ANIM_TYPE, mAnimationType);
+                b.putInt(KEY_ANIM_START_X, mStartX);
+                b.putInt(KEY_ANIM_START_Y, mStartY);
+                b.putInt(KEY_ANIM_START_WIDTH, mStartWidth);
+                b.putInt(KEY_ANIM_START_HEIGHT, mStartHeight);
+                break;
             case ANIM_THUMBNAIL:
                 b.putInt(KEY_ANIM_TYPE, mAnimationType);
                 b.putParcelable(KEY_ANIM_THUMBNAIL, mThumbnail);
@@ -323,6 +396,7 @@
                 b.putInt(KEY_ANIM_START_Y, mStartY);
                 b.putIBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener
                         != null ? mAnimationStartedListener.asBinder() : null);
+                break;
         }
         return b;
     }
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 138a88f..8942135 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -45,6 +45,7 @@
 import android.hardware.ISerialManager;
 import android.hardware.SensorManager;
 import android.hardware.SerialManager;
+import android.hardware.SystemSensorManager;
 import android.hardware.input.IInputManager;
 import android.hardware.input.InputManager;
 import android.hardware.usb.IUsbManager;
@@ -82,7 +83,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserId;
-import android.os.Vibrator;
+import android.os.SystemVibrator;
 import android.os.storage.StorageManager;
 import android.telephony.TelephonyManager;
 import android.content.ClipboardManager;
@@ -407,7 +408,7 @@
 
         registerService(SENSOR_SERVICE, new ServiceFetcher() {
                 public Object createService(ContextImpl ctx) {
-                    return new SensorManager(ctx.mMainThread.getHandler().getLooper());
+                    return new SystemSensorManager(ctx.mMainThread.getHandler().getLooper());
                 }});
 
         registerService(STATUS_BAR_SERVICE, new ServiceFetcher() {
@@ -455,7 +456,7 @@
 
         registerService(VIBRATOR_SERVICE, new ServiceFetcher() {
                 public Object createService(ContextImpl ctx) {
-                    return new Vibrator();
+                    return new SystemVibrator();
                 }});
 
         registerService(WALLPAPER_SERVICE, WALLPAPER_FETCHER);
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index dd58397..55f29e6 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -349,6 +349,7 @@
         private String mMimeType;
         private boolean mRoamingAllowed = true;
         private int mAllowedNetworkTypes = ~0; // default to all network types allowed
+        private boolean mAllowedOverMetered = true;
         private boolean mIsVisibleInDownloadsUi = true;
         private boolean mScannable = false;
         private boolean mUseSystemCache = false;
@@ -609,8 +610,11 @@
         }
 
         /**
-         * Restrict the types of networks over which this download may proceed.  By default, all
-         * network types are allowed.
+         * Restrict the types of networks over which this download may proceed.
+         * By default, all network types are allowed. Consider using
+         * {@link #setAllowedOverMetered(boolean)} instead, since it's more
+         * flexible.
+         *
          * @param flags any combination of the NETWORK_* bit flags.
          * @return this object
          */
@@ -620,6 +624,17 @@
         }
 
         /**
+         * Set whether this download may proceed over a metered network
+         * connection. By default, metered networks are allowed.
+         *
+         * @see ConnectivityManager#isActiveNetworkMetered()
+         */
+        public Request setAllowedOverMetered(boolean allow) {
+            mAllowedOverMetered = allow;
+            return this;
+        }
+
+        /**
          * Set whether this download may proceed over a roaming connection.  By default, roaming is
          * allowed.
          * @param allowed whether to allow a roaming connection to be used
@@ -672,6 +687,7 @@
             putIfNonNull(values, Downloads.Impl.COLUMN_DESCRIPTION, mDescription);
             putIfNonNull(values, Downloads.Impl.COLUMN_MIME_TYPE, mMimeType);
 
+            // TODO: add COLUMN_ALLOW_METERED and persist
             values.put(Downloads.Impl.COLUMN_VISIBILITY, mNotificationVisibility);
             values.put(Downloads.Impl.COLUMN_ALLOWED_NETWORK_TYPES, mAllowedNetworkTypes);
             values.put(Downloads.Impl.COLUMN_ALLOW_ROAMING, mRoamingAllowed);
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index a655dd4..1866830 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -21,7 +21,12 @@
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.Html;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
 import android.text.TextUtils;
+import android.text.style.URLSpan;
 import android.util.Log;
 
 import java.io.FileInputStream;
@@ -144,6 +149,8 @@
 public class ClipData implements Parcelable {
     static final String[] MIMETYPES_TEXT_PLAIN = new String[] {
         ClipDescription.MIMETYPE_TEXT_PLAIN };
+    static final String[] MIMETYPES_TEXT_HTML = new String[] {
+        ClipDescription.MIMETYPE_TEXT_HTML };
     static final String[] MIMETYPES_TEXT_URILIST = new String[] {
         ClipDescription.MIMETYPE_TEXT_URILIST };
     static final String[] MIMETYPES_TEXT_INTENT = new String[] {
@@ -176,6 +183,7 @@
      */
     public static class Item {
         final CharSequence mText;
+        final String mHtmlText;
         final Intent mIntent;
         final Uri mUri;
 
@@ -184,6 +192,20 @@
          */
         public Item(CharSequence text) {
             mText = text;
+            mHtmlText = null;
+            mIntent = null;
+            mUri = null;
+        }
+
+        /**
+         * Create an Item consisting of a single block of (possibly styled) text,
+         * with an alternative HTML formatted representation.  You <em>must</em>
+         * supply a plain text representation in addition to HTML text; coercion
+         * will not be done from HTML formated text into plain text.
+         */
+        public Item(CharSequence text, String htmlText) {
+            mText = text;
+            mHtmlText = htmlText;
             mIntent = null;
             mUri = null;
         }
@@ -193,6 +215,7 @@
          */
         public Item(Intent intent) {
             mText = null;
+            mHtmlText = null;
             mIntent = intent;
             mUri = null;
         }
@@ -202,16 +225,35 @@
          */
         public Item(Uri uri) {
             mText = null;
+            mHtmlText = null;
             mIntent = null;
             mUri = uri;
         }
 
         /**
          * Create a complex Item, containing multiple representations of
-         * text, intent, and/or URI.
+         * text, Intent, and/or URI.
          */
         public Item(CharSequence text, Intent intent, Uri uri) {
             mText = text;
+            mHtmlText = null;
+            mIntent = intent;
+            mUri = uri;
+        }
+
+        /**
+         * Create a complex Item, containing multiple representations of
+         * text, HTML text, Intent, and/or URI.  If providing HTML text, you
+         * <em>must</em> supply a plain text representation as well; coercion
+         * will not be done from HTML formated text into plain text.
+         */
+        public Item(CharSequence text, String htmlText, Intent intent, Uri uri) {
+            if (htmlText != null && text == null) {
+                throw new IllegalArgumentException(
+                        "Plain text must be supplied if HTML text is supplied");
+            }
+            mText = text;
+            mHtmlText = htmlText;
             mIntent = intent;
             mUri = uri;
         }
@@ -224,6 +266,13 @@
         }
 
         /**
+         * Retrieve the raw HTML text contained in this Item.
+         */
+        public String getHtmlText() {
+            return mHtmlText;
+        }
+
+        /**
          * Retrieve the raw Intent contained in this Item.
          */
         public Intent getIntent() {
@@ -250,7 +299,7 @@
          * the content provider does not supply a text representation, return
          * the raw URI as a string.
          * <li> If {@link #getIntent} is non-null, convert that to an intent:
-         * URI and returnit.
+         * URI and return it.
          * <li> Otherwise, return an empty string.
          * </ul>
          *
@@ -261,12 +310,14 @@
 //BEGIN_INCLUDE(coerceToText)
         public CharSequence coerceToText(Context context) {
             // If this Item has an explicit textual value, simply return that.
-            if (mText != null) {
-                return mText;
+            CharSequence text = getText();
+            if (text != null) {
+                return text;
             }
 
             // If this Item has a URI value, try using that.
-            if (mUri != null) {
+            Uri uri = getUri();
+            if (uri != null) {
 
                 // First see if the URI can be opened as a plain text stream
                 // (of any sub-type).  If so, this is the best textual
@@ -275,7 +326,7 @@
                 try {
                     // Ask for a stream of the desired type.
                     AssetFileDescriptor descr = context.getContentResolver()
-                            .openTypedAssetFileDescriptor(mUri, "text/*", null);
+                            .openTypedAssetFileDescriptor(uri, "text/*", null);
                     stream = descr.createInputStream();
                     InputStreamReader reader = new InputStreamReader(stream, "UTF-8");
 
@@ -308,13 +359,14 @@
 
                 // If we couldn't open the URI as a stream, then the URI itself
                 // probably serves fairly well as a textual representation.
-                return mUri.toString();
+                return uri.toString();
             }
 
             // Finally, if all we have is an Intent, then we can just turn that
             // into text.  Not the most user-friendly thing, but it's something.
-            if (mIntent != null) {
-                return mIntent.toUri(Intent.URI_INTENT_SCHEME);
+            Intent intent = getIntent();
+            if (intent != null) {
+                return intent.toUri(Intent.URI_INTENT_SCHEME);
             }
 
             // Shouldn't get here, but just in case...
@@ -322,6 +374,210 @@
         }
 //END_INCLUDE(coerceToText)
 
+        /**
+         * Like {@link #coerceToHtmlText(Context)}, but any text that would
+         * be returned as HTML formatting will be returned as text with
+         * style spans.
+         * @param context The caller's Context, from which its ContentResolver
+         * and other things can be retrieved.
+         * @return Returns the item's textual representation.
+         */
+        public CharSequence coerceToStyledText(Context context) {
+            CharSequence text = getText();
+            if (text instanceof Spanned) {
+                return text;
+            }
+            String htmlText = getHtmlText();
+            if (htmlText != null) {
+                try {
+                    CharSequence newText = Html.fromHtml(htmlText);
+                    if (newText != null) {
+                        return newText;
+                    }
+                } catch (RuntimeException e) {
+                    // If anything bad happens, we'll fall back on the plain text.
+                }
+            }
+
+            if (text != null) {
+                return text;
+            }
+            return coerceToHtmlOrStyledText(context, true);
+        }
+
+        /**
+         * Turn this item into HTML text, regardless of the type of data it
+         * actually contains.
+         *
+         * <p>The algorithm for deciding what text to return is:
+         * <ul>
+         * <li> If {@link #getHtmlText} is non-null, return that.
+         * <li> If {@link #getText} is non-null, return that, converting to
+         * valid HTML text.  If this text contains style spans,
+         * {@link Html#toHtml(Spanned) Html.toHtml(Spanned)} is used to
+         * convert them to HTML formatting.
+         * <li> If {@link #getUri} is non-null, try to retrieve its data
+         * as a text stream from its content provider.  If the provider can
+         * supply text/html data, that will be preferred and returned as-is.
+         * Otherwise, any text/* data will be returned and escaped to HTML.
+         * If it is not a content: URI or the content provider does not supply
+         * a text representation, HTML text containing a link to the URI
+         * will be returned.
+         * <li> If {@link #getIntent} is non-null, convert that to an intent:
+         * URI and return as an HTML link.
+         * <li> Otherwise, return an empty string.
+         * </ul>
+         *
+         * @param context The caller's Context, from which its ContentResolver
+         * and other things can be retrieved.
+         * @return Returns the item's representation as HTML text.
+         */
+        public String coerceToHtmlText(Context context) {
+            // If the item has an explicit HTML value, simply return that.
+            String htmlText = getHtmlText();
+            if (htmlText != null) {
+                return htmlText;
+            }
+
+            // If this Item has a plain text value, return it as HTML.
+            CharSequence text = getText();
+            if (text != null) {
+                if (text instanceof Spanned) {
+                    return Html.toHtml((Spanned)text);
+                }
+                return Html.escapeHtml(text);
+            }
+
+            text = coerceToHtmlOrStyledText(context, false);
+            return text != null ? text.toString() : null;
+        }
+
+        private CharSequence coerceToHtmlOrStyledText(Context context, boolean styled) {
+            // If this Item has a URI value, try using that.
+            if (mUri != null) {
+
+                // Check to see what data representations the content
+                // provider supports.  We would like HTML text, but if that
+                // is not possible we'll live with plan text.
+                String[] types = context.getContentResolver().getStreamTypes(mUri, "text/*");
+                boolean hasHtml = false;
+                boolean hasText = false;
+                if (types != null) {
+                    for (String type : types) {
+                        if ("text/html".equals(type)) {
+                            hasHtml = true;
+                        } else if (type.startsWith("text/")) {
+                            hasText = true;
+                        }
+                    }
+                }
+
+                // If the provider can serve data we can use, open and load it.
+                if (hasHtml || hasText) {
+                    FileInputStream stream = null;
+                    try {
+                        // Ask for a stream of the desired type.
+                        AssetFileDescriptor descr = context.getContentResolver()
+                                .openTypedAssetFileDescriptor(mUri,
+                                        hasHtml ? "text/html" : "text/plain", null);
+                        stream = descr.createInputStream();
+                        InputStreamReader reader = new InputStreamReader(stream, "UTF-8");
+
+                        // Got it...  copy the stream into a local string and return it.
+                        StringBuilder builder = new StringBuilder(128);
+                        char[] buffer = new char[8192];
+                        int len;
+                        while ((len=reader.read(buffer)) > 0) {
+                            builder.append(buffer, 0, len);
+                        }
+                        String text = builder.toString();
+                        if (hasHtml) {
+                            if (styled) {
+                                // We loaded HTML formatted text and the caller
+                                // want styled text, convert it.
+                                try {
+                                    CharSequence newText = Html.fromHtml(text);
+                                    return newText != null ? newText : text;
+                                } catch (RuntimeException e) {
+                                    return text;
+                                }
+                            } else {
+                                // We loaded HTML formatted text and that is what
+                                // the caller wants, just return it.
+                                return text.toString();
+                            }
+                        }
+                        if (styled) {
+                            // We loaded plain text and the caller wants styled
+                            // text, that is all we have so return it.
+                            return text;
+                        } else {
+                            // We loaded plain text and the caller wants HTML
+                            // text, escape it for HTML.
+                            return Html.escapeHtml(text);
+                        }
+
+                    } catch (FileNotFoundException e) {
+                        // Unable to open content URI as text...  not really an
+                        // error, just something to ignore.
+
+                    } catch (IOException e) {
+                        // Something bad has happened.
+                        Log.w("ClippedData", "Failure loading text", e);
+                        return Html.escapeHtml(e.toString());
+
+                    } finally {
+                        if (stream != null) {
+                            try {
+                                stream.close();
+                            } catch (IOException e) {
+                            }
+                        }
+                    }
+                }
+
+                // If we couldn't open the URI as a stream, then we can build
+                // some HTML text with the URI itself.
+                // probably serves fairly well as a textual representation.
+                if (styled) {
+                    return uriToStyledText(mUri.toString());
+                } else {
+                    return uriToHtml(mUri.toString());
+                }
+            }
+
+            // Finally, if all we have is an Intent, then we can just turn that
+            // into text.  Not the most user-friendly thing, but it's something.
+            if (mIntent != null) {
+                if (styled) {
+                    return uriToStyledText(mIntent.toUri(Intent.URI_INTENT_SCHEME));
+                } else {
+                    return uriToHtml(mIntent.toUri(Intent.URI_INTENT_SCHEME));
+                }
+            }
+
+            // Shouldn't get here, but just in case...
+            return "";
+        }
+
+        private String uriToHtml(String uri) {
+            StringBuilder builder = new StringBuilder(256);
+            builder.append("<a href=\"");
+            builder.append(uri);
+            builder.append("\">");
+            builder.append(Html.escapeHtml(uri));
+            builder.append("</a>");
+            return builder.toString();
+        }
+
+        private CharSequence uriToStyledText(String uri) {
+            SpannableStringBuilder builder = new SpannableStringBuilder();
+            builder.append(uri);
+            builder.setSpan(new URLSpan(uri), 0, builder.length(),
+                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+            return builder;
+        }
+
         @Override
         public String toString() {
             StringBuilder b = new StringBuilder(128);
@@ -335,7 +591,10 @@
 
         /** @hide */
         public void toShortString(StringBuilder b) {
-            if (mText != null) {
+            if (mHtmlText != null) {
+                b.append("H:");
+                b.append(mHtmlText);
+            } else if (mText != null) {
                 b.append("T:");
                 b.append(mText);
             } else if (mUri != null) {
@@ -409,6 +668,22 @@
     }
 
     /**
+     * Create a new ClipData holding data of the type
+     * {@link ClipDescription#MIMETYPE_TEXT_HTML}.
+     *
+     * @param label User-visible label for the clip data.
+     * @param text The text of clip as plain text, for receivers that don't
+     * handle HTML.  This is required.
+     * @param htmlText The actual HTML text in the clip.
+     * @return Returns a new ClipData containing the specified data.
+     */
+    static public ClipData newHtmlText(CharSequence label, CharSequence text,
+            String htmlText) {
+        Item item = new Item(text, htmlText);
+        return new ClipData(label, MIMETYPES_TEXT_HTML, item);
+    }
+
+    /**
      * Create a new ClipData holding an Intent with MIME type
      * {@link ClipDescription#MIMETYPE_TEXT_INTENT}.
      *
@@ -574,6 +849,7 @@
         for (int i=0; i<N; i++) {
             Item item = mItems.get(i);
             TextUtils.writeToParcel(item.mText, dest, flags);
+            dest.writeString(item.mHtmlText);
             if (item.mIntent != null) {
                 dest.writeInt(1);
                 item.mIntent.writeToParcel(dest, flags);
@@ -600,9 +876,10 @@
         final int N = in.readInt();
         for (int i=0; i<N; i++) {
             CharSequence text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+            String htmlText = in.readString();
             Intent intent = in.readInt() != 0 ? Intent.CREATOR.createFromParcel(in) : null;
             Uri uri = in.readInt() != 0 ? Uri.CREATOR.createFromParcel(in) : null;
-            mItems.add(new Item(text, intent, uri));
+            mItems.add(new Item(text, htmlText, intent, uri));
         }
     }
 
diff --git a/core/java/android/content/ClipDescription.java b/core/java/android/content/ClipDescription.java
index c6b51ef..5cb6e77 100644
--- a/core/java/android/content/ClipDescription.java
+++ b/core/java/android/content/ClipDescription.java
@@ -41,6 +41,11 @@
     public static final String MIMETYPE_TEXT_PLAIN = "text/plain";
 
     /**
+     * The MIME type for a clip holding HTML text.
+     */
+    public static final String MIMETYPE_TEXT_HTML = "text/html";
+
+    /**
      * The MIME type for a clip holding one or more URIs.  This should be
      * used for URIs that are meaningful to a user (such as an http: URI).
      * It should <em>not</em> be used for a content: URI that references some
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 2930998..722fdc6 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -248,7 +248,7 @@
      * @param mimeTypeFilter The desired MIME type.  This may be a pattern,
      * such as *\/*, to query for all available MIME types that match the
      * pattern.
-     * @return Returns an array of MIME type strings for all availablle
+     * @return Returns an array of MIME type strings for all available
      * data streams that match the given mimeTypeFilter.  If there are none,
      * null is returned.
      */
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 18d682d..6653336 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -954,7 +954,18 @@
      * using EXTRA_TEXT, the MIME type should be "text/plain"; otherwise it
      * should be the MIME type of the data in EXTRA_STREAM.  Use {@literal *}/*
      * if the MIME type is unknown (this will only allow senders that can
-     * handle generic data streams).
+     * handle generic data streams).  If using {@link #EXTRA_TEXT}, you can
+     * also optionally supply {@link #EXTRA_HTML_TEXT} for clients to retrieve
+     * your text with HTML formatting.
+     * <p>
+     * As of {@link android.os.Build.VERSION_CODES#JELLY_BEAN}, the data
+     * being sent can be supplied through {@link #setClipData(ClipData)}.  This
+     * allows you to use {@link #FLAG_GRANT_READ_URI_PERMISSION} when sharing
+     * content: URIs and other advanced features of {@link ClipData}.  If
+     * using this approach, you still must supply the same data through the
+     * {@link #EXTRA_TEXT} or {@link #EXTRA_STREAM} fields described below
+     * for compatibility with old applications.  If you don't set a ClipData,
+     * it will be copied there for you when calling {@link Context#startActivity(Intent)}.
      * <p>
      * Optional standard extras, which may be interpreted by some recipients as
      * appropriate, are: {@link #EXTRA_EMAIL}, {@link #EXTRA_CC},
@@ -967,11 +978,13 @@
     /**
      * Activity Action: Deliver multiple data to someone else.
      * <p>
-     * Like ACTION_SEND, except the data is multiple.
+     * Like {@link #ACTION_SEND}, except the data is multiple.
      * <p>
      * Input: {@link #getType} is the MIME type of the data being sent.
      * get*ArrayListExtra can have either a {@link #EXTRA_TEXT} or {@link
-     * #EXTRA_STREAM} field, containing the data to be sent.
+     * #EXTRA_STREAM} field, containing the data to be sent.  If using
+     * {@link #EXTRA_TEXT}, you can also optionally supply {@link #EXTRA_HTML_TEXT}
+     * for clients to retrieve your text with HTML formatting.
      * <p>
      * Multiple types are supported, and receivers should handle mixed types
      * whenever possible. The right way for the receiver to check them is to
@@ -983,6 +996,15 @@
      * be image/jpg, but if you are sending image/jpg and image/png, then the
      * intent's type should be image/*.
      * <p>
+     * As of {@link android.os.Build.VERSION_CODES#JELLY_BEAN}, the data
+     * being sent can be supplied through {@link #setClipData(ClipData)}.  This
+     * allows you to use {@link #FLAG_GRANT_READ_URI_PERMISSION} when sharing
+     * content: URIs and other advanced features of {@link ClipData}.  If
+     * using this approach, you still must supply the same data through the
+     * {@link #EXTRA_TEXT} or {@link #EXTRA_STREAM} fields described below
+     * for compatibility with old applications.  If you don't set a ClipData,
+     * it will be copied there for you when calling {@link Context#startActivity(Intent)}.
+     * <p>
      * Optional standard extras, which may be interpreted by some recipients as
      * appropriate, are: {@link #EXTRA_EMAIL}, {@link #EXTRA_CC},
      * {@link #EXTRA_BCC}, {@link #EXTRA_SUBJECT}.
@@ -2501,6 +2523,14 @@
     public static final String EXTRA_TEXT = "android.intent.extra.TEXT";
 
     /**
+     * A constant String that is associated with the Intent, used with
+     * {@link #ACTION_SEND} to supply an alternative to {@link #EXTRA_TEXT}
+     * as HTML formatted text.  Note that you <em>must</em> also supply
+     * {@link #EXTRA_TEXT}.
+     */
+    public static final String EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT";
+
+    /**
      * A content: URI holding a stream of data associated with the Intent,
      * used with {@link #ACTION_SEND} to supply the data being sent.
      */
@@ -6546,35 +6576,54 @@
 
         final String action = getAction();
         if (ACTION_SEND.equals(action)) {
-            final Uri stream;
+            Uri stream = null;
             try {
                 stream = getParcelableExtra(EXTRA_STREAM);
             } catch (ClassCastException e) {
-                return;
             }
-            if (stream != null) {
+            final CharSequence text = getCharSequenceExtra(EXTRA_TEXT);
+            final String htmlText = getStringExtra(EXTRA_HTML_TEXT);
+            if (stream != null || text != null || htmlText != null) {
                 final ClipData clipData = new ClipData(
-                        null, new String[] { getType() }, new ClipData.Item(stream));
-
+                        null, new String[] { getType() },
+                        new ClipData.Item(text, htmlText, null, stream));
                 setClipData(clipData);
                 addFlags(FLAG_GRANT_READ_URI_PERMISSION);
             }
 
         } else if (ACTION_SEND_MULTIPLE.equals(action)) {
-            final ArrayList<Uri> streams;
+            ArrayList<Uri> streams = null;
             try {
                 streams = getParcelableArrayListExtra(EXTRA_STREAM);
             } catch (ClassCastException e) {
-                return;
             }
-            if (streams != null && streams.size() > 0) {
-                final Uri firstStream = streams.get(0);
+            final ArrayList<CharSequence> texts = getCharSequenceArrayListExtra(EXTRA_TEXT);
+            final ArrayList<String> htmlTexts = getStringArrayListExtra(EXTRA_HTML_TEXT);
+            int num = -1;
+            if (streams != null) {
+                num = streams.size();
+            }
+            if (texts != null) {
+                if (num >= 0 && num != texts.size()) {
+                    // Wha...!  F- you.
+                    return;
+                }
+                num = texts.size();
+            }
+            if (htmlTexts != null) {
+                if (num >= 0 && num != htmlTexts.size()) {
+                    // Wha...!  F- you.
+                    return;
+                }
+                num = htmlTexts.size();
+            }
+            if (num > 0) {
                 final ClipData clipData = new ClipData(
-                        null, new String[] { getType() }, new ClipData.Item(firstStream));
+                        null, new String[] { getType() },
+                        makeClipItem(streams, texts, htmlTexts, 0));
 
-                final int size = streams.size();
-                for (int i = 1; i < size; i++) {
-                    clipData.addItem(new ClipData.Item(streams.get(i)));
+                for (int i = 1; i < num; i++) {
+                    clipData.addItem(makeClipItem(streams, texts, htmlTexts, i));
                 }
 
                 setClipData(clipData);
@@ -6582,4 +6631,12 @@
             }
         }
     }
+
+    private static ClipData.Item makeClipItem(ArrayList<Uri> streams, ArrayList<CharSequence> texts,
+            ArrayList<String> htmlTexts, int which) {
+        Uri uri = streams != null ? streams.get(which) : null;
+        CharSequence text = texts != null ? texts.get(which) : null;
+        String htmlText = htmlTexts != null ? htmlTexts.get(which) : null;
+        return new ClipData.Item(text, htmlText, null, uri);
+    }
 }
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index b6ebbdf..185fcb9 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3458,9 +3458,9 @@
             ai.disableCompatibilityMode();
         }
         if (stopped) {
-            p.applicationInfo.flags |= ApplicationInfo.FLAG_STOPPED;
+            ai.flags |= ApplicationInfo.FLAG_STOPPED;
         } else {
-            p.applicationInfo.flags &= ~ApplicationInfo.FLAG_STOPPED;
+            ai.flags &= ~ApplicationInfo.FLAG_STOPPED;
         }
         if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
             ai.enabled = true;
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index 254f652..04f6377 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -711,6 +711,7 @@
             throw new IllegalArgumentException("sql must not be null.");
         }
 
+        int changedRows = 0;
         final int cookie = mRecentOperations.beginOperation("executeForChangedRowCount",
                 sql, bindArgs);
         try {
@@ -721,8 +722,9 @@
                 applyBlockGuardPolicy(statement);
                 attachCancellationSignal(cancellationSignal);
                 try {
-                    return nativeExecuteForChangedRowCount(
+                    changedRows = nativeExecuteForChangedRowCount(
                             mConnectionPtr, statement.mStatementPtr);
+                    return changedRows;
                 } finally {
                     detachCancellationSignal(cancellationSignal);
                 }
@@ -733,7 +735,9 @@
             mRecentOperations.failOperation(cookie, ex);
             throw ex;
         } finally {
-            mRecentOperations.endOperation(cookie);
+            if (mRecentOperations.endOperationDeferLog(cookie)) {
+                mRecentOperations.logOperation(cookie, "changedRows=" + changedRows);
+            }
         }
     }
 
diff --git a/core/java/android/hardware/LegacySensorManager.java b/core/java/android/hardware/LegacySensorManager.java
new file mode 100644
index 0000000..62c194f
--- /dev/null
+++ b/core/java/android/hardware/LegacySensorManager.java
@@ -0,0 +1,434 @@
+/*
+ * 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;
+
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.view.IRotationWatcher;
+import android.view.IWindowManager;
+import android.view.Surface;
+
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Helper class for implementing the legacy sensor manager API.
+ * @hide
+ */
+@SuppressWarnings("deprecation")
+final class LegacySensorManager {
+    private static boolean sInitialized;
+    private static IWindowManager sWindowManager;
+    private static int sRotation = Surface.ROTATION_0;
+
+    private final SensorManager mSensorManager;
+
+    // List of legacy listeners.  Guarded by mLegacyListenersMap.
+    private final HashMap<SensorListener, LegacyListener> mLegacyListenersMap =
+            new HashMap<SensorListener, LegacyListener>();
+
+    public LegacySensorManager(SensorManager sensorManager) {
+        mSensorManager = sensorManager;
+
+        synchronized (SensorManager.class) {
+            if (!sInitialized) {
+                sWindowManager = IWindowManager.Stub.asInterface(
+                        ServiceManager.getService("window"));
+                if (sWindowManager != null) {
+                    // if it's null we're running in the system process
+                    // which won't get the rotated values
+                    try {
+                        sRotation = sWindowManager.watchRotation(
+                                new IRotationWatcher.Stub() {
+                                    public void onRotationChanged(int rotation) {
+                                        LegacySensorManager.onRotationChanged(rotation);
+                                    }
+                                }
+                        );
+                    } catch (RemoteException e) {
+                    }
+                }
+            }
+        }
+    }
+
+    public int getSensors() {
+        int result = 0;
+        final List<Sensor> fullList = mSensorManager.getFullSensorList();
+        for (Sensor i : fullList) {
+            switch (i.getType()) {
+                case Sensor.TYPE_ACCELEROMETER:
+                    result |= SensorManager.SENSOR_ACCELEROMETER;
+                    break;
+                case Sensor.TYPE_MAGNETIC_FIELD:
+                    result |= SensorManager.SENSOR_MAGNETIC_FIELD;
+                    break;
+                case Sensor.TYPE_ORIENTATION:
+                    result |= SensorManager.SENSOR_ORIENTATION
+                            | SensorManager.SENSOR_ORIENTATION_RAW;
+                    break;
+            }
+        }
+        return result;
+    }
+
+    public boolean registerListener(SensorListener listener, int sensors, int rate) {
+        if (listener == null) {
+            return false;
+        }
+        boolean result = false;
+        result = registerLegacyListener(SensorManager.SENSOR_ACCELEROMETER,
+                Sensor.TYPE_ACCELEROMETER, listener, sensors, rate) || result;
+        result = registerLegacyListener(SensorManager.SENSOR_MAGNETIC_FIELD,
+                Sensor.TYPE_MAGNETIC_FIELD, listener, sensors, rate) || result;
+        result = registerLegacyListener(SensorManager.SENSOR_ORIENTATION_RAW,
+                Sensor.TYPE_ORIENTATION, listener, sensors, rate) || result;
+        result = registerLegacyListener(SensorManager.SENSOR_ORIENTATION,
+                Sensor.TYPE_ORIENTATION, listener, sensors, rate) || result;
+        result = registerLegacyListener(SensorManager.SENSOR_TEMPERATURE,
+                Sensor.TYPE_TEMPERATURE, listener, sensors, rate) || result;
+        return result;
+    }
+
+    private boolean registerLegacyListener(int legacyType, int type,
+            SensorListener listener, int sensors, int rate) {
+        boolean result = false;
+        // Are we activating this legacy sensor?
+        if ((sensors & legacyType) != 0) {
+            // if so, find a suitable Sensor
+            Sensor sensor = mSensorManager.getDefaultSensor(type);
+            if (sensor != null) {
+                // We do all of this work holding the legacy listener lock to ensure
+                // that the invariants around listeners are maintained.  This is safe
+                // because neither registerLegacyListener nor unregisterLegacyListener
+                // are called reentrantly while sensors are being registered or unregistered.
+                synchronized (mLegacyListenersMap) {
+                    // If we don't already have one, create a LegacyListener
+                    // to wrap this listener and process the events as
+                    // they are expected by legacy apps.
+                    LegacyListener legacyListener = mLegacyListenersMap.get(listener);
+                    if (legacyListener == null) {
+                        // we didn't find a LegacyListener for this client,
+                        // create one, and put it in our list.
+                        legacyListener = new LegacyListener(listener);
+                        mLegacyListenersMap.put(listener, legacyListener);
+                    }
+
+                    // register this legacy sensor with this legacy listener
+                    if (legacyListener.registerSensor(legacyType)) {
+                        // and finally, register the legacy listener with the new apis
+                        result = mSensorManager.registerListener(legacyListener, sensor, rate);
+                    } else {
+                        result = true; // sensor already enabled
+                    }
+                }
+            }
+        }
+        return result;
+    }
+
+    public void unregisterListener(SensorListener listener, int sensors) {
+        if (listener == null) {
+            return;
+        }
+        unregisterLegacyListener(SensorManager.SENSOR_ACCELEROMETER, Sensor.TYPE_ACCELEROMETER,
+                listener, sensors);
+        unregisterLegacyListener(SensorManager.SENSOR_MAGNETIC_FIELD, Sensor.TYPE_MAGNETIC_FIELD,
+                listener, sensors);
+        unregisterLegacyListener(SensorManager.SENSOR_ORIENTATION_RAW, Sensor.TYPE_ORIENTATION,
+                listener, sensors);
+        unregisterLegacyListener(SensorManager.SENSOR_ORIENTATION, Sensor.TYPE_ORIENTATION,
+                listener, sensors);
+        unregisterLegacyListener(SensorManager.SENSOR_TEMPERATURE, Sensor.TYPE_TEMPERATURE,
+                listener, sensors);
+    }
+
+    private void unregisterLegacyListener(int legacyType, int type,
+            SensorListener listener, int sensors) {
+        // Are we deactivating this legacy sensor?
+        if ((sensors & legacyType) != 0) {
+            // if so, find the corresponding Sensor
+            Sensor sensor = mSensorManager.getDefaultSensor(type);
+            if (sensor != null) {
+                // We do all of this work holding the legacy listener lock to ensure
+                // that the invariants around listeners are maintained.  This is safe
+                // because neither registerLegacyListener nor unregisterLegacyListener
+                // are called re-entrantly while sensors are being registered or unregistered.
+                synchronized (mLegacyListenersMap) {
+                    // do we know about this listener?
+                    LegacyListener legacyListener = mLegacyListenersMap.get(listener);
+                    if (legacyListener != null) {
+                        // unregister this legacy sensor and if we don't
+                        // need the corresponding Sensor, unregister it too
+                        if (legacyListener.unregisterSensor(legacyType)) {
+                            // corresponding sensor not needed, unregister
+                            mSensorManager.unregisterListener(legacyListener, sensor);
+
+                            // finally check if we still need the legacyListener
+                            // in our mapping, if not, get rid of it too.
+                            if (!legacyListener.hasSensors()) {
+                                mLegacyListenersMap.remove(listener);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    static void onRotationChanged(int rotation) {
+        synchronized (SensorManager.class) {
+            sRotation  = rotation;
+        }
+    }
+
+    static int getRotation() {
+        synchronized (SensorManager.class) {
+            return sRotation;
+        }
+    }
+
+    private static final class LegacyListener implements SensorEventListener {
+        private float mValues[] = new float[6];
+        private SensorListener mTarget;
+        private int mSensors;
+        private final LmsFilter mYawfilter = new LmsFilter();
+
+        LegacyListener(SensorListener target) {
+            mTarget = target;
+            mSensors = 0;
+        }
+
+        boolean registerSensor(int legacyType) {
+            if ((mSensors & legacyType) != 0) {
+                return false;
+            }
+            boolean alreadyHasOrientationSensor = hasOrientationSensor(mSensors);
+            mSensors |= legacyType;
+            if (alreadyHasOrientationSensor && hasOrientationSensor(legacyType)) {
+                return false; // don't need to re-register the orientation sensor
+            }
+            return true;
+        }
+
+        boolean unregisterSensor(int legacyType) {
+            if ((mSensors & legacyType) == 0) {
+                return false;
+            }
+            mSensors &= ~legacyType;
+            if (hasOrientationSensor(legacyType) && hasOrientationSensor(mSensors)) {
+                return false; // can't unregister the orientation sensor just yet
+            }
+            return true;
+        }
+
+        boolean hasSensors() {
+            return mSensors != 0;
+        }
+
+        private static boolean hasOrientationSensor(int sensors) {
+            return (sensors & (SensorManager.SENSOR_ORIENTATION
+                    | SensorManager.SENSOR_ORIENTATION_RAW)) != 0;
+        }
+
+        public void onAccuracyChanged(Sensor sensor, int accuracy) {
+            try {
+                mTarget.onAccuracyChanged(getLegacySensorType(sensor.getType()), accuracy);
+            } catch (AbstractMethodError e) {
+                // old app that doesn't implement this method
+                // just ignore it.
+            }
+        }
+
+        public void onSensorChanged(SensorEvent event) {
+            final float v[] = mValues;
+            v[0] = event.values[0];
+            v[1] = event.values[1];
+            v[2] = event.values[2];
+            int type = event.sensor.getType();
+            int legacyType = getLegacySensorType(type);
+            mapSensorDataToWindow(legacyType, v, LegacySensorManager.getRotation());
+            if (type == Sensor.TYPE_ORIENTATION) {
+                if ((mSensors & SensorManager.SENSOR_ORIENTATION_RAW)!=0) {
+                    mTarget.onSensorChanged(SensorManager.SENSOR_ORIENTATION_RAW, v);
+                }
+                if ((mSensors & SensorManager.SENSOR_ORIENTATION)!=0) {
+                    v[0] = mYawfilter.filter(event.timestamp, v[0]);
+                    mTarget.onSensorChanged(SensorManager.SENSOR_ORIENTATION, v);
+                }
+            } else {
+                mTarget.onSensorChanged(legacyType, v);
+            }
+        }
+
+        /*
+         * Helper function to convert the specified sensor's data to the windows's
+         * coordinate space from the device's coordinate space.
+         *
+         * output: 3,4,5: values in the old API format
+         *         0,1,2: transformed values in the old API format
+         *
+         */
+        private void mapSensorDataToWindow(int sensor,
+                float[] values, int orientation) {
+            float x = values[0];
+            float y = values[1];
+            float z = values[2];
+
+            switch (sensor) {
+                case SensorManager.SENSOR_ORIENTATION:
+                case SensorManager.SENSOR_ORIENTATION_RAW:
+                    z = -z;
+                    break;
+                case SensorManager.SENSOR_ACCELEROMETER:
+                    x = -x;
+                    y = -y;
+                    z = -z;
+                    break;
+                case SensorManager.SENSOR_MAGNETIC_FIELD:
+                    x = -x;
+                    y = -y;
+                    break;
+            }
+            values[0] = x;
+            values[1] = y;
+            values[2] = z;
+            values[3] = x;
+            values[4] = y;
+            values[5] = z;
+
+            if ((orientation & Surface.ROTATION_90) != 0) {
+                // handles 90 and 270 rotation
+                switch (sensor) {
+                    case SensorManager.SENSOR_ACCELEROMETER:
+                    case SensorManager.SENSOR_MAGNETIC_FIELD:
+                        values[0] =-y;
+                        values[1] = x;
+                        values[2] = z;
+                        break;
+                    case SensorManager.SENSOR_ORIENTATION:
+                    case SensorManager.SENSOR_ORIENTATION_RAW:
+                        values[0] = x + ((x < 270) ? 90 : -270);
+                        values[1] = z;
+                        values[2] = y;
+                        break;
+                }
+            }
+            if ((orientation & Surface.ROTATION_180) != 0) {
+                x = values[0];
+                y = values[1];
+                z = values[2];
+                // handles 180 (flip) and 270 (flip + 90) rotation
+                switch (sensor) {
+                    case SensorManager.SENSOR_ACCELEROMETER:
+                    case SensorManager.SENSOR_MAGNETIC_FIELD:
+                        values[0] =-x;
+                        values[1] =-y;
+                        values[2] = z;
+                        break;
+                    case SensorManager.SENSOR_ORIENTATION:
+                    case SensorManager.SENSOR_ORIENTATION_RAW:
+                        values[0] = (x >= 180) ? (x - 180) : (x + 180);
+                        values[1] =-y;
+                        values[2] =-z;
+                        break;
+                }
+            }
+        }
+
+        private static int getLegacySensorType(int type) {
+            switch (type) {
+                case Sensor.TYPE_ACCELEROMETER:
+                    return SensorManager.SENSOR_ACCELEROMETER;
+                case Sensor.TYPE_MAGNETIC_FIELD:
+                    return SensorManager.SENSOR_MAGNETIC_FIELD;
+                case Sensor.TYPE_ORIENTATION:
+                    return SensorManager.SENSOR_ORIENTATION_RAW;
+                case Sensor.TYPE_TEMPERATURE:
+                    return SensorManager.SENSOR_TEMPERATURE;
+            }
+            return 0;
+        }
+    }
+
+    private static final class LmsFilter {
+        private static final int SENSORS_RATE_MS = 20;
+        private static final int COUNT = 12;
+        private static final float PREDICTION_RATIO = 1.0f/3.0f;
+        private static final float PREDICTION_TIME = (SENSORS_RATE_MS*COUNT/1000.0f)*PREDICTION_RATIO;
+        private float mV[] = new float[COUNT*2];
+        private float mT[] = new float[COUNT*2];
+        private int mIndex;
+
+        public LmsFilter() {
+            mIndex = COUNT;
+        }
+
+        public float filter(long time, float in) {
+            float v = in;
+            final float ns = 1.0f / 1000000000.0f;
+            final float t = time*ns;
+            float v1 = mV[mIndex];
+            if ((v-v1) > 180) {
+                v -= 360;
+            } else if ((v1-v) > 180) {
+                v += 360;
+            }
+            /* Manage the circular buffer, we write the data twice spaced
+             * by COUNT values, so that we don't have to copy the array
+             * when it's full
+             */
+            mIndex++;
+            if (mIndex >= COUNT*2)
+                mIndex = COUNT;
+            mV[mIndex] = v;
+            mT[mIndex] = t;
+            mV[mIndex-COUNT] = v;
+            mT[mIndex-COUNT] = t;
+
+            float A, B, C, D, E;
+            float a, b;
+            int i;
+
+            A = B = C = D = E = 0;
+            for (i=0 ; i<COUNT-1 ; i++) {
+                final int j = mIndex - 1 - i;
+                final float Z = mV[j];
+                final float T = 0.5f*(mT[j] + mT[j+1]) - t;
+                float dT = mT[j] - mT[j+1];
+                dT *= dT;
+                A += Z*dT;
+                B += T*(T*dT);
+                C +=   (T*dT);
+                D += Z*(T*dT);
+                E += dT;
+            }
+            b = (A*B + C*D) / (E*B + C*C);
+            a = (E*b - A) / C;
+            float f = b + PREDICTION_TIME*a;
+
+            // Normalize
+            f *= (1.0f / 360.0f);
+            if (((f>=0)?f:-f) >= 0.5f)
+                f = f - (float)Math.ceil(f + 0.5f) + 1.0f;
+            if (f < 0)
+                f += 1.0f;
+            f *= 360.0f;
+            return f;
+        }
+    }
+}
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 63fb32d..3c70dc6 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -131,7 +131,6 @@
     private float   mResolution;
     private float   mPower;
     private int     mMinDelay;
-    private int     mLegacyType;
 
 
     Sensor() {
@@ -203,12 +202,4 @@
         mMaxRange = max;
         mResolution = res;
     }
-
-    void setLegacyType(int legacyType) {
-        mLegacyType = legacyType;
-    }
-
-    int getLegacyType() {
-        return mLegacyType;
-    }
 }
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 3fdf246..aeb46cf 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -16,23 +16,12 @@
 
 package android.hardware;
 
-import android.os.Looper;
-import android.os.Process;
-import android.os.RemoteException;
 import android.os.Handler;
-import android.os.Message;
-import android.os.ServiceManager;
 import android.util.Log;
 import android.util.SparseArray;
-import android.util.SparseBooleanArray;
-import android.util.SparseIntArray;
-import android.view.IRotationWatcher;
-import android.view.IWindowManager;
-import android.view.Surface;
 
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
 
 /**
@@ -83,11 +72,19 @@
  * @see Sensor
  *
  */
-public class SensorManager
-{
-    private static final String TAG = "SensorManager";
+public abstract class SensorManager {
+    /** @hide */
+    protected static final String TAG = "SensorManager";
+
     private static final float[] mTempMatrix = new float[16];
 
+    // Cached lists of sensors by type.  Guarded by mSensorListByType.
+    private final SparseArray<List<Sensor>> mSensorListByType =
+            new SparseArray<List<Sensor>>();
+
+    // Legacy sensor manager implementation.  Guarded by mSensorListByType during initialization.
+    private LegacySensorManager mLegacySensorManager;
+
     /* NOTE: sensor IDs must be a power of 2 */
 
     /**
@@ -353,340 +350,18 @@
     /** see {@link #remapCoordinateSystem} */
     public static final int AXIS_MINUS_Z = AXIS_Z | 0x80;
 
-    /*-----------------------------------------------------------------------*/
-
-    Looper mMainLooper;
-    @SuppressWarnings("deprecation")
-    private HashMap<SensorListener, LegacyListener> mLegacyListenersMap =
-        new HashMap<SensorListener, LegacyListener>();
-
-    /*-----------------------------------------------------------------------*/
-
-    private static final int SENSOR_DISABLE = -1;
-    private static boolean sSensorModuleInitialized = false;
-    private static ArrayList<Sensor> sFullSensorsList = new ArrayList<Sensor>();
-    private static SparseArray<List<Sensor>> sSensorListByType = new SparseArray<List<Sensor>>();
-    private static IWindowManager sWindowManager;
-    private static int sRotation = Surface.ROTATION_0;
-    /* The thread and the sensor list are global to the process
-     * but the actual thread is spawned on demand */
-    private static SensorThread sSensorThread;
-    private static int sQueue;
-
-    // Used within this module from outside SensorManager, don't make private
-    static SparseArray<Sensor> sHandleToSensor = new SparseArray<Sensor>();
-    static final ArrayList<ListenerDelegate> sListeners =
-        new ArrayList<ListenerDelegate>();
-
-    /*-----------------------------------------------------------------------*/
-
-    private class SensorEventPool {
-        private final int mPoolSize;
-        private final SensorEvent mPool[];
-        private int mNumItemsInPool;
-
-        private SensorEvent createSensorEvent() {
-            // maximal size for all legacy events is 3
-            return new SensorEvent(3);
-        }
-
-        SensorEventPool(int poolSize) {
-            mPoolSize = poolSize;
-            mNumItemsInPool = poolSize;
-            mPool = new SensorEvent[poolSize];
-        }
-
-        SensorEvent getFromPool() {
-            SensorEvent t = null;
-            synchronized (this) {
-                if (mNumItemsInPool > 0) {
-                    // remove the "top" item from the pool
-                    final int index = mPoolSize - mNumItemsInPool;
-                    t = mPool[index];
-                    mPool[index] = null;
-                    mNumItemsInPool--;
-                }
-            }
-            if (t == null) {
-                // the pool was empty or this item was removed from the pool for
-                // the first time. In any case, we need to create a new item.
-                t = createSensorEvent();
-            }
-            return t;
-        }
-
-        void returnToPool(SensorEvent t) {
-            synchronized (this) {
-                // is there space left in the pool?
-                if (mNumItemsInPool < mPoolSize) {
-                    // if so, return the item to the pool
-                    mNumItemsInPool++;
-                    final int index = mPoolSize - mNumItemsInPool;
-                    mPool[index] = t;
-                }
-            }
-        }
-    }
-
-    private static SensorEventPool sPool;
-
-    /*-----------------------------------------------------------------------*/
-
-    static private class SensorThread {
-
-        Thread mThread;
-        boolean mSensorsReady;
-
-        SensorThread() {
-        }
-
-        @Override
-        protected void finalize() {
-        }
-
-        // must be called with sListeners lock
-        boolean startLocked() {
-            try {
-                if (mThread == null) {
-                    mSensorsReady = false;
-                    SensorThreadRunnable runnable = new SensorThreadRunnable();
-                    Thread thread = new Thread(runnable, SensorThread.class.getName());
-                    thread.start();
-                    synchronized (runnable) {
-                        while (mSensorsReady == false) {
-                            runnable.wait();
-                        }
-                    }
-                    mThread = thread;
-                }
-            } catch (InterruptedException e) {
-            }
-            return mThread == null ? false : true;
-        }
-
-        private class SensorThreadRunnable implements Runnable {
-            SensorThreadRunnable() {
-            }
-
-            private boolean open() {
-                // NOTE: this cannot synchronize on sListeners, since
-                // it's held in the main thread at least until we
-                // return from here.
-                sQueue = sensors_create_queue();
-                return true;
-            }
-
-            public void run() {
-                //Log.d(TAG, "entering main sensor thread");
-                final float[] values = new float[3];
-                final int[] status = new int[1];
-                final long timestamp[] = new long[1];
-                Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
-
-                if (!open()) {
-                    return;
-                }
-
-                synchronized (this) {
-                    // we've open the driver, we're ready to open the sensors
-                    mSensorsReady = true;
-                    this.notify();
-                }
-
-                while (true) {
-                    // wait for an event
-                    final int sensor = sensors_data_poll(sQueue, values, status, timestamp);
-
-                    int accuracy = status[0];
-                    synchronized (sListeners) {
-                        if (sensor == -1 || sListeners.isEmpty()) {
-                            // we lost the connection to the event stream. this happens
-                            // when the last listener is removed or if there is an error
-                            if (sensor == -1 && !sListeners.isEmpty()) {
-                                // log a warning in case of abnormal termination
-                                Log.e(TAG, "_sensors_data_poll() failed, we bail out: sensors=" + sensor);
-                            }
-                            // we have no more listeners or polling failed, terminate the thread
-                            sensors_destroy_queue(sQueue);
-                            sQueue = 0;
-                            mThread = null;
-                            break;
-                        }
-                        final Sensor sensorObject = sHandleToSensor.get(sensor);
-                        if (sensorObject != null) {
-                            // report the sensor event to all listeners that
-                            // care about it.
-                            final int size = sListeners.size();
-                            for (int i=0 ; i<size ; i++) {
-                                ListenerDelegate listener = sListeners.get(i);
-                                if (listener.hasSensor(sensorObject)) {
-                                    // this is asynchronous (okay to call
-                                    // with sListeners lock held).
-                                    listener.onSensorChangedLocked(sensorObject,
-                                            values, timestamp, accuracy);
-                                }
-                            }
-                        }
-                    }
-                }
-                //Log.d(TAG, "exiting main sensor thread");
-            }
-        }
-    }
-
-    /*-----------------------------------------------------------------------*/
-
-    private class ListenerDelegate {
-        private final SensorEventListener mSensorEventListener;
-        private final ArrayList<Sensor> mSensorList = new ArrayList<Sensor>();
-        private final Handler mHandler;
-        public SparseBooleanArray mSensors = new SparseBooleanArray();
-        public SparseBooleanArray mFirstEvent = new SparseBooleanArray();
-        public SparseIntArray mSensorAccuracies = new SparseIntArray();
-
-        ListenerDelegate(SensorEventListener listener, Sensor sensor, Handler handler) {
-            mSensorEventListener = listener;
-            Looper looper = (handler != null) ? handler.getLooper() : mMainLooper;
-            // currently we create one Handler instance per listener, but we could
-            // have one per looper (we'd need to pass the ListenerDelegate
-            // instance to handleMessage and keep track of them separately).
-            mHandler = new Handler(looper) {
-                @Override
-                public void handleMessage(Message msg) {
-                    final SensorEvent t = (SensorEvent)msg.obj;
-                    final int handle = t.sensor.getHandle();
-
-                    switch (t.sensor.getType()) {
-                        // Only report accuracy for sensors that support it.
-                        case Sensor.TYPE_MAGNETIC_FIELD:
-                        case Sensor.TYPE_ORIENTATION:
-                            // call onAccuracyChanged() only if the value changes
-                            final int accuracy = mSensorAccuracies.get(handle);
-                            if ((t.accuracy >= 0) && (accuracy != t.accuracy)) {
-                                mSensorAccuracies.put(handle, t.accuracy);
-                                mSensorEventListener.onAccuracyChanged(t.sensor, t.accuracy);
-                            }
-                            break;
-                        default:
-                            // For other sensors, just report the accuracy once
-                            if (mFirstEvent.get(handle) == false) {
-                                mFirstEvent.put(handle, true);
-                                mSensorEventListener.onAccuracyChanged(
-                                        t.sensor, SENSOR_STATUS_ACCURACY_HIGH);
-                            }
-                            break;
-                    }
-
-                    mSensorEventListener.onSensorChanged(t);
-                    sPool.returnToPool(t);
-                }
-            };
-            addSensor(sensor);
-        }
-
-        Object getListener() {
-            return mSensorEventListener;
-        }
-
-        void addSensor(Sensor sensor) {
-            mSensors.put(sensor.getHandle(), true);
-            mSensorList.add(sensor);
-        }
-        int removeSensor(Sensor sensor) {
-            mSensors.delete(sensor.getHandle());
-            mSensorList.remove(sensor);
-            return mSensors.size();
-        }
-        boolean hasSensor(Sensor sensor) {
-            return mSensors.get(sensor.getHandle());
-        }
-        List<Sensor> getSensors() {
-            return mSensorList;
-        }
-
-        void onSensorChangedLocked(Sensor sensor, float[] values, long[] timestamp, int accuracy) {
-            SensorEvent t = sPool.getFromPool();
-            final float[] v = t.values;
-            v[0] = values[0];
-            v[1] = values[1];
-            v[2] = values[2];
-            t.timestamp = timestamp[0];
-            t.accuracy = accuracy;
-            t.sensor = sensor;
-            Message msg = Message.obtain();
-            msg.what = 0;
-            msg.obj = t;
-            msg.setAsynchronous(true);
-            mHandler.sendMessage(msg);
-        }
-    }
 
     /**
      * {@hide}
      */
-    public SensorManager(Looper mainLooper) {
-        mMainLooper = mainLooper;
-
-
-        synchronized(sListeners) {
-            if (!sSensorModuleInitialized) {
-                sSensorModuleInitialized = true;
-
-                nativeClassInit();
-
-                sWindowManager = IWindowManager.Stub.asInterface(
-                        ServiceManager.getService("window"));
-                if (sWindowManager != null) {
-                    // if it's null we're running in the system process
-                    // which won't get the rotated values
-                    try {
-                        sRotation = sWindowManager.watchRotation(
-                                new IRotationWatcher.Stub() {
-                                    public void onRotationChanged(int rotation) {
-                                        SensorManager.this.onRotationChanged(rotation);
-                                    }
-                                }
-                        );
-                    } catch (RemoteException e) {
-                    }
-                }
-
-                // initialize the sensor list
-                sensors_module_init();
-                final ArrayList<Sensor> fullList = sFullSensorsList;
-                int i = 0;
-                do {
-                    Sensor sensor = new Sensor();
-                    i = sensors_module_get_next_sensor(sensor, i);
-
-                    if (i>=0) {
-                        //Log.d(TAG, "found sensor: " + sensor.getName() +
-                        //        ", handle=" + sensor.getHandle());
-                        sensor.setLegacyType(getLegacySensorType(sensor.getType()));
-                        fullList.add(sensor);
-                        sHandleToSensor.append(sensor.getHandle(), sensor);
-                    }
-                } while (i>0);
-
-                sPool = new SensorEventPool( sFullSensorsList.size()*2 );
-                sSensorThread = new SensorThread();
-            }
-        }
+    public SensorManager() {
     }
 
-    private int getLegacySensorType(int type) {
-        switch (type) {
-            case Sensor.TYPE_ACCELEROMETER:
-                return SENSOR_ACCELEROMETER;
-            case Sensor.TYPE_MAGNETIC_FIELD:
-                return SENSOR_MAGNETIC_FIELD;
-            case Sensor.TYPE_ORIENTATION:
-                return SENSOR_ORIENTATION_RAW;
-            case Sensor.TYPE_TEMPERATURE:
-                return SENSOR_TEMPERATURE;
-        }
-        return 0;
-    }
+    /**
+     * Gets the full list of sensors that are available.
+     * @hide
+     */
+    protected abstract List<Sensor> getFullSensorList();
 
     /**
      * @return available sensors.
@@ -695,23 +370,7 @@
      */
     @Deprecated
     public int getSensors() {
-        int result = 0;
-        final ArrayList<Sensor> fullList = sFullSensorsList;
-        for (Sensor i : fullList) {
-            switch (i.getType()) {
-                case Sensor.TYPE_ACCELEROMETER:
-                    result |= SensorManager.SENSOR_ACCELEROMETER;
-                    break;
-                case Sensor.TYPE_MAGNETIC_FIELD:
-                    result |= SensorManager.SENSOR_MAGNETIC_FIELD;
-                    break;
-                case Sensor.TYPE_ORIENTATION:
-                    result |= SensorManager.SENSOR_ORIENTATION |
-                    SensorManager.SENSOR_ORIENTATION_RAW;
-                    break;
-            }
-        }
-        return result;
+        return getLegacySensorManager().getSensors();
     }
 
     /**
@@ -731,9 +390,9 @@
     public List<Sensor> getSensorList(int type) {
         // cache the returned lists the first time
         List<Sensor> list;
-        final ArrayList<Sensor> fullList = sFullSensorsList;
-        synchronized(fullList) {
-            list = sSensorListByType.get(type);
+        final List<Sensor> fullList = getFullSensorList();
+        synchronized (mSensorListByType) {
+            list = mSensorListByType.get(type);
             if (list == null) {
                 if (type == Sensor.TYPE_ALL) {
                     list = fullList;
@@ -745,7 +404,7 @@
                     }
                 }
                 list = Collections.unmodifiableList(list);
-                sSensorListByType.append(type, list);
+                mSensorListByType.append(type, list);
             }
         }
         return list;
@@ -817,128 +476,7 @@
      */
     @Deprecated
     public boolean registerListener(SensorListener listener, int sensors, int rate) {
-        if (listener == null) {
-            return false;
-        }
-        boolean result = false;
-        result = registerLegacyListener(SENSOR_ACCELEROMETER, Sensor.TYPE_ACCELEROMETER,
-                listener, sensors, rate) || result;
-        result = registerLegacyListener(SENSOR_MAGNETIC_FIELD, Sensor.TYPE_MAGNETIC_FIELD,
-                listener, sensors, rate) || result;
-        result = registerLegacyListener(SENSOR_ORIENTATION_RAW, Sensor.TYPE_ORIENTATION,
-                listener, sensors, rate) || result;
-        result = registerLegacyListener(SENSOR_ORIENTATION, Sensor.TYPE_ORIENTATION,
-                listener, sensors, rate) || result;
-        result = registerLegacyListener(SENSOR_TEMPERATURE, Sensor.TYPE_TEMPERATURE,
-                listener, sensors, rate) || result;
-        return result;
-    }
-
-    @SuppressWarnings("deprecation")
-    private boolean registerLegacyListener(int legacyType, int type,
-            SensorListener listener, int sensors, int rate)
-    {
-        if (listener == null) {
-            return false;
-        }
-        boolean result = false;
-        // Are we activating this legacy sensor?
-        if ((sensors & legacyType) != 0) {
-            // if so, find a suitable Sensor
-            Sensor sensor = getDefaultSensor(type);
-            if (sensor != null) {
-                // If we don't already have one, create a LegacyListener
-                // to wrap this listener and process the events as
-                // they are expected by legacy apps.
-                LegacyListener legacyListener = null;
-                synchronized (mLegacyListenersMap) {
-                    legacyListener = mLegacyListenersMap.get(listener);
-                    if (legacyListener == null) {
-                        // we didn't find a LegacyListener for this client,
-                        // create one, and put it in our list.
-                        legacyListener = new LegacyListener(listener);
-                        mLegacyListenersMap.put(listener, legacyListener);
-                    }
-                }
-                // register this legacy sensor with this legacy listener
-                legacyListener.registerSensor(legacyType);
-                // and finally, register the legacy listener with the new apis
-                result = registerListener(legacyListener, sensor, rate);
-            }
-        }
-        return result;
-    }
-
-    /**
-     * Unregisters a listener for the sensors with which it is registered.
-     *
-     * @deprecated This method is deprecated, use
-     *             {@link SensorManager#unregisterListener(SensorEventListener, Sensor)}
-     *             instead.
-     *
-     * @param listener
-     *        a SensorListener object
-     *
-     * @param sensors
-     *        a bit masks of the sensors to unregister from
-     */
-    @Deprecated
-    public void unregisterListener(SensorListener listener, int sensors) {
-        unregisterLegacyListener(SENSOR_ACCELEROMETER, Sensor.TYPE_ACCELEROMETER,
-                listener, sensors);
-        unregisterLegacyListener(SENSOR_MAGNETIC_FIELD, Sensor.TYPE_MAGNETIC_FIELD,
-                listener, sensors);
-        unregisterLegacyListener(SENSOR_ORIENTATION_RAW, Sensor.TYPE_ORIENTATION,
-                listener, sensors);
-        unregisterLegacyListener(SENSOR_ORIENTATION, Sensor.TYPE_ORIENTATION,
-                listener, sensors);
-        unregisterLegacyListener(SENSOR_TEMPERATURE, Sensor.TYPE_TEMPERATURE,
-                listener, sensors);
-    }
-
-    @SuppressWarnings("deprecation")
-    private void unregisterLegacyListener(int legacyType, int type,
-            SensorListener listener, int sensors)
-    {
-        if (listener == null) {
-            return;
-        }
-        // do we know about this listener?
-        LegacyListener legacyListener = null;
-        synchronized (mLegacyListenersMap) {
-            legacyListener = mLegacyListenersMap.get(listener);
-        }
-        if (legacyListener != null) {
-            // Are we deactivating this legacy sensor?
-            if ((sensors & legacyType) != 0) {
-                // if so, find the corresponding Sensor
-                Sensor sensor = getDefaultSensor(type);
-                if (sensor != null) {
-                    // unregister this legacy sensor and if we don't
-                    // need the corresponding Sensor, unregister it too
-                    if (legacyListener.unregisterSensor(legacyType)) {
-                        // corresponding sensor not needed, unregister
-                        unregisterListener(legacyListener, sensor);
-                        // finally check if we still need the legacyListener
-                        // in our mapping, if not, get rid of it too.
-                        synchronized(sListeners) {
-                            boolean found = false;
-                            for (ListenerDelegate i : sListeners) {
-                                if (i.getListener() == legacyListener) {
-                                    found = true;
-                                    break;
-                                }
-                            }
-                            if (!found) {
-                                synchronized (mLegacyListenersMap) {
-                                    mLegacyListenersMap.remove(listener);
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
+        return getLegacySensorManager().registerListener(listener, sensors, rate);
     }
 
     /**
@@ -959,6 +497,24 @@
     /**
      * Unregisters a listener for the sensors with which it is registered.
      *
+     * @deprecated This method is deprecated, use
+     *             {@link SensorManager#unregisterListener(SensorEventListener, Sensor)}
+     *             instead.
+     *
+     * @param listener
+     *        a SensorListener object
+     *
+     * @param sensors
+     *        a bit masks of the sensors to unregister from
+     */
+    @Deprecated
+    public void unregisterListener(SensorListener listener, int sensors) {
+        getLegacySensorManager().unregisterListener(listener, sensors);
+    }
+
+    /**
+     * Unregisters a listener for the sensors with which it is registered.
+     *
      * @param listener
      *        a SensorEventListener object
      *
@@ -970,7 +526,11 @@
      *
      */
     public void unregisterListener(SensorEventListener listener, Sensor sensor) {
-        unregisterListener((Object)listener, sensor);
+        if (listener == null || sensor == null) {
+            return;
+        }
+
+        unregisterListenerImpl(listener, sensor);
     }
 
     /**
@@ -984,9 +544,16 @@
      *
      */
     public void unregisterListener(SensorEventListener listener) {
-        unregisterListener((Object)listener);
+        if (listener == null) {
+            return;
+        }
+
+        unregisterListenerImpl(listener, null);
     }
 
+    /** @hide */
+    protected abstract void unregisterListenerImpl(SensorEventListener listener, Sensor sensor);
+
     /**
      * Registers a {@link android.hardware.SensorEventListener
      * SensorEventListener} for the given sensor.
@@ -1019,31 +586,6 @@
         return registerListener(listener, sensor, rate, null);
     }
 
-    private boolean enableSensorLocked(Sensor sensor, int delay) {
-        boolean result = false;
-        for (ListenerDelegate i : sListeners) {
-            if (i.hasSensor(sensor)) {
-                String name = sensor.getName();
-                int handle = sensor.getHandle();
-                result = sensors_enable_sensor(sQueue, name, handle, delay);
-                break;
-            }
-        }
-        return result;
-    }
-
-    private boolean disableSensorLocked(Sensor sensor) {
-        for (ListenerDelegate i : sListeners) {
-            if (i.hasSensor(sensor)) {
-                // not an error, it's just that this sensor is still in use
-                return true;
-            }
-        }
-        String name = sensor.getName();
-        int handle = sensor.getHandle();
-        return sensors_enable_sensor(sQueue, name, handle, SENSOR_DISABLE);
-    }
-
     /**
      * Registers a {@link android.hardware.SensorEventListener
      * SensorEventListener} for the given sensor.
@@ -1081,7 +623,7 @@
         if (listener == null || sensor == null) {
             return false;
         }
-        boolean result = true;
+
         int delay = -1;
         switch (rate) {
             case SENSOR_DELAY_FASTEST:
@@ -1101,92 +643,12 @@
                 break;
         }
 
-        synchronized (sListeners) {
-            // look for this listener in our list
-            ListenerDelegate l = null;
-            for (ListenerDelegate i : sListeners) {
-                if (i.getListener() == listener) {
-                    l = i;
-                    break;
-                }
-            }
-
-            // if we don't find it, add it to the list
-            if (l == null) {
-                l = new ListenerDelegate(listener, sensor, handler);
-                sListeners.add(l);
-                // if the list is not empty, start our main thread
-                if (!sListeners.isEmpty()) {
-                    if (sSensorThread.startLocked()) {
-                        if (!enableSensorLocked(sensor, delay)) {
-                            // oops. there was an error
-                            sListeners.remove(l);
-                            result = false;
-                        }
-                    } else {
-                        // there was an error, remove the listener
-                        sListeners.remove(l);
-                        result = false;
-                    }
-                } else {
-                    // weird, we couldn't add the listener
-                    result = false;
-                }
-            } else {
-                l.addSensor(sensor);
-                if (!enableSensorLocked(sensor, delay)) {
-                    // oops. there was an error
-                    l.removeSensor(sensor);
-                    result = false;
-                }
-            }
-        }
-
-        return result;
+        return registerListenerImpl(listener, sensor, delay, handler);
     }
 
-    private void unregisterListener(Object listener, Sensor sensor) {
-        if (listener == null || sensor == null) {
-            return;
-        }
-
-        synchronized (sListeners) {
-            final int size = sListeners.size();
-            for (int i=0 ; i<size ; i++) {
-                ListenerDelegate l = sListeners.get(i);
-                if (l.getListener() == listener) {
-                    if (l.removeSensor(sensor) == 0) {
-                        // if we have no more sensors enabled on this listener,
-                        // take it off the list.
-                        sListeners.remove(i);
-                    }
-                    break;
-                }
-            }
-            disableSensorLocked(sensor);
-        }
-    }
-
-    private void unregisterListener(Object listener) {
-        if (listener == null) {
-            return;
-        }
-
-        synchronized (sListeners) {
-            final int size = sListeners.size();
-            for (int i=0 ; i<size ; i++) {
-                ListenerDelegate l = sListeners.get(i);
-                if (l.getListener() == listener) {
-                    sListeners.remove(i);
-                    // disable all sensors for this listener
-                    for (Sensor sensor : l.getSensors()) {
-                        disableSensorLocked(sensor);
-                    }
-                    break;
-                }
-            }
-        }
-    }
+    /** @hide */
+    protected abstract boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
+            int delay, Handler handler);
 
     /**
      * <p>
@@ -1653,228 +1115,11 @@
      * @param p atmospheric pressure
      * @return Altitude in meters
      */
-   public static float getAltitude(float p0, float p) {
+    public static float getAltitude(float p0, float p) {
         final float coef = 1.0f / 5.255f;
         return 44330.0f * (1.0f - (float)Math.pow(p/p0, coef));
     }
 
-
-   /**
-     * {@hide}
-     */
-    public void onRotationChanged(int rotation) {
-        synchronized(sListeners) {
-            sRotation  = rotation;
-        }
-    }
-
-    static int getRotation() {
-        synchronized(sListeners) {
-            return sRotation;
-        }
-    }
-
-    private class LegacyListener implements SensorEventListener {
-        private float mValues[] = new float[6];
-        @SuppressWarnings("deprecation")
-        private SensorListener mTarget;
-        private int mSensors;
-        private final LmsFilter mYawfilter = new LmsFilter();
-
-        @SuppressWarnings("deprecation")
-        LegacyListener(SensorListener target) {
-            mTarget = target;
-            mSensors = 0;
-        }
-
-        void registerSensor(int legacyType) {
-            mSensors |= legacyType;
-        }
-
-        boolean unregisterSensor(int legacyType) {
-            mSensors &= ~legacyType;
-            int mask = SENSOR_ORIENTATION|SENSOR_ORIENTATION_RAW;
-            if (((legacyType&mask)!=0) && ((mSensors&mask)!=0)) {
-                return false;
-            }
-            return true;
-        }
-
-        @SuppressWarnings("deprecation")
-        public void onAccuracyChanged(Sensor sensor, int accuracy) {
-            try {
-                mTarget.onAccuracyChanged(sensor.getLegacyType(), accuracy);
-            } catch (AbstractMethodError e) {
-                // old app that doesn't implement this method
-                // just ignore it.
-            }
-        }
-
-        @SuppressWarnings("deprecation")
-        public void onSensorChanged(SensorEvent event) {
-            final float v[] = mValues;
-            v[0] = event.values[0];
-            v[1] = event.values[1];
-            v[2] = event.values[2];
-            int legacyType = event.sensor.getLegacyType();
-            mapSensorDataToWindow(legacyType, v, SensorManager.getRotation());
-            if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) {
-                if ((mSensors & SENSOR_ORIENTATION_RAW)!=0) {
-                    mTarget.onSensorChanged(SENSOR_ORIENTATION_RAW, v);
-                }
-                if ((mSensors & SENSOR_ORIENTATION)!=0) {
-                    v[0] = mYawfilter.filter(event.timestamp, v[0]);
-                    mTarget.onSensorChanged(SENSOR_ORIENTATION, v);
-                }
-            } else {
-                mTarget.onSensorChanged(legacyType, v);
-            }
-        }
-
-        /*
-         * Helper function to convert the specified sensor's data to the windows's
-         * coordinate space from the device's coordinate space.
-         *
-         * output: 3,4,5: values in the old API format
-         *         0,1,2: transformed values in the old API format
-         *
-         */
-        private void mapSensorDataToWindow(int sensor,
-                float[] values, int orientation) {
-            float x = values[0];
-            float y = values[1];
-            float z = values[2];
-
-            switch (sensor) {
-                case SensorManager.SENSOR_ORIENTATION:
-                case SensorManager.SENSOR_ORIENTATION_RAW:
-                    z = -z;
-                    break;
-                case SensorManager.SENSOR_ACCELEROMETER:
-                    x = -x;
-                    y = -y;
-                    z = -z;
-                    break;
-                case SensorManager.SENSOR_MAGNETIC_FIELD:
-                    x = -x;
-                    y = -y;
-                    break;
-            }
-            values[0] = x;
-            values[1] = y;
-            values[2] = z;
-            values[3] = x;
-            values[4] = y;
-            values[5] = z;
-
-            if ((orientation & Surface.ROTATION_90) != 0) {
-                // handles 90 and 270 rotation
-                switch (sensor) {
-                    case SENSOR_ACCELEROMETER:
-                    case SENSOR_MAGNETIC_FIELD:
-                        values[0] =-y;
-                        values[1] = x;
-                        values[2] = z;
-                        break;
-                    case SENSOR_ORIENTATION:
-                    case SENSOR_ORIENTATION_RAW:
-                        values[0] = x + ((x < 270) ? 90 : -270);
-                        values[1] = z;
-                        values[2] = y;
-                        break;
-                }
-            }
-            if ((orientation & Surface.ROTATION_180) != 0) {
-                x = values[0];
-                y = values[1];
-                z = values[2];
-                // handles 180 (flip) and 270 (flip + 90) rotation
-                switch (sensor) {
-                    case SENSOR_ACCELEROMETER:
-                    case SENSOR_MAGNETIC_FIELD:
-                        values[0] =-x;
-                        values[1] =-y;
-                        values[2] = z;
-                        break;
-                    case SENSOR_ORIENTATION:
-                    case SENSOR_ORIENTATION_RAW:
-                        values[0] = (x >= 180) ? (x - 180) : (x + 180);
-                        values[1] =-y;
-                        values[2] =-z;
-                        break;
-                }
-            }
-        }
-    }
-
-    class LmsFilter {
-        private static final int SENSORS_RATE_MS = 20;
-        private static final int COUNT = 12;
-        private static final float PREDICTION_RATIO = 1.0f/3.0f;
-        private static final float PREDICTION_TIME = (SENSORS_RATE_MS*COUNT/1000.0f)*PREDICTION_RATIO;
-        private float mV[] = new float[COUNT*2];
-        private float mT[] = new float[COUNT*2];
-        private int mIndex;
-
-        public LmsFilter() {
-            mIndex = COUNT;
-        }
-
-        public float filter(long time, float in) {
-            float v = in;
-            final float ns = 1.0f / 1000000000.0f;
-            final float t = time*ns;
-            float v1 = mV[mIndex];
-            if ((v-v1) > 180) {
-                v -= 360;
-            } else if ((v1-v) > 180) {
-                v += 360;
-            }
-            /* Manage the circular buffer, we write the data twice spaced
-             * by COUNT values, so that we don't have to copy the array
-             * when it's full
-             */
-            mIndex++;
-            if (mIndex >= COUNT*2)
-                mIndex = COUNT;
-            mV[mIndex] = v;
-            mT[mIndex] = t;
-            mV[mIndex-COUNT] = v;
-            mT[mIndex-COUNT] = t;
-
-            float A, B, C, D, E;
-            float a, b;
-            int i;
-
-            A = B = C = D = E = 0;
-            for (i=0 ; i<COUNT-1 ; i++) {
-                final int j = mIndex - 1 - i;
-                final float Z = mV[j];
-                final float T = 0.5f*(mT[j] + mT[j+1]) - t;
-                float dT = mT[j] - mT[j+1];
-                dT *= dT;
-                A += Z*dT;
-                B += T*(T*dT);
-                C +=   (T*dT);
-                D += Z*(T*dT);
-                E += dT;
-            }
-            b = (A*B + C*D) / (E*B + C*C);
-            a = (E*b - A) / C;
-            float f = b + PREDICTION_TIME*a;
-
-            // Normalize
-            f *= (1.0f / 360.0f);
-            if (((f>=0)?f:-f) >= 0.5f)
-                f = f - (float)Math.ceil(f + 0.5f) + 1.0f;
-            if (f < 0)
-                f += 1.0f;
-            f *= 360.0f;
-            return f;
-        }
-    }
-
-
     /** Helper function to compute the angle change between two rotation matrices.
      *  Given a current rotation matrix (R) and a previous rotation matrix
      *  (prevR) computes the rotation around the x,y, and z axes which
@@ -2060,14 +1305,66 @@
         Q[3] = rv[2];
     }
 
-    private static native void nativeClassInit();
+    private LegacySensorManager getLegacySensorManager() {
+        synchronized (mSensorListByType) {
+            if (mLegacySensorManager == null) {
+                Log.i(TAG, "This application is using deprecated SensorManager API which will "
+                        + "be removed someday.  Please consider switching to the new API.");
+                mLegacySensorManager = new LegacySensorManager(this);
+            }
+            return mLegacySensorManager;
+        }
+    }
 
-    private static native int sensors_module_init();
-    private static native int sensors_module_get_next_sensor(Sensor sensor, int next);
+    /**
+     * Sensor event pool implementation.
+     * @hide
+     */
+    protected static final class SensorEventPool {
+        private final int mPoolSize;
+        private final SensorEvent mPool[];
+        private int mNumItemsInPool;
 
-    // Used within this module from outside SensorManager, don't make private
-    static native int sensors_create_queue();
-    static native void sensors_destroy_queue(int queue);
-    static native boolean sensors_enable_sensor(int queue, String name, int sensor, int enable);
-    static native int sensors_data_poll(int queue, float[] values, int[] status, long[] timestamp);
+        private SensorEvent createSensorEvent() {
+            // maximal size for all legacy events is 3
+            return new SensorEvent(3);
+        }
+
+        SensorEventPool(int poolSize) {
+            mPoolSize = poolSize;
+            mNumItemsInPool = poolSize;
+            mPool = new SensorEvent[poolSize];
+        }
+
+        SensorEvent getFromPool() {
+            SensorEvent t = null;
+            synchronized (this) {
+                if (mNumItemsInPool > 0) {
+                    // remove the "top" item from the pool
+                    final int index = mPoolSize - mNumItemsInPool;
+                    t = mPool[index];
+                    mPool[index] = null;
+                    mNumItemsInPool--;
+                }
+            }
+            if (t == null) {
+                // the pool was empty or this item was removed from the pool for
+                // the first time. In any case, we need to create a new item.
+                t = createSensorEvent();
+            }
+            return t;
+        }
+
+        void returnToPool(SensorEvent t) {
+            synchronized (this) {
+                // is there space left in the pool?
+                if (mNumItemsInPool < mPoolSize) {
+                    // if so, return the item to the pool
+                    mNumItemsInPool++;
+                    final int index = mPoolSize - mNumItemsInPool;
+                    mPool[index] = t;
+                }
+            }
+        }
+    }
 }
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
new file mode 100644
index 0000000..0204e94
--- /dev/null
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -0,0 +1,398 @@
+/*
+ * 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;
+
+import android.os.Looper;
+import android.os.Process;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Sensor manager implementation that communicates with the built-in
+ * system sensors.
+ *
+ * @hide
+ */
+public class SystemSensorManager extends SensorManager {
+    private static final int SENSOR_DISABLE = -1;
+    private static boolean sSensorModuleInitialized = false;
+    private static ArrayList<Sensor> sFullSensorsList = new ArrayList<Sensor>();
+    /* The thread and the sensor list are global to the process
+     * but the actual thread is spawned on demand */
+    private static SensorThread sSensorThread;
+    private static int sQueue;
+
+    // Used within this module from outside SensorManager, don't make private
+    static SparseArray<Sensor> sHandleToSensor = new SparseArray<Sensor>();
+    static final ArrayList<ListenerDelegate> sListeners =
+        new ArrayList<ListenerDelegate>();
+
+    // Common pool of sensor events.
+    static SensorEventPool sPool;
+
+    // Looper associated with the context in which this instance was created.
+    final Looper mMainLooper;
+
+    /*-----------------------------------------------------------------------*/
+
+    static private class SensorThread {
+
+        Thread mThread;
+        boolean mSensorsReady;
+
+        SensorThread() {
+        }
+
+        @Override
+        protected void finalize() {
+        }
+
+        // must be called with sListeners lock
+        boolean startLocked() {
+            try {
+                if (mThread == null) {
+                    mSensorsReady = false;
+                    SensorThreadRunnable runnable = new SensorThreadRunnable();
+                    Thread thread = new Thread(runnable, SensorThread.class.getName());
+                    thread.start();
+                    synchronized (runnable) {
+                        while (mSensorsReady == false) {
+                            runnable.wait();
+                        }
+                    }
+                    mThread = thread;
+                }
+            } catch (InterruptedException e) {
+            }
+            return mThread == null ? false : true;
+        }
+
+        private class SensorThreadRunnable implements Runnable {
+            SensorThreadRunnable() {
+            }
+
+            private boolean open() {
+                // NOTE: this cannot synchronize on sListeners, since
+                // it's held in the main thread at least until we
+                // return from here.
+                sQueue = sensors_create_queue();
+                return true;
+            }
+
+            public void run() {
+                //Log.d(TAG, "entering main sensor thread");
+                final float[] values = new float[3];
+                final int[] status = new int[1];
+                final long timestamp[] = new long[1];
+                Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
+
+                if (!open()) {
+                    return;
+                }
+
+                synchronized (this) {
+                    // we've open the driver, we're ready to open the sensors
+                    mSensorsReady = true;
+                    this.notify();
+                }
+
+                while (true) {
+                    // wait for an event
+                    final int sensor = sensors_data_poll(sQueue, values, status, timestamp);
+
+                    int accuracy = status[0];
+                    synchronized (sListeners) {
+                        if (sensor == -1 || sListeners.isEmpty()) {
+                            // we lost the connection to the event stream. this happens
+                            // when the last listener is removed or if there is an error
+                            if (sensor == -1 && !sListeners.isEmpty()) {
+                                // log a warning in case of abnormal termination
+                                Log.e(TAG, "_sensors_data_poll() failed, we bail out: sensors=" + sensor);
+                            }
+                            // we have no more listeners or polling failed, terminate the thread
+                            sensors_destroy_queue(sQueue);
+                            sQueue = 0;
+                            mThread = null;
+                            break;
+                        }
+                        final Sensor sensorObject = sHandleToSensor.get(sensor);
+                        if (sensorObject != null) {
+                            // report the sensor event to all listeners that
+                            // care about it.
+                            final int size = sListeners.size();
+                            for (int i=0 ; i<size ; i++) {
+                                ListenerDelegate listener = sListeners.get(i);
+                                if (listener.hasSensor(sensorObject)) {
+                                    // this is asynchronous (okay to call
+                                    // with sListeners lock held).
+                                    listener.onSensorChangedLocked(sensorObject,
+                                            values, timestamp, accuracy);
+                                }
+                            }
+                        }
+                    }
+                }
+                //Log.d(TAG, "exiting main sensor thread");
+            }
+        }
+    }
+
+    /*-----------------------------------------------------------------------*/
+
+    private class ListenerDelegate {
+        private final SensorEventListener mSensorEventListener;
+        private final ArrayList<Sensor> mSensorList = new ArrayList<Sensor>();
+        private final Handler mHandler;
+        public SparseBooleanArray mSensors = new SparseBooleanArray();
+        public SparseBooleanArray mFirstEvent = new SparseBooleanArray();
+        public SparseIntArray mSensorAccuracies = new SparseIntArray();
+
+        ListenerDelegate(SensorEventListener listener, Sensor sensor, Handler handler) {
+            mSensorEventListener = listener;
+            Looper looper = (handler != null) ? handler.getLooper() : mMainLooper;
+            // currently we create one Handler instance per listener, but we could
+            // have one per looper (we'd need to pass the ListenerDelegate
+            // instance to handleMessage and keep track of them separately).
+            mHandler = new Handler(looper) {
+                @Override
+                public void handleMessage(Message msg) {
+                    final SensorEvent t = (SensorEvent)msg.obj;
+                    final int handle = t.sensor.getHandle();
+
+                    switch (t.sensor.getType()) {
+                        // Only report accuracy for sensors that support it.
+                        case Sensor.TYPE_MAGNETIC_FIELD:
+                        case Sensor.TYPE_ORIENTATION:
+                            // call onAccuracyChanged() only if the value changes
+                            final int accuracy = mSensorAccuracies.get(handle);
+                            if ((t.accuracy >= 0) && (accuracy != t.accuracy)) {
+                                mSensorAccuracies.put(handle, t.accuracy);
+                                mSensorEventListener.onAccuracyChanged(t.sensor, t.accuracy);
+                            }
+                            break;
+                        default:
+                            // For other sensors, just report the accuracy once
+                            if (mFirstEvent.get(handle) == false) {
+                                mFirstEvent.put(handle, true);
+                                mSensorEventListener.onAccuracyChanged(
+                                        t.sensor, SENSOR_STATUS_ACCURACY_HIGH);
+                            }
+                            break;
+                    }
+
+                    mSensorEventListener.onSensorChanged(t);
+                    sPool.returnToPool(t);
+                }
+            };
+            addSensor(sensor);
+        }
+
+        Object getListener() {
+            return mSensorEventListener;
+        }
+
+        void addSensor(Sensor sensor) {
+            mSensors.put(sensor.getHandle(), true);
+            mSensorList.add(sensor);
+        }
+        int removeSensor(Sensor sensor) {
+            mSensors.delete(sensor.getHandle());
+            mSensorList.remove(sensor);
+            return mSensors.size();
+        }
+        boolean hasSensor(Sensor sensor) {
+            return mSensors.get(sensor.getHandle());
+        }
+        List<Sensor> getSensors() {
+            return mSensorList;
+        }
+
+        void onSensorChangedLocked(Sensor sensor, float[] values, long[] timestamp, int accuracy) {
+            SensorEvent t = sPool.getFromPool();
+            final float[] v = t.values;
+            v[0] = values[0];
+            v[1] = values[1];
+            v[2] = values[2];
+            t.timestamp = timestamp[0];
+            t.accuracy = accuracy;
+            t.sensor = sensor;
+            Message msg = Message.obtain();
+            msg.what = 0;
+            msg.obj = t;
+            msg.setAsynchronous(true);
+            mHandler.sendMessage(msg);
+        }
+    }
+
+    /**
+     * {@hide}
+     */
+    public SystemSensorManager(Looper mainLooper) {
+        mMainLooper = mainLooper;
+
+        synchronized(sListeners) {
+            if (!sSensorModuleInitialized) {
+                sSensorModuleInitialized = true;
+
+                nativeClassInit();
+
+                // initialize the sensor list
+                sensors_module_init();
+                final ArrayList<Sensor> fullList = sFullSensorsList;
+                int i = 0;
+                do {
+                    Sensor sensor = new Sensor();
+                    i = sensors_module_get_next_sensor(sensor, i);
+
+                    if (i>=0) {
+                        //Log.d(TAG, "found sensor: " + sensor.getName() +
+                        //        ", handle=" + sensor.getHandle());
+                        fullList.add(sensor);
+                        sHandleToSensor.append(sensor.getHandle(), sensor);
+                    }
+                } while (i>0);
+
+                sPool = new SensorEventPool( sFullSensorsList.size()*2 );
+                sSensorThread = new SensorThread();
+            }
+        }
+    }
+
+    /** @hide */
+    @Override
+    protected List<Sensor> getFullSensorList() {
+        return sFullSensorsList;
+    }
+
+    private boolean enableSensorLocked(Sensor sensor, int delay) {
+        boolean result = false;
+        for (ListenerDelegate i : sListeners) {
+            if (i.hasSensor(sensor)) {
+                String name = sensor.getName();
+                int handle = sensor.getHandle();
+                result = sensors_enable_sensor(sQueue, name, handle, delay);
+                break;
+            }
+        }
+        return result;
+    }
+
+    private boolean disableSensorLocked(Sensor sensor) {
+        for (ListenerDelegate i : sListeners) {
+            if (i.hasSensor(sensor)) {
+                // not an error, it's just that this sensor is still in use
+                return true;
+            }
+        }
+        String name = sensor.getName();
+        int handle = sensor.getHandle();
+        return sensors_enable_sensor(sQueue, name, handle, SENSOR_DISABLE);
+    }
+
+    /** @hide */
+    @Override
+    protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
+            int delay, Handler handler) {
+        boolean result = true;
+        synchronized (sListeners) {
+            // look for this listener in our list
+            ListenerDelegate l = null;
+            for (ListenerDelegate i : sListeners) {
+                if (i.getListener() == listener) {
+                    l = i;
+                    break;
+                }
+            }
+
+            // if we don't find it, add it to the list
+            if (l == null) {
+                l = new ListenerDelegate(listener, sensor, handler);
+                sListeners.add(l);
+                // if the list is not empty, start our main thread
+                if (!sListeners.isEmpty()) {
+                    if (sSensorThread.startLocked()) {
+                        if (!enableSensorLocked(sensor, delay)) {
+                            // oops. there was an error
+                            sListeners.remove(l);
+                            result = false;
+                        }
+                    } else {
+                        // there was an error, remove the listener
+                        sListeners.remove(l);
+                        result = false;
+                    }
+                } else {
+                    // weird, we couldn't add the listener
+                    result = false;
+                }
+            } else if (!l.hasSensor(sensor)) {
+                l.addSensor(sensor);
+                if (!enableSensorLocked(sensor, delay)) {
+                    // oops. there was an error
+                    l.removeSensor(sensor);
+                    result = false;
+                }
+            }
+        }
+
+        return result;
+    }
+
+    /** @hide */
+    @Override
+    protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) {
+        synchronized (sListeners) {
+            final int size = sListeners.size();
+            for (int i=0 ; i<size ; i++) {
+                ListenerDelegate l = sListeners.get(i);
+                if (l.getListener() == listener) {
+                    if (sensor == null) {
+                        sListeners.remove(i);
+                        // disable all sensors for this listener
+                        for (Sensor s : l.getSensors()) {
+                            disableSensorLocked(s);
+                        }
+                    } else if (l.removeSensor(sensor) == 0) {
+                        // if we have no more sensors enabled on this listener,
+                        // take it off the list.
+                        sListeners.remove(i);
+                        disableSensorLocked(sensor);
+                    }
+                    break;
+                }
+            }
+        }
+    }
+
+    private static native void nativeClassInit();
+
+    private static native int sensors_module_init();
+    private static native int sensors_module_get_next_sensor(Sensor sensor, int next);
+
+    // Used within this module from outside SensorManager, don't make private
+    static native int sensors_create_queue();
+    static native void sensors_destroy_queue(int queue);
+    static native boolean sensors_enable_sensor(int queue, String name, int sensor, int enable);
+    static native int sensors_data_poll(int queue, float[] values, int[] status, long[] timestamp);
+}
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index ca8321f..3137947 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.input.KeyboardLayout;
 import android.hardware.input.IInputDevicesChangedListener;
+import android.os.IBinder;
 import android.view.InputDevice;
 import android.view.InputEvent;
 
@@ -46,4 +47,8 @@
 
     // Registers an input devices changed listener.
     void registerInputDevicesChangedListener(IInputDevicesChangedListener listener);
+
+    // Input device vibrator control.
+    void vibrate(int deviceId, in long[] pattern, int repeat, IBinder token);
+    void cancelVibrate(int deviceId, IBinder token);
 }
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 35c49a1..b39b823 100755
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -19,12 +19,14 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.content.Context;
+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.os.Vibrator;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.util.Log;
@@ -587,6 +589,15 @@
     }
 
     /**
+     * Gets a vibrator service associated with an input device, assuming it has one.
+     * @return The vibrator, never null.
+     * @hide
+     */
+    public Vibrator getInputDeviceVibrator(int deviceId) {
+        return new InputDeviceVibrator(deviceId);
+    }
+
+    /**
      * Listens for changes in input devices.
      */
     public interface InputDeviceListener {
@@ -645,4 +656,45 @@
             }
         }
     }
+
+    private final class InputDeviceVibrator extends Vibrator {
+        private final int mDeviceId;
+        private final Binder mToken;
+
+        public InputDeviceVibrator(int deviceId) {
+            mDeviceId = deviceId;
+            mToken = new Binder();
+        }
+
+        @Override
+        public boolean hasVibrator() {
+            return true;
+        }
+
+        @Override
+        public void vibrate(long milliseconds) {
+            vibrate(new long[] { 0, milliseconds}, -1);
+        }
+
+        @Override
+        public void vibrate(long[] pattern, int repeat) {
+            if (repeat >= pattern.length) {
+                throw new ArrayIndexOutOfBoundsException();
+            }
+            try {
+                mIm.vibrate(mDeviceId, pattern, repeat, mToken);
+            } catch (RemoteException ex) {
+                Log.w(TAG, "Failed to vibrate.", ex);
+            }
+        }
+
+        @Override
+        public void cancel() {
+            try {
+                mIm.cancelVibrate(mDeviceId, mToken);
+            } catch (RemoteException ex) {
+                Log.w(TAG, "Failed to cancel vibration.", ex);
+            }
+        }
+    }
 }
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index de16985..ef4209f 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -373,10 +373,11 @@
     }
 
     /**
-     * Gets you info about the current data network.
-     * Call {@link NetworkInfo#isConnected()} on the returned {@link NetworkInfo}
-     * to check if the device has a data connection.
-    */
+     * Returns details about the currently active 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 no networks are available.
+     */
     public NetworkInfo getActiveNetworkInfo() {
         try {
             return mService.getActiveNetworkInfo();
@@ -856,4 +857,19 @@
         } catch (RemoteException e) {}
         return false;
     }
+
+    /**
+     * Returns if the currently active data network is metered. A network is
+     * classified as metered when the user is sensitive to heavy data usage on
+     * that connection. You should check this before doing large data transfers,
+     * and warn the user or delay the operation until another network is
+     * available.
+     */
+    public boolean isActiveNetworkMetered() {
+        try {
+            return mService.isActiveNetworkMetered();
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
 }
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 7046008..92aeff2 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -51,6 +51,7 @@
     NetworkState[] getAllNetworkState();
 
     NetworkQuotaInfo getActiveNetworkQuotaInfo();
+    boolean isActiveNetworkMetered();
 
     boolean setRadios(boolean onOff);
 
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 89c9c36..3250ae7 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -32,6 +32,7 @@
     /** Control UID policies. */
     void setAppPolicy(int appId, int policy);
     int getAppPolicy(int appId);
+    int[] getAppsWithPolicy(int policy);
 
     boolean isUidForeground(int uid);
 
@@ -50,5 +51,6 @@
     boolean getRestrictBackground();
 
     NetworkQuotaInfo getNetworkQuotaInfo(in NetworkState state);
+    boolean isNetworkMetered(in NetworkState state);
 
 }
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index b4f6367..08d4c6c 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -32,6 +32,9 @@
 
     /** Return data layer snapshot of UID network usage. */
     NetworkStats getDataLayerSnapshotForUid(int uid);
+    /** Return set of any ifaces associated with mobile networks since boot. */
+    String[] getMobileIfaces();
+
     /** Increment data layer count of operations performed for UID and tag. */
     void incrementOperationCount(int uid, int tag, int operationCount);
 
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 2b36131..07bfd4b 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -92,6 +92,14 @@
         }
     }
 
+    public int[] getAppsWithPolicy(int policy) {
+        try {
+            return mService.getAppsWithPolicy(policy);
+        } catch (RemoteException e) {
+            return new int[0];
+        }
+    }
+
     public void registerListener(INetworkPolicyListener listener) {
         try {
             mService.registerListener(listener);
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index 50432a1..39a4d7b 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -48,6 +48,8 @@
     public static final int MATCH_MOBILE_4G = 3;
     public static final int MATCH_WIFI = 4;
     public static final int MATCH_ETHERNET = 5;
+    public static final int MATCH_MOBILE_WILDCARD = 6;
+    public static final int MATCH_WIFI_WILDCARD = 7;
 
     /**
      * Set of {@link NetworkInfo#getType()} that reflect data usage.
@@ -86,11 +88,19 @@
     }
 
     /**
+     * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks,
+     * regardless of IMSI.
+     */
+    public static NetworkTemplate buildTemplateMobileWildcard() {
+        return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null);
+    }
+
+    /**
      * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks,
      * regardless of SSID.
      */
     public static NetworkTemplate buildTemplateWifiWildcard() {
-        return new NetworkTemplate(MATCH_WIFI, null, null);
+        return new NetworkTemplate(MATCH_WIFI_WILDCARD, null, null);
     }
 
     @Deprecated
@@ -198,6 +208,10 @@
                 return matchesWifi(ident);
             case MATCH_ETHERNET:
                 return matchesEthernet(ident);
+            case MATCH_MOBILE_WILDCARD:
+                return matchesMobileWildcard(ident);
+            case MATCH_WIFI_WILDCARD:
+                return matchesWifiWildcard(ident);
             default:
                 throw new IllegalArgumentException("unknown network template");
         }
@@ -257,13 +271,7 @@
     private boolean matchesWifi(NetworkIdentity ident) {
         switch (ident.mType) {
             case TYPE_WIFI:
-                if (mNetworkId == null) {
-                    return true;
-                } else {
-                    return Objects.equal(mNetworkId, ident.mNetworkId);
-                }
-            case TYPE_WIFI_P2P:
-                return mNetworkId == null;
+                return Objects.equal(mNetworkId, ident.mNetworkId);
             default:
                 return false;
         }
@@ -279,6 +287,24 @@
         return false;
     }
 
+    private boolean matchesMobileWildcard(NetworkIdentity ident) {
+        if (ident.mType == TYPE_WIMAX) {
+            return true;
+        } else {
+            return contains(DATA_USAGE_NETWORK_TYPES, ident.mType);
+        }
+    }
+
+    private boolean matchesWifiWildcard(NetworkIdentity ident) {
+        switch (ident.mType) {
+            case TYPE_WIFI:
+            case TYPE_WIFI_P2P:
+                return true;
+            default:
+                return false;
+        }
+    }
+
     private static String getMatchRuleName(int matchRule) {
         switch (matchRule) {
             case MATCH_MOBILE_3G_LOWER:
@@ -291,6 +317,10 @@
                 return "WIFI";
             case MATCH_ETHERNET:
                 return "ETHERNET";
+            case MATCH_MOBILE_WILDCARD:
+                return "MOBILE_WILDCARD";
+            case MATCH_WIFI_WILDCARD:
+                return "WIFI_WILDCARD";
             default:
                 return "UNKNOWN";
         }
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index ee3e165..e437d2e 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -88,6 +88,16 @@
      */
     public static final int TAG_SYSTEM_BACKUP = 0xFFFFFF03;
 
+    private static INetworkStatsService sStatsService;
+
+    private synchronized static INetworkStatsService getStatsService() {
+        if (sStatsService == null) {
+            sStatsService = INetworkStatsService.Stub.asInterface(
+                    ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
+        }
+        return sStatsService;
+    }
+
     /**
      * Snapshot of {@link NetworkStats} when the currently active profiling
      * session started, or {@code null} if no session active.
@@ -228,11 +238,9 @@
      * @param operationCount Number of operations to increment count by.
      */
     public static void incrementOperationCount(int tag, int operationCount) {
-        final INetworkStatsService statsService = INetworkStatsService.Stub.asInterface(
-                ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
         final int uid = android.os.Process.myUid();
         try {
-            statsService.incrementOperationCount(uid, tag, operationCount);
+            getStatsService().incrementOperationCount(uid, tag, operationCount);
         } catch (RemoteException e) {
             throw new RuntimeException(e);
         }
@@ -257,7 +265,13 @@
      * @return number of packets.  If the statistics are not supported by this device,
      * {@link #UNSUPPORTED} will be returned.
      */
-    public static native long getMobileTxPackets();
+    public static long getMobileTxPackets() {
+        long total = 0;
+        for (String iface : getMobileIfaces()) {
+            total += getTxPackets(iface);
+        }
+        return total;
+    }
 
     /**
      * Get the total number of packets received through the mobile interface.
@@ -265,7 +279,13 @@
      * @return number of packets.  If the statistics are not supported by this device,
      * {@link #UNSUPPORTED} will be returned.
      */
-    public static native long getMobileRxPackets();
+    public static long getMobileRxPackets() {
+        long total = 0;
+        for (String iface : getMobileIfaces()) {
+            total += getRxPackets(iface);
+        }
+        return total;
+    }
 
     /**
      * Get the total number of bytes transmitted through the mobile interface.
@@ -273,7 +293,13 @@
      * @return number of bytes.  If the statistics are not supported by this device,
      * {@link #UNSUPPORTED} will be returned.
      */
-      public static native long getMobileTxBytes();
+    public static long getMobileTxBytes() {
+        long total = 0;
+        for (String iface : getMobileIfaces()) {
+            total += getTxBytes(iface);
+        }
+        return total;
+    }
 
     /**
      * Get the total number of bytes received through the mobile interface.
@@ -281,7 +307,13 @@
      * @return number of bytes.  If the statistics are not supported by this device,
      * {@link #UNSUPPORTED} will be returned.
      */
-    public static native long getMobileRxBytes();
+    public static long getMobileRxBytes() {
+        long total = 0;
+        for (String iface : getMobileIfaces()) {
+            total += getRxBytes(iface);
+        }
+        return total;
+    }
 
     /**
      * Get the total number of packets transmitted through the specified interface.
@@ -290,7 +322,9 @@
      * {@link #UNSUPPORTED} will be returned.
      * @hide
      */
-    public static native long getTxPackets(String iface);
+    public static long getTxPackets(String iface) {
+        return nativeGetIfaceStat(iface, TYPE_TX_PACKETS);
+    }
 
     /**
      * Get the total number of packets received through the specified interface.
@@ -299,7 +333,9 @@
      * {@link #UNSUPPORTED} will be returned.
      * @hide
      */
-    public static native long getRxPackets(String iface);
+    public static long getRxPackets(String iface) {
+        return nativeGetIfaceStat(iface, TYPE_RX_PACKETS);
+    }
 
     /**
      * Get the total number of bytes transmitted through the specified interface.
@@ -308,7 +344,9 @@
      * {@link #UNSUPPORTED} will be returned.
      * @hide
      */
-    public static native long getTxBytes(String iface);
+    public static long getTxBytes(String iface) {
+        return nativeGetIfaceStat(iface, TYPE_TX_BYTES);
+    }
 
     /**
      * Get the total number of bytes received through the specified interface.
@@ -317,8 +355,9 @@
      * {@link #UNSUPPORTED} will be returned.
      * @hide
      */
-    public static native long getRxBytes(String iface);
-
+    public static long getRxBytes(String iface) {
+        return nativeGetIfaceStat(iface, TYPE_RX_BYTES);
+    }
 
     /**
      * Get the total number of packets sent through all network interfaces.
@@ -326,7 +365,9 @@
      * @return the number of packets.  If the statistics are not supported by this device,
      * {@link #UNSUPPORTED} will be returned.
      */
-    public static native long getTotalTxPackets();
+    public static long getTotalTxPackets() {
+        return nativeGetTotalStat(TYPE_TX_PACKETS);
+    }
 
     /**
      * Get the total number of packets received through all network interfaces.
@@ -334,7 +375,9 @@
      * @return number of packets.  If the statistics are not supported by this device,
      * {@link #UNSUPPORTED} will be returned.
      */
-    public static native long getTotalRxPackets();
+    public static long getTotalRxPackets() {
+        return nativeGetTotalStat(TYPE_RX_PACKETS);
+    }
 
     /**
      * Get the total number of bytes sent through all network interfaces.
@@ -342,7 +385,9 @@
      * @return number of bytes.  If the statistics are not supported by this device,
      * {@link #UNSUPPORTED} will be returned.
      */
-    public static native long getTotalTxBytes();
+    public static long getTotalTxBytes() {
+        return nativeGetTotalStat(TYPE_TX_BYTES);
+    }
 
     /**
      * Get the total number of bytes received through all network interfaces.
@@ -350,7 +395,9 @@
      * @return number of bytes.  If the statistics are not supported by this device,
      * {@link #UNSUPPORTED} will be returned.
      */
-    public static native long getTotalRxBytes();
+    public static long getTotalRxBytes() {
+        return nativeGetTotalStat(TYPE_RX_BYTES);
+    }
 
     /**
      * Get the number of bytes sent through the network for this UID.
@@ -483,7 +530,6 @@
      */
     public static native long getUidTcpRxSegments(int uid);
 
-
     /**
      * Get the number of UDP packets sent for this UID.
      * Includes DNS requests.
@@ -515,13 +561,33 @@
      * special permission.
      */
     private static NetworkStats getDataLayerSnapshotForUid(Context context) {
-        final INetworkStatsService statsService = INetworkStatsService.Stub.asInterface(
-                ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
         final int uid = android.os.Process.myUid();
         try {
-            return statsService.getDataLayerSnapshotForUid(uid);
+            return getStatsService().getDataLayerSnapshotForUid(uid);
         } catch (RemoteException e) {
             throw new RuntimeException(e);
         }
     }
+
+    /**
+     * Return set of any ifaces associated with mobile networks since boot.
+     * Interfaces are never removed from this list, so counters should always be
+     * monotonic.
+     */
+    private static String[] getMobileIfaces() {
+        try {
+            return getStatsService().getMobileIfaces();
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    // NOTE: keep these in sync with android_net_TrafficStats.cpp
+    private static final int TYPE_RX_BYTES = 0;
+    private static final int TYPE_RX_PACKETS = 1;
+    private static final int TYPE_TX_BYTES = 2;
+    private static final int TYPE_TX_PACKETS = 3;
+
+    private static native long nativeGetTotalStat(int type);
+    private static native long nativeGetIfaceStat(String iface, int type);
 }
diff --git a/core/java/android/net/nsd/DnsSdServiceInfo.java b/core/java/android/net/nsd/DnsSdServiceInfo.java
index 33c3eb9..66abd3a 100644
--- a/core/java/android/net/nsd/DnsSdServiceInfo.java
+++ b/core/java/android/net/nsd/DnsSdServiceInfo.java
@@ -22,8 +22,8 @@
 import java.net.InetAddress;
 
 /**
- * Defines a service based on DNS service discovery
- * {@hide}
+ * A class representing service information for network service discovery
+ * {@see NsdManager}
  */
 public class DnsSdServiceInfo implements NetworkServiceInfo, Parcelable {
 
@@ -40,56 +40,63 @@
     public DnsSdServiceInfo() {
     }
 
+    /** @hide */
     public DnsSdServiceInfo(String sn, String rt, DnsSdTxtRecord tr) {
         mServiceName = sn;
         mServiceType = rt;
         mTxtRecord = tr;
     }
 
+    /** Get the service name */
     @Override
-    /** @hide */
     public String getServiceName() {
         return mServiceName;
     }
 
+    /** Set the service name */
     @Override
-    /** @hide */
     public void setServiceName(String s) {
         mServiceName = s;
     }
 
+    /** Get the service type */
     @Override
-    /** @hide */
     public String getServiceType() {
         return mServiceType;
     }
 
+    /** Set the service type */
     @Override
-    /** @hide */
     public void setServiceType(String s) {
         mServiceType = s;
     }
 
+    /** @hide */
     public DnsSdTxtRecord getTxtRecord() {
         return mTxtRecord;
     }
 
+    /** @hide */
     public void setTxtRecord(DnsSdTxtRecord t) {
         mTxtRecord = new DnsSdTxtRecord(t);
     }
 
+    /** Get the host address. The host address is valid for a resolved service. */
     public InetAddress getHost() {
         return mHost;
     }
 
+    /** Set the host address */
     public void setHost(InetAddress s) {
         mHost = s;
     }
 
+    /** Get port number. The port number is valid for a resolved service. */
     public int getPort() {
         return mPort;
     }
 
+    /** Set port number */
     public void setPort(int p) {
         mPort = p;
     }
@@ -147,5 +154,4 @@
                 return new DnsSdServiceInfo[size];
             }
         };
-
 }
diff --git a/core/java/android/net/nsd/DnsSdTxtRecord.java b/core/java/android/net/nsd/DnsSdTxtRecord.java
index 952e02f..ccb9a91 100644
--- a/core/java/android/net/nsd/DnsSdTxtRecord.java
+++ b/core/java/android/net/nsd/DnsSdTxtRecord.java
@@ -37,7 +37,6 @@
  * The DnsSdTxtRecord object stores the entire TXT data as a single byte array, traversing it
  * as need be to implement its various methods.
  *
- * @hide
  */
 public class DnsSdTxtRecord implements Parcelable {
     private static final byte mSeperator = '=';
diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java
index 505f11b..dac8d20 100644
--- a/core/java/android/net/nsd/NsdManager.java
+++ b/core/java/android/net/nsd/NsdManager.java
@@ -24,29 +24,110 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.Messenger;
+import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.Protocol;
 
 /**
- * The Network Service Discovery Manager class provides the API for service
- * discovery. Service discovery enables applications to discover and connect with services
- * on a network. Example applications include a game application discovering another instance
- * of the game application or a printer application discovering other printers on a network.
+ * The Network Service Discovery Manager class provides the API to discover services
+ * on a network. As an example, if device A and device B are connected over a Wi-Fi
+ * network, a game registered on device A can be discovered by a game on device
+ * B. Another example use case is an application discovering printers on the network.
+ *
+ * <p> The API currently supports DNS based service discovery and discovery is currently
+ * limited to a local network over Multicast DNS. In future, it will be extended to
+ * support wide area discovery and other service discovery mechanisms.
+ * DNS service discovery is described at http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt
  *
  * <p> The API is asynchronous and responses to requests from an application are on listener
- * callbacks provided by the application. The application needs to do an initialization with
- * {@link #initialize} before doing any operation.
+ * callbacks provided by the application. The application must invoke {@link #initialize} before
+ * doing any other operation.
  *
- * <p> Android currently supports DNS based service discovery and it is limited to a local
- * network with the use of multicast DNS. In future, this class will be
- * extended to support other service discovery mechanisms.
+ * <p> There are three main operations the API supports - registration, discovery and resolution.
+ * <pre>
+ *                          Application start
+ *                                 |
+ *                                 |         <----------------------------------------------
+ *                             initialize()                                                 |
+ *                                 |                                                        |
+ *                                 | Wait until channel connects                            |
+ *                                 | before doing any operation                             |
+ *                                 |                                                        |
+ *                           onChannelConnected()                    __________             |
+ *                                 |                                           |            |
+ *                                 |                                           |            |
+ *                                 |                  onServiceRegistered()    |            |
+ *                     Register any local services  /                          |            |
+ *                      to be advertised with       \                          |            | If application needs to
+ *                       registerService()            onFailure()              |            | do any further operations
+ *                                 |                                           |            | again, it needs to
+ *                                 |                                           |            | initialize() connection
+ *                          discoverServices()                                 |            | to framework again
+ *                                 |                                           |            |
+ *                      Maintain a list to track                               |            |
+ *                        discovered services                                  |            |
+ *                                 |                                           |            |
+ *                                 |--------->                                 |-> onChannelDisconnected()
+ *                                 |          |                                |
+ *                                 |      onServiceFound()                     |
+ *                                 |          |                                |
+ *                                 |     add service to list                   |
+ *                                 |          |                                |
+ *                                 |<----------                                |
+ *                                 |                                           |
+ *                                 |--------->                                 |
+ *                                 |          |                                |
+ *                                 |      onServiceLost()                      |
+ *                                 |          |                                |
+ *                                 |   remove service from list                |
+ *                                 |          |                                |
+ *                                 |<----------                                |
+ *                                 |                                           |
+ *                                 |                                           |
+ *                                 | Connect to a service                      |
+ *                                 | from list ?                               |
+ *                                 |                                           |
+ *                          resolveService()                                   |
+ *                                 |                                           |
+ *                         onServiceResolved()                                 |
+ *                                 |                                           |
+ *                     Establish connection to service                         |
+ *                     with the host and port information                      |
+ *                                 |                                           |
+ *                                 |                                ___________|
+ *                           deinitialize()
+ *                    when done with all operations
+ *                          or before quit
+ *
+ * </pre>
+ * An application that needs to advertise itself over a network for other applications to
+ * discover it can do so with a call to {@link #registerService}. If Example is a http based
+ * application that can provide HTML data to peer services, it can register a name "Example"
+ * with service type "_http._tcp". A successful registration is notified with a callback to
+ * {@link DnsSdRegisterListener#onServiceRegistered} and a failure to register is notified
+ * over {@link DnsSdRegisterListener#onFailure}
+ *
+ * <p> A peer application looking for http services can initiate a discovery for "_http._tcp"
+ * with a call to {@link #discoverServices}. A service found is notified with a callback
+ * to {@link DnsSdDiscoveryListener#onServiceFound} and a service lost is notified on
+ * {@link DnsSdDiscoveryListener#onServiceLost}.
+ *
+ * <p> Once the peer application discovers the "Example" http srevice, and needs to receive data
+ * from the "Example" application, it can initiate a resolve with {@link #resolveService} to
+ * resolve the host and port details for the purpose of establishing a connection. A successful
+ * resolve is notified on {@link DnsSdResolveListener#onServiceResolved} and a failure is notified
+ * on {@link DnsSdResolveListener#onFailure}.
+ *
+ * Applications can reserve for a service type at
+ * http://www.iana.org/form/ports-service. Existing services can be found at
+ * http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml
  *
  * Get an instance of this class by calling {@link android.content.Context#getSystemService(String)
  * Context.getSystemService(Context.NSD_SERVICE)}.
- * @hide
  *
+ * {@see DnsSdServiceInfo}
  */
 public class NsdManager {
     private static final String TAG = "NsdManager";
@@ -80,27 +161,32 @@
     public static final int REGISTER_SERVICE_SUCCEEDED              = BASE + 11;
 
     /** @hide */
-    public static final int UPDATE_SERVICE                          = BASE + 12;
+    public static final int UNREGISTER_SERVICE                      = BASE + 12;
     /** @hide */
-    public static final int UPDATE_SERVICE_FAILED                   = BASE + 13;
+    public static final int UNREGISTER_SERVICE_FAILED               = BASE + 13;
     /** @hide */
-    public static final int UPDATE_SERVICE_SUCCEEDED                = BASE + 14;
+    public static final int UNREGISTER_SERVICE_SUCCEEDED            = BASE + 14;
 
     /** @hide */
-    public static final int RESOLVE_SERVICE                         = BASE + 15;
+    public static final int UPDATE_SERVICE                          = BASE + 15;
     /** @hide */
-    public static final int RESOLVE_SERVICE_FAILED                  = BASE + 16;
+    public static final int UPDATE_SERVICE_FAILED                   = BASE + 16;
     /** @hide */
-    public static final int RESOLVE_SERVICE_SUCCEEDED               = BASE + 17;
+    public static final int UPDATE_SERVICE_SUCCEEDED                = BASE + 17;
 
     /** @hide */
-    public static final int STOP_RESOLVE                            = BASE + 18;
+    public static final int RESOLVE_SERVICE                         = BASE + 18;
     /** @hide */
-    public static final int STOP_RESOLVE_FAILED                     = BASE + 19;
+    public static final int RESOLVE_SERVICE_FAILED                  = BASE + 19;
     /** @hide */
-    public static final int STOP_RESOLVE_SUCCEEDED                  = BASE + 20;
+    public static final int RESOLVE_SERVICE_SUCCEEDED               = BASE + 20;
 
-
+    /** @hide */
+    public static final int STOP_RESOLVE                            = BASE + 21;
+    /** @hide */
+    public static final int STOP_RESOLVE_FAILED                     = BASE + 22;
+    /** @hide */
+    public static final int STOP_RESOLVE_SUCCEEDED                  = BASE + 23;
 
     /**
      * Create a new Nsd instance. Applications use
@@ -115,36 +201,44 @@
     }
 
     /**
+     * Passed with onFailure() calls.
      * Indicates that the operation failed due to an internal error.
      */
     public static final int ERROR               = 0;
 
     /**
-     * Indicates that the operation failed because service discovery is unsupported on the device.
+     * Passed with onFailure() calls.
+     * Indicates that the operation failed because service discovery
+     * is unsupported on the device.
      */
     public static final int UNSUPPORTED         = 1;
 
     /**
-     * Indicates that the operation failed because the framework is busy and
-     * unable to service the request.
+     * Passed with onFailure() calls.
+     * Indicates that the operation failed because the framework is
+     * busy and unable to service the request.
      */
     public static final int BUSY                = 2;
 
     /**
+     * Passed with onFailure() calls.
      * Indicates that the operation failed because it is already active.
      */
     public static final int ALREADY_ACTIVE      = 3;
 
     /**
+     * Passed with onFailure() calls.
      * Indicates that the operation failed because maximum limit on
      * service registrations has reached.
      */
     public static final int MAX_REGS_REACHED    = 4;
 
-
-
     /** Interface for callback invocation when framework channel is connected or lost */
     public interface ChannelListener {
+       /**
+         * The channel to the framework is connected.
+         * Application can initiate calls into the framework using the channel instance passed.
+         */
         public void onChannelConnected(Channel c);
         /**
          * The channel to the framework has been disconnected.
@@ -153,6 +247,7 @@
         public void onChannelDisconnected();
     }
 
+    /** Generic interface for callback invocation for a success or failure */
     public interface ActionListener {
 
         public void onFailure(int errorCode);
@@ -160,11 +255,12 @@
         public void onSuccess();
     }
 
+    /** Interface for callback invocation for service discovery */
     public interface DnsSdDiscoveryListener {
 
         public void onFailure(int errorCode);
 
-        public void onStarted(String registrationType);
+        public void onStarted(String serviceType);
 
         public void onServiceFound(DnsSdServiceInfo serviceInfo);
 
@@ -172,6 +268,7 @@
 
     }
 
+    /** Interface for callback invocation for service registration */
     public interface DnsSdRegisterListener {
 
         public void onFailure(int errorCode);
@@ -179,6 +276,7 @@
         public void onServiceRegistered(int registeredId, DnsSdServiceInfo serviceInfo);
     }
 
+    /** @hide */
     public interface DnsSdUpdateRegistrationListener {
 
         public void onFailure(int errorCode);
@@ -186,6 +284,7 @@
         public void onServiceUpdated(int registeredId, DnsSdTxtRecord txtRecord);
     }
 
+    /** Interface for callback invocation for service resolution */
     public interface DnsSdResolveListener {
 
         public void onFailure(int errorCode);
@@ -208,6 +307,7 @@
         private DnsSdDiscoveryListener mDnsSdDiscoveryListener;
         private ActionListener mDnsSdStopDiscoveryListener;
         private DnsSdRegisterListener mDnsSdRegisterListener;
+        private ActionListener mDnsSdUnregisterListener;
         private DnsSdUpdateRegistrationListener mDnsSdUpdateListener;
         private DnsSdResolveListener mDnsSdResolveListener;
         private ActionListener mDnsSdStopResolveListener;
@@ -279,7 +379,17 @@
                                     (DnsSdServiceInfo) message.obj);
                         }
                         break;
-                    case UPDATE_SERVICE_FAILED:
+                    case UNREGISTER_SERVICE_FAILED:
+                        if (mDnsSdUnregisterListener != null) {
+                            mDnsSdUnregisterListener.onFailure(message.arg1);
+                        }
+                        break;
+                    case UNREGISTER_SERVICE_SUCCEEDED:
+                        if (mDnsSdUnregisterListener != null) {
+                            mDnsSdUnregisterListener.onSuccess();
+                        }
+                        break;
+                   case UPDATE_SERVICE_FAILED:
                         if (mDnsSdUpdateListener != null) {
                             mDnsSdUpdateListener.onFailure(message.arg1);
                         }
@@ -319,6 +429,10 @@
         }
    }
 
+    private static void checkChannel(Channel c) {
+        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
+    }
+
     /**
      * Registers the application with the service discovery framework. This function
      * must be the first to be called before any other operations are performed. No service
@@ -327,7 +441,7 @@
      *
      * @param srcContext is the context of the source
      * @param srcLooper is the Looper on which the callbacks are receivied
-     * @param listener for callback at loss of framework communication.
+     * @param listener for callback at loss of framework communication. Cannot be null.
      */
     public void initialize(Context srcContext, Looper srcLooper, ChannelListener listener) {
         Messenger messenger = getMessenger();
@@ -339,88 +453,142 @@
     }
 
     /**
-     * Set the listener for service discovery. Can be null.
+     * Disconnects application from service discovery framework. No further operations
+     * will succeed until a {@link #initialize} is called again.
+     *
+     * @param c channel initialized with {@link #initialize}
      */
-    public void setDiscoveryListener(Channel c, DnsSdDiscoveryListener b) {
-        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
-        c.mDnsSdDiscoveryListener = b;
+    public void deinitialize(Channel c) {
+        checkChannel(c);
+        c.mAsyncChannel.disconnect();
     }
 
     /**
-     * Set the listener for stop service discovery. Can be null.
+     * Register a service to be discovered by other services.
+     *
+     * <p> The function call immediately returns after sending a request to register service
+     * to the framework. The application is notified of a success to initiate
+     * discovery through the callback {@link DnsSdRegisterListener#onServiceRegistered} or a failure
+     * through {@link DnsSdRegisterListener#onFailure}.
+     *
+     * @param c is the channel created at {@link #initialize}
+     * @param serviceType The service type being advertised.
+     * @param port on which the service is listenering for incoming connections
+     * @param listener for success or failure callback. Can be null.
      */
-    public void setStopDiscoveryListener(Channel c, ActionListener a) {
-        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
-        c.mDnsSdStopDiscoveryListener = a;
-    }
-
-    /**
-     * Set the listener for service registration. Can be null.
-     */
-    public void setRegisterListener(Channel c, DnsSdRegisterListener b) {
-        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
-        c.mDnsSdRegisterListener = b;
-    }
-
-    /**
-     * Set the listener for service registration. Can be null.
-     */
-    public void setUpdateRegistrationListener(Channel c, DnsSdUpdateRegistrationListener b) {
-        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
-        c.mDnsSdUpdateListener = b;
-    }
-
-    /**
-     * Set the listener for service resolution. Can be null.
-     */
-    public void setResolveListener(Channel c, DnsSdResolveListener b) {
-        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
-        c.mDnsSdResolveListener = b;
-    }
-
-    /**
-     * Set the listener for stopping service resolution. Can be null.
-     */
-    public void setStopResolveListener(Channel c, ActionListener b) {
-        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
-        c.mDnsSdStopResolveListener = b;
-    }
-
-    public void registerService(Channel c, DnsSdServiceInfo serviceInfo) {
-        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
-        if (serviceInfo == null) throw new IllegalArgumentException("Null serviceInfo");
+    public void registerService(Channel c, String serviceName, String serviceType, int port,
+            DnsSdRegisterListener listener) {
+        checkChannel(c);
+        if (TextUtils.isEmpty(serviceName) || TextUtils.isEmpty(serviceType)) {
+            throw new IllegalArgumentException("Service name or type cannot be empty");
+        }
+        if (port <= 0) {
+            throw new IllegalArgumentException("Invalid port number");
+        }
+        DnsSdServiceInfo serviceInfo = new DnsSdServiceInfo(serviceName, serviceType, null);
+        serviceInfo.setPort(port);
+        c.mDnsSdRegisterListener = listener;
         c.mAsyncChannel.sendMessage(REGISTER_SERVICE, serviceInfo);
     }
 
+    /**
+     * Unregister a service registered through {@link #registerService}
+     * @param c is the channel created at {@link #initialize}
+     * @param registeredId is obtained at {@link DnsSdRegisterListener#onServiceRegistered}
+     * @param listener provides callbacks for success or failure. Can be null.
+     */
+    public void unregisterService(Channel c, int registeredId, ActionListener listener) {
+        checkChannel(c);
+        c.mDnsSdUnregisterListener = listener;
+        c.mAsyncChannel.sendMessage(UNREGISTER_SERVICE, registeredId);
+    }
+
+    /** @hide */
     public void updateService(Channel c, int registeredId, DnsSdTxtRecord txtRecord) {
-        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
+        checkChannel(c);
         c.mAsyncChannel.sendMessage(UPDATE_SERVICE, registeredId, 0, txtRecord);
     }
 
-    public void discoverServices(Channel c, String serviceType) {
-        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
-        if (c.mDnsSdDiscoveryListener == null) throw new
-                IllegalStateException("Discovery listener needs to be set first");
+    /**
+     * Initiate service discovery to browse for instances of a service type. Service discovery
+     * consumes network bandwidth and will continue until the application calls
+     * {@link #stopServiceDiscovery}.
+     *
+     * <p> The function call immediately returns after sending a request to start service
+     * discovery to the framework. The application is notified of a success to initiate
+     * discovery through the callback {@link DnsSdDiscoveryListener#onStarted} or a failure
+     * through {@link DnsSdDiscoveryListener#onFailure}.
+     *
+     * <p> Upon successful start, application is notified when a service is found with
+     * {@link DnsSdDiscoveryListener#onServiceFound} or when a service is lost with
+     * {@link DnsSdDiscoveryListener#onServiceLost}.
+     *
+     * <p> Upon failure to start, service discovery is not active and application does
+     * not need to invoke {@link #stopServiceDiscovery}
+     *
+     * @param c is the channel created at {@link #initialize}
+     * @param serviceType The service type being discovered. Examples include "_http._tcp" for
+     * http services or "_ipp._tcp" for printers
+     * @param listener provides callbacks when service is found or lost. Cannot be null.
+     */
+    public void discoverServices(Channel c, String serviceType, DnsSdDiscoveryListener listener) {
+        checkChannel(c);
+        if (listener == null) {
+            throw new IllegalStateException("Discovery listener needs to be set first");
+        }
+        if (TextUtils.isEmpty(serviceType)) {
+            throw new IllegalStateException("Service type cannot be empty");
+        }
         DnsSdServiceInfo s = new DnsSdServiceInfo();
         s.setServiceType(serviceType);
+        c.mDnsSdDiscoveryListener = listener;
         c.mAsyncChannel.sendMessage(DISCOVER_SERVICES, s);
     }
 
-    public void stopServiceDiscovery(Channel c) {
-        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
+    /**
+     * Stop service discovery initiated with {@link #discoverServices}. An active service
+     * discovery is notified to the application with {@link DnsSdDiscoveryListener#onStarted}
+     * and it stays active until the application invokes a stop service discovery.
+     *
+     * <p> Upon failure to start service discovery notified through
+     * {@link DnsSdDiscoveryListener#onFailure} service discovery is not active and
+     * application does not need to stop it.
+     *
+     * @param c is the channel created at {@link #initialize}
+     * @param listener notifies success or failure. Can be null.
+     */
+    public void stopServiceDiscovery(Channel c, ActionListener listener) {
+        checkChannel(c);
+        c.mDnsSdStopDiscoveryListener = listener;
         c.mAsyncChannel.sendMessage(STOP_DISCOVERY);
     }
 
-    public void resolveService(Channel c, DnsSdServiceInfo serviceInfo) {
-        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
-        if (serviceInfo == null) throw new IllegalArgumentException("Null serviceInfo");
-        if (c.mDnsSdResolveListener == null) throw new
-                IllegalStateException("Resolve listener needs to be set first");
+    /**
+     * Resolve a discovered service. An application can resolve a service right before
+     * establishing a connection to fetch the IP and port details on which to setup
+     * the connection.
+     *
+     * @param c is the channel created at {@link #initialize}
+     * @param serviceName of the the service
+     * @param serviceType of the service
+     * @param listener to receive callback upon success or failure. Cannot be null.
+     */
+    public void resolveService(Channel c, String serviceName, String serviceType,
+            DnsSdResolveListener listener) {
+        checkChannel(c);
+        if (TextUtils.isEmpty(serviceName) || TextUtils.isEmpty(serviceType)) {
+            throw new IllegalArgumentException("Service name or type cannot be empty");
+        }
+        if (listener == null) throw new
+                IllegalStateException("Resolve listener cannot be null");
+        c.mDnsSdResolveListener = listener;
+        DnsSdServiceInfo serviceInfo = new DnsSdServiceInfo(serviceName, serviceType, null);
         c.mAsyncChannel.sendMessage(RESOLVE_SERVICE, serviceInfo);
     }
 
+    /** @hide */
     public void stopServiceResolve(Channel c) {
-        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
+        checkChannel(c);
         if (c.mDnsSdResolveListener == null) throw new
                 IllegalStateException("Resolve listener needs to be set first");
         c.mAsyncChannel.sendMessage(STOP_RESOLVE);
diff --git a/core/java/android/nfc/INdefPushCallback.aidl b/core/java/android/nfc/INdefPushCallback.aidl
index 4e79822..1c6d5d0 100644
--- a/core/java/android/nfc/INdefPushCallback.aidl
+++ b/core/java/android/nfc/INdefPushCallback.aidl
@@ -25,7 +25,6 @@
 interface INdefPushCallback
 {
     NdefMessage createMessage();
-    Uri getUri();
-    String getMimeType();
+    Uri[] getUris();
     void onNdefPushComplete();
 }
diff --git a/core/java/android/nfc/NfcActivityManager.java b/core/java/android/nfc/NfcActivityManager.java
index f80dae4..7ffa575 100644
--- a/core/java/android/nfc/NfcActivityManager.java
+++ b/core/java/android/nfc/NfcActivityManager.java
@@ -108,8 +108,8 @@
         NdefMessage ndefMessage = null;  // static NDEF message
         NfcAdapter.CreateNdefMessageCallback ndefMessageCallback = null;
         NfcAdapter.OnNdefPushCompleteCallback onNdefPushCompleteCallback = null;
-        Uri uri = null;
-        String mimeType = null;
+        NfcAdapter.CreateBeamUrisCallback uriCallback = null;
+        Uri[] uris = null;
         public NfcActivityState(Activity activity) {
             if (activity.getWindow().isDestroyed()) {
                 throw new IllegalStateException("activity is already destroyed");
@@ -128,14 +128,19 @@
             ndefMessage = null;
             ndefMessageCallback = null;
             onNdefPushCompleteCallback = null;
-            uri = null;
-            mimeType = null;
+            uriCallback = null;
+            uris = null;
         }
         @Override
         public String toString() {
             StringBuilder s = new StringBuilder("[").append(" ");
             s.append(ndefMessage).append(" ").append(ndefMessageCallback).append(" ");
-            s.append(onNdefPushCompleteCallback).append(" ").append(uri).append("]");
+            s.append(uriCallback).append(" ");
+            if (uris != null) {
+                for (Uri uri : uris) {
+                    s.append(onNdefPushCompleteCallback).append(" ").append(uri).append("]");
+                }
+            }
             return s.toString();
         }
     }
@@ -184,12 +189,25 @@
         mDefaultEvent = new NfcEvent(mAdapter);
     }
 
-    public void setNdefPushContentUri(Activity activity, String mimeType, Uri uri) {
+    public void setNdefPushContentUri(Activity activity, Uri[] uris) {
         boolean isResumed;
         synchronized (NfcActivityManager.this) {
             NfcActivityState state = getActivityState(activity);
-            state.uri = uri;
-            state.mimeType = mimeType;
+            state.uris = uris;
+            isResumed = state.resumed;
+        }
+        if (isResumed) {
+            requestNfcServiceCallback(true);
+        }
+    }
+
+
+    public void setNdefPushContentUriCallback(Activity activity,
+            NfcAdapter.CreateBeamUrisCallback callback) {
+        boolean isResumed;
+        synchronized (NfcActivityManager.this) {
+            NfcActivityState state = getActivityState(activity);
+            state.uriCallback = callback;
             isResumed = state.resumed;
         }
         if (isResumed) {
@@ -271,24 +289,22 @@
 
     /** Callback from NFC service, usually on binder thread */
     @Override
-    public Uri getUri() {
+    public Uri[] getUris() {
+        Uri[] uris;
+        NfcAdapter.CreateBeamUrisCallback callback;
         synchronized (NfcActivityManager.this) {
             NfcActivityState state = findResumedActivityState();
             if (state == null) return null;
-
-            return state.uri;
+            uris = state.uris;
+            callback = state.uriCallback;
+        }
+        if (callback != null) {
+            return callback.createBeamUris(mDefaultEvent);
+        } else {
+            return uris;
         }
     }
-    /** Callback from NFC service, usually on binder thread */
-    @Override
-    public String getMimeType() {
-        synchronized (NfcActivityManager.this) {
-            NfcActivityState state = findResumedActivityState();
-            if (state == null) return null;
 
-            return state.mimeType;
-        }
-    }
     /** Callback from NFC service, usually on binder thread */
     @Override
     public void onNdefPushComplete() {
@@ -358,4 +374,5 @@
             }
         }
     }
+
 }
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 917751c..90f5bef 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -203,6 +203,27 @@
     /** @hide */
     public static final int STATE_TURNING_OFF = 4;
 
+    /** @hide */
+    public static final String ACTION_HANDOVER_TRANSFER_STARTED =
+            "android.nfc.action.HANDOVER_TRANSFER_STARTED";
+
+    /** @hide */
+    public static final String ACTION_HANDOVER_TRANSFER_DONE =
+            "android.nfc.action.HANDOVER_TRANSFER_DONE";
+
+    /** @hide */
+    public static final String EXTRA_HANDOVER_TRANSFER_STATUS =
+            "android.nfc.extra.HANDOVER_TRANSFER_STATUS";
+
+    /** @hide */
+    public static final int HANDOVER_TRANSFER_STATUS_SUCCESS = 0;
+    /** @hide */
+    public static final int HANDOVER_TRANSFER_STATUS_FAILURE = 1;
+
+    /** @hide */
+    public static final String EXTRA_HANDOVER_TRANSFER_URI =
+            "android.nfc.extra.HANDOVER_TRANSFER_URI";
+
     // Guarded by NfcAdapter.class
     static boolean sIsInitialized = false;
 
@@ -281,6 +302,12 @@
         public NdefMessage createNdefMessage(NfcEvent event);
     }
 
+
+    // TODO javadoc
+    public interface CreateBeamUrisCallback {
+        public Uri[] createBeamUris(NfcEvent event);
+    }
+
     /**
      * Helper to check if this device has FEATURE_NFC, but without using
      * a context.
@@ -556,16 +583,22 @@
         }
     }
 
-    //TODO: Consider a callback alternative
-    //TOOD: See if we get rid of mimeType
     //TODO: make sure NFC service has permission for URI
+    //TODO: see if we will eventually support multiple URIs
     //TODO: javadoc
-    /** @hide */
-    public void setBeamPushUri(String mimeType, Uri uri, Activity activity) {
+    public void setBeamPushUris(Uri[] uris, Activity activity) {
         if (activity == null) {
             throw new NullPointerException("activity cannot be null");
         }
-        mNfcActivityManager.setNdefPushContentUri(activity, mimeType, uri);
+        mNfcActivityManager.setNdefPushContentUri(activity, uris);
+    }
+
+    // TODO javadoc
+    public void setBeamPushUrisCallback(CreateBeamUrisCallback callback, Activity activity) {
+        if (activity == null) {
+            throw new NullPointerException("activity cannot be null");
+        }
+        mNfcActivityManager.setNdefPushContentUriCallback(activity, callback);
     }
 
     /**
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 20a731e..98fe06a 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -1324,4 +1324,42 @@
             return false;
         }
     }
+
+    /**
+     * Return a String describing the calling method and location at a particular stack depth.
+     * @param callStack the Thread stack 
+     * @param depth the depth of stack to return information for.
+     * @return the String describing the caller at that depth.
+     */
+    private static String getCaller(StackTraceElement callStack[], int depth) {
+        // callStack[4] is the caller of the method that called getCallers()
+        if (4 + depth >= callStack.length) {
+            return "<bottom of call stack>";
+        }
+        StackTraceElement caller = callStack[4 + depth];
+        return caller.getClassName() + "." + caller.getMethodName() + ":" + caller.getLineNumber();
+    }
+
+    /**
+     * Return a string consisting of methods and locations at multiple call stack levels.
+     * @param depth the number of levels to return, starting with the immediate caller.
+     * @return a string describing the call stack.
+     * {@hide}
+     */
+    public static String getCallers(final int depth) {
+        final StackTraceElement[] callStack = Thread.currentThread().getStackTrace();
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0; i < depth; i++) {
+            sb.append(getCaller(callStack, i)).append(" ");
+        }
+        return sb.toString();
+    }
+
+    /**
+     * @return a String describing the immediate caller of the calling function.
+     * {@hide}
+     */
+    public static String getCaller() {
+        return getCaller(Thread.currentThread().getStackTrace(), 0);
+    }
 }
diff --git a/core/java/android/os/NullVibrator.java b/core/java/android/os/NullVibrator.java
new file mode 100644
index 0000000..8de4e06
--- /dev/null
+++ b/core/java/android/os/NullVibrator.java
@@ -0,0 +1,55 @@
+/*
+ * 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.os;
+
+import android.util.Log;
+
+/**
+ * Vibrator implementation that does nothing.
+ *
+ * @hide
+ */
+public class NullVibrator extends Vibrator {
+    private static final NullVibrator sInstance = new NullVibrator();
+
+    private NullVibrator() {
+    }
+
+    public static NullVibrator getInstance() {
+        return sInstance;
+    }
+
+    @Override
+    public boolean hasVibrator() {
+        return false;
+    }
+
+    @Override
+    public void vibrate(long milliseconds) {
+    }
+
+    @Override
+    public void vibrate(long[] pattern, int repeat) {
+        if (repeat >= pattern.length) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+    }
+
+    @Override
+    public void cancel() {
+    }
+}
diff --git a/core/java/android/os/SystemVibrator.java b/core/java/android/os/SystemVibrator.java
new file mode 100644
index 0000000..7c5a47e
--- /dev/null
+++ b/core/java/android/os/SystemVibrator.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 android.os;
+
+import android.util.Log;
+
+/**
+ * Vibrator implementation that controls the main system vibrator.
+ *
+ * @hide
+ */
+public class SystemVibrator extends Vibrator {
+    private static final String TAG = "Vibrator";
+
+    private final IVibratorService mService;
+    private final Binder mToken = new Binder();
+
+    public SystemVibrator() {
+        mService = IVibratorService.Stub.asInterface(
+                ServiceManager.getService("vibrator"));
+    }
+
+    @Override
+    public boolean hasVibrator() {
+        if (mService == null) {
+            Log.w(TAG, "Failed to vibrate; no vibrator service.");
+            return false;
+        }
+        try {
+            return mService.hasVibrator();
+        } catch (RemoteException e) {
+        }
+        return false;
+    }
+
+    @Override
+    public void vibrate(long milliseconds) {
+        if (mService == null) {
+            Log.w(TAG, "Failed to vibrate; no vibrator service.");
+            return;
+        }
+        try {
+            mService.vibrate(milliseconds, mToken);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to vibrate.", e);
+        }
+    }
+
+    @Override
+    public void vibrate(long[] pattern, int repeat) {
+        if (mService == null) {
+            Log.w(TAG, "Failed to vibrate; no vibrator service.");
+            return;
+        }
+        // catch this here because the server will do nothing.  pattern may
+        // not be null, let that be checked, because the server will drop it
+        // anyway
+        if (repeat < pattern.length) {
+            try {
+                mService.vibratePattern(pattern, repeat, mToken);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed to vibrate.", e);
+            }
+        } else {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+    }
+
+    @Override
+    public void cancel() {
+        if (mService == null) {
+            return;
+        }
+        try {
+            mService.cancelVibrate(mToken);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to cancel vibration.", e);
+        }
+    }
+}
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index af94a37..4645fab 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -33,6 +33,7 @@
     public static final long TRACE_TAG_GRAPHICS = 1L << 1;
     public static final long TRACE_TAG_INPUT = 1L << 2;
     public static final long TRACE_TAG_VIEW = 1L << 3;
+    public static final long TRACE_TAG_WEBVIEW = 1L << 4;
 
     private static final long sEnabledTags = nativeGetEnabledTags();
 
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index 3769cfe..3f783c9 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -16,61 +16,37 @@
 
 package android.os;
 
-import android.util.Log;
+import android.content.Context;
 
 /**
  * Class that operates the vibrator on the device.
  * <p>
  * If your process exits, any vibration you started with will stop.
  * </p>
+ *
+ * To obtain an instance of the system vibrator, call
+ * {@link Context#getSystemService} with {@link Context#VIBRATOR_SERVICE} as argument.
  */
-public class Vibrator
-{
-    private static final String TAG = "Vibrator";
-
-    IVibratorService mService;
-    private final Binder mToken = new Binder();
-
-    /** @hide */
-    public Vibrator()
-    {
-        mService = IVibratorService.Stub.asInterface(
-                ServiceManager.getService("vibrator"));
+public abstract class Vibrator {
+    /**
+     * @hide to prevent subclassing from outside of the framework
+     */
+    public Vibrator() {
     }
 
     /**
-     * Check whether the hardware has a vibrator.  Returns true if a vibrator
-     * exists, else false.
+     * Check whether the hardware has a vibrator.
+     *
+     * @return True if the hardware has a vibrator, else false.
      */
-    public boolean hasVibrator() {
-        if (mService == null) {
-            Log.w(TAG, "Failed to vibrate; no vibrator service.");
-            return false;
-        }
-        try {
-            return mService.hasVibrator();
-        } catch (RemoteException e) {
-        }
-        return false;
-    }
+    public abstract boolean hasVibrator();
     
     /**
-     * Turn the vibrator on.
+     * Vibrate constantly for the specified period of time.
      *
      * @param milliseconds The number of milliseconds to vibrate.
      */
-    public void vibrate(long milliseconds)
-    {
-        if (mService == null) {
-            Log.w(TAG, "Failed to vibrate; no vibrator service.");
-            return;
-        }
-        try {
-            mService.vibrate(milliseconds, mToken);
-        } catch (RemoteException e) {
-            Log.w(TAG, "Failed to vibrate.", e);
-        }
-    }
+    public abstract void vibrate(long milliseconds);
 
     /**
      * Vibrate with a given pattern.
@@ -90,38 +66,10 @@
      * @param repeat the index into pattern at which to repeat, or -1 if
      *        you don't want to repeat.
      */
-    public void vibrate(long[] pattern, int repeat)
-    {
-        if (mService == null) {
-            Log.w(TAG, "Failed to vibrate; no vibrator service.");
-            return;
-        }
-        // catch this here because the server will do nothing.  pattern may
-        // not be null, let that be checked, because the server will drop it
-        // anyway
-        if (repeat < pattern.length) {
-            try {
-                mService.vibratePattern(pattern, repeat, mToken);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Failed to vibrate.", e);
-            }
-        } else {
-            throw new ArrayIndexOutOfBoundsException();
-        }
-    }
+    public abstract void vibrate(long[] pattern, int repeat);
 
     /**
      * Turn the vibrator off.
      */
-    public void cancel()
-    {
-        if (mService == null) {
-            return;
-        }
-        try {
-            mService.cancelVibrate(mToken);
-        } catch (RemoteException e) {
-            Log.w(TAG, "Failed to cancel vibration.", e);
-        }
-    }
+    public abstract void cancel();
 }
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index 83799c4..c4aa691 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -756,6 +756,22 @@
         public static final int ATTENDEE_STATUS_DECLINED = 2;
         public static final int ATTENDEE_STATUS_INVITED = 3;
         public static final int ATTENDEE_STATUS_TENTATIVE = 4;
+
+        /**
+         * The identity of the attendee as referenced in
+         * {@link ContactsContract.CommonDataKinds.Identity#IDENTITY}.
+         * This is required only if {@link #ATTENDEE_ID_NAMESPACE} is present. Column name.
+         * <P>Type: STRING</P>
+         */
+        public static final String ATTENDEE_IDENTITY = "attendeeIdentity";
+
+        /**
+         * The identity name space of the attendee as referenced in
+         * {@link ContactsContract.CommonDataKinds.Identity#NAMESPACE}.
+         * This is required only if {@link #ATTENDEE_IDENTITY} is present. Column name.
+         * <P>Type: STRING</P>
+         */
+        public static final String ATTENDEE_ID_NAMESPACE = "attendeeIdNamespace";
     }
 
     /**
@@ -773,6 +789,8 @@
      * <li>{@link #ATTENDEE_RELATIONSHIP}</li>
      * <li>{@link #ATTENDEE_TYPE}</li>
      * <li>{@link #ATTENDEE_STATUS}</li>
+     * <li>{@link #ATTENDEE_IDENTITY}</li>
+     * <li>{@link #ATTENDEE_ID_NAMESPACE}</li>
      * </ul>
      */
     public static final class Attendees implements BaseColumns, AttendeesColumns, EventsColumns {
@@ -1221,12 +1239,17 @@
                     Attendees.ATTENDEE_RELATIONSHIP,
                     Attendees.ATTENDEE_TYPE,
                     Attendees.ATTENDEE_STATUS,
+                    Attendees.ATTENDEE_IDENTITY,
+                    Attendees.ATTENDEE_ID_NAMESPACE
             };
             private static final int COLUMN_ATTENDEE_NAME = 0;
             private static final int COLUMN_ATTENDEE_EMAIL = 1;
             private static final int COLUMN_ATTENDEE_RELATIONSHIP = 2;
             private static final int COLUMN_ATTENDEE_TYPE = 3;
             private static final int COLUMN_ATTENDEE_STATUS = 4;
+            private static final int COLUMN_ATTENDEE_IDENTITY = 5;
+            private static final int COLUMN_ATTENDEE_ID_NAMESPACE = 6;
+
             private static final String[] EXTENDED_PROJECTION = new String[] {
                     ExtendedProperties._ID,
                     ExtendedProperties.NAME,
@@ -1362,6 +1385,10 @@
                                 subCursor.getInt(COLUMN_ATTENDEE_TYPE));
                         attendeeValues.put(Attendees.ATTENDEE_STATUS,
                                 subCursor.getInt(COLUMN_ATTENDEE_STATUS));
+                        attendeeValues.put(Attendees.ATTENDEE_IDENTITY,
+                                subCursor.getInt(COLUMN_ATTENDEE_IDENTITY));
+                        attendeeValues.put(Attendees.ATTENDEE_ID_NAMESPACE,
+                                subCursor.getInt(COLUMN_ATTENDEE_ID_NAMESPACE));
                         entity.addSubValue(Attendees.CONTENT_URI, attendeeValues);
                     }
                 } finally {
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index e4729c7..035d8c4 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -1536,7 +1536,11 @@
          *
          * @param resolver the ContentResolver to use
          * @param contactId the person who was contacted
+         *
+         * @deprecated The class DataUsageStatUpdater of the Android support library should
+         *     be used instead.
          */
+        @Deprecated
         public static void markAsContacted(ContentResolver resolver, long contactId) {
             Uri uri = ContentUris.withAppendedId(CONTENT_URI, contactId);
             ContentValues values = new ContentValues();
@@ -7500,7 +7504,7 @@
      * <p>
      * Applications can also clear all usage information with:
      * <pre>
-     * boolean successful = resolver.delete(DataUsageFeedback.FEEDBACK_URI, null, null) > 0;
+     * boolean successful = resolver.delete(DataUsageFeedback.DELETE_USAGE_URI, null, null) > 0;
      * </pre>
      * </p>
      */
@@ -7514,6 +7518,14 @@
                 Uri.withAppendedPath(Data.CONTENT_URI, "usagefeedback");
 
         /**
+         * The content:// style URI for deleting all usage information.
+         * Must be used with {@link ContentResolver#delete(Uri, String, String[])}.
+         * The {@code where} and {@code selectionArgs} parameters are ignored.
+         */
+        public static final Uri DELETE_USAGE_URI =
+                Uri.withAppendedPath(Contacts.CONTENT_URI, "delete_usage");
+
+        /**
          * <p>
          * Name for query parameter specifying the type of data usage.
          * </p>
diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java
index bd6170b..cd8d51f 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -704,6 +704,37 @@
          */
         public static final int STATUS_BLOCKED = 498;
 
+        /** {@hide} */
+        public static String statusToString(int status) {
+            switch (status) {
+                case STATUS_PENDING: return "PENDING";
+                case STATUS_RUNNING: return "RUNNING";
+                case STATUS_PAUSED_BY_APP: return "PAUSED_BY_APP";
+                case STATUS_WAITING_TO_RETRY: return "WAITING_TO_RETRY";
+                case STATUS_WAITING_FOR_NETWORK: return "WAITING_FOR_NETWORK";
+                case STATUS_QUEUED_FOR_WIFI: return "QUEUED_FOR_WIFI";
+                case STATUS_INSUFFICIENT_SPACE_ERROR: return "INSUFFICIENT_SPACE_ERROR";
+                case STATUS_DEVICE_NOT_FOUND_ERROR: return "DEVICE_NOT_FOUND_ERROR";
+                case STATUS_SUCCESS: return "SUCCESS";
+                case STATUS_BAD_REQUEST: return "BAD_REQUEST";
+                case STATUS_NOT_ACCEPTABLE: return "NOT_ACCEPTABLE";
+                case STATUS_LENGTH_REQUIRED: return "LENGTH_REQUIRED";
+                case STATUS_PRECONDITION_FAILED: return "PRECONDITION_FAILED";
+                case STATUS_FILE_ALREADY_EXISTS_ERROR: return "FILE_ALREADY_EXISTS_ERROR";
+                case STATUS_CANNOT_RESUME: return "CANNOT_RESUME";
+                case STATUS_CANCELED: return "CANCELED";
+                case STATUS_UNKNOWN_ERROR: return "UNKNOWN_ERROR";
+                case STATUS_FILE_ERROR: return "FILE_ERROR";
+                case STATUS_UNHANDLED_REDIRECT: return "UNHANDLED_REDIRECT";
+                case STATUS_UNHANDLED_HTTP_CODE: return "UNHANDLED_HTTP_CODE";
+                case STATUS_HTTP_DATA_ERROR: return "HTTP_DATA_ERROR";
+                case STATUS_HTTP_EXCEPTION: return "HTTP_EXCEPTION";
+                case STATUS_TOO_MANY_REDIRECTS: return "TOO_MANY_REDIRECTS";
+                case STATUS_BLOCKED: return "BLOCKED";
+                default: return Integer.toString(status);
+            }
+        }
+
         /**
          * This download is visible but only shows in the notifications
          * while it's in progress.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 2aaf548..6dfbb2f 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1464,6 +1464,20 @@
         public static final String VIBRATE_ON = "vibrate_on";
 
         /**
+         * If 1, redirects the system vibrator to all currently attached input devices
+         * that support vibration.  If there are no such input devices, then the system
+         * vibrator is used instead.
+         * If 0, does not register the system vibrator.
+         *
+         * This setting is mainly intended to provide a compatibility mechanism for
+         * applications that only know about the system vibrator and do not use the
+         * input device vibrator API.
+         *
+         * @hide
+         */
+        public static final String VIBRATE_INPUT_DEVICES = "vibrate_input_devices";
+
+        /**
          * Ringer volume. This is used internally, changing this value will not
          * change the volume. See AudioManager.
          */
@@ -1970,6 +1984,7 @@
             SCREEN_BRIGHTNESS_MODE,
             SCREEN_AUTO_BRIGHTNESS_ADJ,
             VIBRATE_ON,
+            VIBRATE_INPUT_DEVICES,
             MODE_RINGER,
             MODE_RINGER_STREAMS_AFFECTED,
             MUTE_STREAMS_AFFECTED,
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index 850349b..36c0189 100755
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -611,6 +611,11 @@
     /*package*/ void initBluetoothAfterTurningOn() {
         String discoverable = getProperty("Discoverable", false);
         String timeout = getProperty("DiscoverableTimeout", false);
+        if (timeout == null) {
+            Log.w(TAG, "Null DiscoverableTimeout property");
+            // assign a number, anything not 0
+            timeout = "1";
+        }
         if (discoverable.equals("true") && Integer.valueOf(timeout) != 0) {
             setAdapterPropertyBooleanNative("Discoverable", 0);
         }
diff --git a/core/java/android/service/textservice/SpellCheckerService.java b/core/java/android/service/textservice/SpellCheckerService.java
index 53ce32d..c579e6e 100644
--- a/core/java/android/service/textservice/SpellCheckerService.java
+++ b/core/java/android/service/textservice/SpellCheckerService.java
@@ -26,12 +26,18 @@
 import android.os.IBinder;
 import android.os.Process;
 import android.os.RemoteException;
+import android.text.TextUtils;
+import android.text.method.WordIterator;
 import android.util.Log;
 import android.view.textservice.SentenceSuggestionsInfo;
 import android.view.textservice.SuggestionsInfo;
 import android.view.textservice.TextInfo;
+import android.widget.SpellChecker;
 
 import java.lang.ref.WeakReference;
+import java.text.BreakIterator;
+import java.util.ArrayList;
+import java.util.Locale;
 
 /**
  * SpellCheckerService provides an abstract base class for a spell checker.
@@ -92,6 +98,7 @@
      */
     public static abstract class Session {
         private InternalISpellCheckerSession mInternalSession;
+        private volatile SentenceLevelAdapter mSentenceLevelAdapter;
 
         /**
          * @hide
@@ -142,8 +149,8 @@
 
         /**
          * Get sentence suggestions for specified texts in an array of TextInfo.
-         * The default implementation returns an array of SentenceSuggestionsInfo by simply
-         * calling onGetSuggestions.
+         * The default implementation splits the input text to words and returns
+         * {@link SentenceSuggestionsInfo} which contains suggestions for each word.
          * This function will run on the incoming IPC thread.
          * So, this is not called on the main thread,
          * but will be called in series on another thread.
@@ -156,14 +163,41 @@
          */
         public SentenceSuggestionsInfo[] onGetSentenceSuggestionsMultiple(TextInfo[] textInfos,
                 int suggestionsLimit) {
-            final int length = textInfos.length;
-            final SentenceSuggestionsInfo[] retval = new SentenceSuggestionsInfo[length];
-            for (int i = 0; i < length; ++i) {
-                final SuggestionsInfo si = onGetSuggestions(textInfos[i], suggestionsLimit);
-                si.setCookieAndSequence(textInfos[i].getCookie(), textInfos[i].getSequence());
-                final int N = textInfos[i].getText().length();
-                retval[i] = new SentenceSuggestionsInfo(
-                        new SuggestionsInfo[] {si}, new int[]{0}, new int[]{N});
+            if (textInfos == null || textInfos.length == 0) {
+                return SentenceLevelAdapter.EMPTY_SENTENCE_SUGGESTIONS_INFOS;
+            }
+            if (DBG) {
+                Log.d(TAG, "onGetSentenceSuggestionsMultiple: + " + textInfos.length + ", "
+                        + suggestionsLimit);
+            }
+            if (mSentenceLevelAdapter == null) {
+                synchronized(this) {
+                    if (mSentenceLevelAdapter == null) {
+                        final String localeStr = getLocale();
+                        if (!TextUtils.isEmpty(localeStr)) {
+                            mSentenceLevelAdapter = new SentenceLevelAdapter(new Locale(localeStr));
+                        }
+                    }
+                }
+            }
+            if (mSentenceLevelAdapter == null) {
+                return SentenceLevelAdapter.EMPTY_SENTENCE_SUGGESTIONS_INFOS;
+            }
+            final int infosSize = textInfos.length;
+            final SentenceSuggestionsInfo[] retval = new SentenceSuggestionsInfo[infosSize];
+            for (int i = 0; i < infosSize; ++i) {
+                final SentenceLevelAdapter.SentenceTextInfoParams textInfoParams =
+                        mSentenceLevelAdapter.getSplitWords(textInfos[i]);
+                final ArrayList<SentenceLevelAdapter.SentenceWordItem> mItems =
+                        textInfoParams.mItems;
+                final int itemsSize = mItems.size();
+                final TextInfo[] splitTextInfos = new TextInfo[itemsSize];
+                for (int j = 0; j < itemsSize; ++j) {
+                    splitTextInfos[j] = mItems.get(j).mTextInfo;
+                }
+                retval[i] = SentenceLevelAdapter.reconstructSuggestions(
+                        textInfoParams, onGetSuggestionsMultiple(
+                                splitTextInfos, suggestionsLimit, true));
             }
             return retval;
         }
@@ -290,4 +324,135 @@
             return internalSession;
         }
     }
+
+    /**
+     * Adapter class to accommodate word level spell checking APIs to sentence level spell checking
+     * APIs used in
+     * {@link SpellCheckerService.Session#onGetSuggestionsMultiple(TextInfo[], int, boolean)}
+     */
+    private static class SentenceLevelAdapter {
+        public static final SentenceSuggestionsInfo[] EMPTY_SENTENCE_SUGGESTIONS_INFOS =
+                new SentenceSuggestionsInfo[] {};
+        private static final SuggestionsInfo EMPTY_SUGGESTIONS_INFO = new SuggestionsInfo(0, null);
+        /**
+         * Container for split TextInfo parameters
+         */
+        public static class SentenceWordItem {
+            public final TextInfo mTextInfo;
+            public final int mStart;
+            public final int mLength;
+            public SentenceWordItem(TextInfo ti, int start, int end) {
+                mTextInfo = ti;
+                mStart = start;
+                mLength = end - start;
+            }
+        }
+
+        /**
+         * Container for originally queried TextInfo and parameters
+         */
+        public static class SentenceTextInfoParams {
+            final TextInfo mOriginalTextInfo;
+            final ArrayList<SentenceWordItem> mItems;
+            final int mSize;
+            public SentenceTextInfoParams(TextInfo ti, ArrayList<SentenceWordItem> items) {
+                mOriginalTextInfo = ti;
+                mItems = items;
+                mSize = items.size();
+            }
+        }
+
+        private final WordIterator mWordIterator;
+        public SentenceLevelAdapter(Locale locale) {
+            mWordIterator = new WordIterator(locale);
+        }
+
+        private SentenceTextInfoParams getSplitWords(TextInfo originalTextInfo) {
+            final WordIterator wordIterator = mWordIterator;
+            final CharSequence originalText = originalTextInfo.getText();
+            final int cookie = originalTextInfo.getCookie();
+            final int start = 0;
+            final int end = originalText.length();
+            final ArrayList<SentenceWordItem> wordItems = new ArrayList<SentenceWordItem>();
+            wordIterator.setCharSequence(originalText, 0, originalText.length());
+            int wordEnd = wordIterator.following(start);
+            int wordStart = wordIterator.getBeginning(wordEnd);
+            if (DBG) {
+                Log.d(TAG, "iterator: break: ---- 1st word start = " + wordStart + ", end = "
+                        + wordEnd + "\n" + originalText);
+            }
+            while (wordStart <= end && wordEnd != BreakIterator.DONE
+                    && wordStart != BreakIterator.DONE) {
+                if (wordEnd >= start && wordEnd > wordStart) {
+                    final String query = originalText.subSequence(wordStart, wordEnd).toString();
+                    final TextInfo ti = new TextInfo(query, cookie, query.hashCode());
+                    wordItems.add(new SentenceWordItem(ti, wordStart, wordEnd));
+                    if (DBG) {
+                        Log.d(TAG, "Adapter: word (" + (wordItems.size() - 1) + ") " + query);
+                    }
+                }
+                wordEnd = wordIterator.following(wordEnd);
+                if (wordEnd == BreakIterator.DONE) {
+                    break;
+                }
+                wordStart = wordIterator.getBeginning(wordEnd);
+            }
+            if (originalText.length() >= SpellChecker.WORD_ITERATOR_INTERVAL
+                    && wordItems.size() >= 2) {
+                if (DBG) {
+                    Log.w(TAG, "Remove possibly divided word: "
+                            + wordItems.get(0).mTextInfo.getText());
+                }
+                wordItems.remove(0);
+            }
+            return new SentenceTextInfoParams(originalTextInfo, wordItems);
+        }
+
+        public static SentenceSuggestionsInfo reconstructSuggestions(
+                SentenceTextInfoParams originalTextInfoParams, SuggestionsInfo[] results) {
+            if (results == null || results.length == 0) {
+                return null;
+            }
+            if (DBG) {
+                Log.w(TAG, "Adapter: onGetSuggestions: got " + results.length);
+            }
+            if (originalTextInfoParams == null) {
+                if (DBG) {
+                    Log.w(TAG, "Adapter: originalTextInfoParams is null.");
+                }
+                return null;
+            }
+            final int originalCookie = originalTextInfoParams.mOriginalTextInfo.getCookie();
+            final int originalSequence =
+                    originalTextInfoParams.mOriginalTextInfo.getSequence();
+
+            final int querySize = originalTextInfoParams.mSize;
+            final int[] offsets = new int[querySize];
+            final int[] lengths = new int[querySize];
+            final SuggestionsInfo[] reconstructedSuggestions = new SuggestionsInfo[querySize];
+            for (int i = 0; i < querySize; ++i) {
+                final SentenceWordItem item = originalTextInfoParams.mItems.get(i);
+                SuggestionsInfo result = null;
+                for (int j = 0; j < results.length; ++j) {
+                    final SuggestionsInfo cur = results[j];
+                    if (cur != null && cur.getSequence() == item.mTextInfo.getSequence()) {
+                        result = cur;
+                        result.setCookieAndSequence(originalCookie, originalSequence);
+                        break;
+                    }
+                }
+                offsets[i] = item.mStart;
+                lengths[i] = item.mLength;
+                reconstructedSuggestions[i] = result != null ? result : EMPTY_SUGGESTIONS_INFO;
+                if (DBG) {
+                    final int size = reconstructedSuggestions[i].getSuggestionsCount();
+                    Log.w(TAG, "reconstructedSuggestions(" + i + ")" + size + ", first = "
+                            + (size > 0 ? reconstructedSuggestions[i].getSuggestionAt(0)
+                                    : "<none>") + ", offset = " + offsets[i] + ", length = "
+                            + lengths[i]);
+                }
+            }
+            return new SentenceSuggestionsInfo(reconstructedSuggestions, offsets, lengths);
+        }
+    }
 }
diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java
index 8c97293..35e2e4a 100644
--- a/core/java/android/text/Html.java
+++ b/core/java/android/text/Html.java
@@ -147,6 +147,15 @@
         return out.toString();
     }
 
+    /**
+     * Returns an HTML escaped representation of the given plain text.
+     */
+    public static String escapeHtml(CharSequence text) {
+        StringBuilder out = new StringBuilder();
+        withinStyle(out, text, 0, text.length());
+        return out.toString();
+    }
+
     private static void withinHtml(StringBuilder out, Spanned text) {
         int len = text.length();
 
@@ -370,7 +379,7 @@
         }
     }
 
-    private static void withinStyle(StringBuilder out, Spanned text,
+    private static void withinStyle(StringBuilder out, CharSequence text,
                                     int start, int end) {
         for (int i = start; i < end; i++) {
             char c = text.charAt(i);
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
new file mode 100644
index 0000000..6c1a6bf
--- /dev/null
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -0,0 +1,901 @@
+/*
+ * 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.view;
+
+import static android.view.accessibility.AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Process;
+import android.os.RemoteException;
+import android.util.Pool;
+import android.util.Poolable;
+import android.util.PoolableManager;
+import android.util.Pools;
+import android.util.SparseLongArray;
+import android.view.ViewGroup.ChildListForAccessibility;
+import android.view.accessibility.AccessibilityInteractionClient;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeProvider;
+import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Class for managing accessibility interactions initiated from the system
+ * and targeting the view hierarchy. A *ClientThread method is to be
+ * called from the interaction connection ViewAncestor gives the system to
+ * talk to it and a corresponding *UiThread method that is executed on the
+ * UI thread.
+ */
+final class AccessibilityInteractionController {
+    private static final int POOL_SIZE = 5;
+
+    private ArrayList<AccessibilityNodeInfo> mTempAccessibilityNodeInfoList =
+        new ArrayList<AccessibilityNodeInfo>();
+
+    private final Handler mHandler = new PrivateHandler();
+
+    private final ViewRootImpl mViewRootImpl;
+
+    private final AccessibilityNodePrefetcher mPrefetcher;
+
+    public AccessibilityInteractionController(ViewRootImpl viewRootImpl) {
+        mViewRootImpl = viewRootImpl;
+        mPrefetcher = new AccessibilityNodePrefetcher();
+    }
+
+    // Reusable poolable arguments for interacting with the view hierarchy
+    // to fit more arguments than Message and to avoid sharing objects between
+    // two messages since several threads can send messages concurrently.
+    private final Pool<SomeArgs> mPool = Pools.synchronizedPool(Pools.finitePool(
+            new PoolableManager<SomeArgs>() {
+                public SomeArgs newInstance() {
+                    return new SomeArgs();
+                }
+
+                public void onAcquired(SomeArgs info) {
+                    /* do nothing */
+                }
+
+                public void onReleased(SomeArgs info) {
+                    info.clear();
+                }
+            }, POOL_SIZE)
+    );
+
+    private class SomeArgs implements Poolable<SomeArgs> {
+        private SomeArgs mNext;
+        private boolean mIsPooled;
+
+        public Object arg1;
+        public Object arg2;
+        public int argi1;
+        public int argi2;
+        public int argi3;
+
+        public SomeArgs getNextPoolable() {
+            return mNext;
+        }
+
+        public boolean isPooled() {
+            return mIsPooled;
+        }
+
+        public void setNextPoolable(SomeArgs args) {
+            mNext = args;
+        }
+
+        public void setPooled(boolean isPooled) {
+            mIsPooled = isPooled;
+        }
+
+        private void clear() {
+            arg1 = null;
+            arg2 = null;
+            argi1 = 0;
+            argi2 = 0;
+            argi3 = 0;
+        }
+    }
+
+    public void findAccessibilityNodeInfoByAccessibilityIdClientThread(
+            long accessibilityNodeId, int interactionId,
+            IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
+            long interrogatingTid) {
+        Message message = mHandler.obtainMessage();
+        message.what = PrivateHandler.MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID;
+        message.arg1 = flags;
+        SomeArgs args = mPool.acquire();
+        args.argi1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
+        args.argi2 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId);
+        args.argi3 = interactionId;
+        args.arg1 = callback;
+        message.obj = args;
+        // If the interrogation is performed by the same thread as the main UI
+        // thread in this process, set the message as a static reference so
+        // after this call completes the same thread but in the interrogating
+        // client can handle the message to generate the result.
+        if (interrogatingPid == Process.myPid()
+                && interrogatingTid == Looper.getMainLooper().getThread().getId()) {
+            AccessibilityInteractionClient.getInstanceForThread(
+                    interrogatingTid).setSameThreadMessage(message);
+        } else {
+            mHandler.sendMessage(message);
+        }
+    }
+
+    private void findAccessibilityNodeInfoByAccessibilityIdUiThread(Message message) {
+        final int flags = message.arg1;
+        SomeArgs args = (SomeArgs) message.obj;
+        final int accessibilityViewId = args.argi1;
+        final int virtualDescendantId = args.argi2;
+        final int interactionId = args.argi3;
+        final IAccessibilityInteractionConnectionCallback callback =
+            (IAccessibilityInteractionConnectionCallback) args.arg1;
+        mPool.release(args);
+        List<AccessibilityNodeInfo> infos = mTempAccessibilityNodeInfoList;
+        infos.clear();
+        try {
+            if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null) {
+                return;
+            }
+            mViewRootImpl.mAttachInfo.mIncludeNotImportantViews =
+                (flags & INCLUDE_NOT_IMPORTANT_VIEWS) != 0;
+            View root = null;
+            if (accessibilityViewId == AccessibilityNodeInfo.UNDEFINED) {
+                root = mViewRootImpl.mView;
+            } else {
+                root = findViewByAccessibilityId(accessibilityViewId);
+            }
+            if (root != null && isDisplayedOnScreen(root)) {
+                mPrefetcher.prefetchAccessibilityNodeInfos(root, virtualDescendantId, flags, infos);
+            }
+        } finally {
+            try {
+                mViewRootImpl.mAttachInfo.mIncludeNotImportantViews = false;
+                callback.setFindAccessibilityNodeInfosResult(infos, interactionId);
+                infos.clear();
+            } catch (RemoteException re) {
+                /* ignore - the other side will time out */
+            }
+        }
+    }
+
+    public void findAccessibilityNodeInfoByViewIdClientThread(long accessibilityNodeId,
+            int viewId, int interactionId, IAccessibilityInteractionConnectionCallback callback,
+            int flags, int interrogatingPid, long interrogatingTid) {
+        Message message = mHandler.obtainMessage();
+        message.what = PrivateHandler.MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID;
+        message.arg1 = flags;
+        message.arg2 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
+        SomeArgs args = mPool.acquire();
+        args.argi1 = viewId;
+        args.argi2 = interactionId;
+        args.arg1 = callback;
+        message.obj = args;
+        // If the interrogation is performed by the same thread as the main UI
+        // thread in this process, set the message as a static reference so
+        // after this call completes the same thread but in the interrogating
+        // client can handle the message to generate the result.
+        if (interrogatingPid == Process.myPid()
+                && interrogatingTid == Looper.getMainLooper().getThread().getId()) {
+            AccessibilityInteractionClient.getInstanceForThread(
+                    interrogatingTid).setSameThreadMessage(message);
+        } else {
+            mHandler.sendMessage(message);
+        }
+    }
+
+    private void findAccessibilityNodeInfoByViewIdUiThread(Message message) {
+        final int flags = message.arg1;
+        final int accessibilityViewId = message.arg2;
+        SomeArgs args = (SomeArgs) message.obj;
+        final int viewId = args.argi1;
+        final int interactionId = args.argi2;
+        final IAccessibilityInteractionConnectionCallback callback =
+            (IAccessibilityInteractionConnectionCallback) args.arg1;
+        mPool.release(args);
+        AccessibilityNodeInfo info = null;
+        try {
+            if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null) {
+                return;
+            }
+            mViewRootImpl.mAttachInfo.mIncludeNotImportantViews =
+                (flags & INCLUDE_NOT_IMPORTANT_VIEWS) != 0;
+            View root = null;
+            if (accessibilityViewId != AccessibilityNodeInfo.UNDEFINED) {
+                root = findViewByAccessibilityId(accessibilityViewId);
+            } else {
+                root = mViewRootImpl.mView;
+            }
+            if (root != null) {
+                View target = root.findViewById(viewId);
+                if (target != null && isDisplayedOnScreen(target)) {
+                    info = target.createAccessibilityNodeInfo();
+                }
+            }
+        } finally {
+            try {
+                mViewRootImpl.mAttachInfo.mIncludeNotImportantViews = false;
+                callback.setFindAccessibilityNodeInfoResult(info, interactionId);
+            } catch (RemoteException re) {
+                /* ignore - the other side will time out */
+            }
+        }
+    }
+
+    public void findAccessibilityNodeInfosByTextClientThread(long accessibilityNodeId,
+            String text, int interactionId, IAccessibilityInteractionConnectionCallback callback,
+            int flags,  int interrogatingPid, long interrogatingTid) {
+        Message message = mHandler.obtainMessage();
+        message.what = PrivateHandler.MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT;
+        message.arg1 = flags;
+        SomeArgs args = mPool.acquire();
+        args.arg1 = text;
+        args.argi1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
+        args.argi2 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId);
+        args.argi3 = interactionId;
+        args.arg2 = callback;
+        message.obj = args;
+        // If the interrogation is performed by the same thread as the main UI
+        // thread in this process, set the message as a static reference so
+        // after this call completes the same thread but in the interrogating
+        // client can handle the message to generate the result.
+        if (interrogatingPid == Process.myPid()
+                && interrogatingTid == Looper.getMainLooper().getThread().getId()) {
+            AccessibilityInteractionClient.getInstanceForThread(
+                    interrogatingTid).setSameThreadMessage(message);
+        } else {
+            mHandler.sendMessage(message);
+        }
+    }
+
+    private void findAccessibilityNodeInfosByTextUiThread(Message message) {
+        final int flags = message.arg1;
+        SomeArgs args = (SomeArgs) message.obj;
+        final String text = (String) args.arg1;
+        final int accessibilityViewId = args.argi1;
+        final int virtualDescendantId = args.argi2;
+        final int interactionId = args.argi3;
+        final IAccessibilityInteractionConnectionCallback callback =
+            (IAccessibilityInteractionConnectionCallback) args.arg2;
+        mPool.release(args);
+        List<AccessibilityNodeInfo> infos = null;
+        try {
+            if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null) {
+                return;
+            }
+            mViewRootImpl.mAttachInfo.mIncludeNotImportantViews =
+                (flags & INCLUDE_NOT_IMPORTANT_VIEWS) != 0;
+            View root = null;
+            if (accessibilityViewId != AccessibilityNodeInfo.UNDEFINED) {
+                root = findViewByAccessibilityId(accessibilityViewId);
+            } else {
+                root = mViewRootImpl.mView;
+            }
+            if (root != null && isDisplayedOnScreen(root)) {
+                AccessibilityNodeProvider provider = root.getAccessibilityNodeProvider();
+                if (provider != null) {
+                    infos = provider.findAccessibilityNodeInfosByText(text,
+                            virtualDescendantId);
+                } else if (virtualDescendantId == AccessibilityNodeInfo.UNDEFINED) {
+                    ArrayList<View> foundViews = mViewRootImpl.mAttachInfo.mTempArrayList;
+                    foundViews.clear();
+                    root.findViewsWithText(foundViews, text, View.FIND_VIEWS_WITH_TEXT
+                            | View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION
+                            | View.FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS);
+                    if (!foundViews.isEmpty()) {
+                        infos = mTempAccessibilityNodeInfoList;
+                        infos.clear();
+                        final int viewCount = foundViews.size();
+                        for (int i = 0; i < viewCount; i++) {
+                            View foundView = foundViews.get(i);
+                            if (isDisplayedOnScreen(foundView)) {
+                                provider = foundView.getAccessibilityNodeProvider();
+                                if (provider != null) {
+                                    List<AccessibilityNodeInfo> infosFromProvider =
+                                        provider.findAccessibilityNodeInfosByText(text,
+                                                virtualDescendantId);
+                                    if (infosFromProvider != null) {
+                                        infos.addAll(infosFromProvider);
+                                    }
+                                } else  {
+                                    infos.add(foundView.createAccessibilityNodeInfo());
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        } finally {
+            try {
+                mViewRootImpl.mAttachInfo.mIncludeNotImportantViews = false;
+                callback.setFindAccessibilityNodeInfosResult(infos, interactionId);
+            } catch (RemoteException re) {
+                /* ignore - the other side will time out */
+            }
+        }
+    }
+
+    public void findFocusClientThread(long accessibilityNodeId, int interactionId, int focusType,
+            IAccessibilityInteractionConnectionCallback callback,  int flags, int interogatingPid,
+            long interrogatingTid) {
+        Message message = mHandler.obtainMessage();
+        message.what = PrivateHandler.MSG_FIND_FOCUS;
+        message.arg1 = flags;
+        message.arg2 = focusType;
+        SomeArgs args = mPool.acquire();
+        args.argi1 = interactionId;
+        args.argi2 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
+        args.argi3 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId);
+        args.arg1 = callback;
+        message.obj = args;
+        // If the interrogation is performed by the same thread as the main UI
+        // thread in this process, set the message as a static reference so
+        // after this call completes the same thread but in the interrogating
+        // client can handle the message to generate the result.
+        if (interogatingPid == Process.myPid()
+                && interrogatingTid == Looper.getMainLooper().getThread().getId()) {
+            AccessibilityInteractionClient.getInstanceForThread(
+                    interrogatingTid).setSameThreadMessage(message);
+        } else {
+            mHandler.sendMessage(message);
+        }
+    }
+
+    private void findFocusUiThread(Message message) {
+        final int flags = message.arg1;
+        final int focusType = message.arg2;
+        SomeArgs args = (SomeArgs) message.obj;
+        final int interactionId = args.argi1;
+        final int accessibilityViewId = args.argi2;
+        final int virtualDescendantId = args.argi3;
+        final IAccessibilityInteractionConnectionCallback callback =
+            (IAccessibilityInteractionConnectionCallback) args.arg1;
+        mPool.release(args);
+        AccessibilityNodeInfo focused = null;
+        try {
+            if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null) {
+                return;
+            }
+            mViewRootImpl.mAttachInfo.mIncludeNotImportantViews =
+                (flags & INCLUDE_NOT_IMPORTANT_VIEWS) != 0;
+            View root = null;
+            if (accessibilityViewId != AccessibilityNodeInfo.UNDEFINED) {
+                root = findViewByAccessibilityId(accessibilityViewId);
+            } else {
+                root = mViewRootImpl.mView;
+            }
+            if (root != null && isDisplayedOnScreen(root)) {
+                switch (focusType) {
+                    case AccessibilityNodeInfo.FOCUS_ACCESSIBILITY: {
+                        View host = mViewRootImpl.mAccessibilityFocusedHost;
+                        // If there is no accessibility focus host or it is not a descendant
+                        // of the root from which to start the search, then the search failed.
+                        if (host == null || !ViewRootImpl.isViewDescendantOf(host, root)) {
+                            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();
+                        if (provider != null) {
+                            focused = provider.findAccessibilitiyFocus(virtualDescendantId);
+                        } else if (virtualDescendantId == View.NO_ID) {
+                            focused = host.createAccessibilityNodeInfo();
+                        }
+                    } break;
+                    case AccessibilityNodeInfo.FOCUS_INPUT: {
+                        // Input focus cannot go to virtual views.
+                        View target = root.findFocus();
+                        if (target != null && isDisplayedOnScreen(target)) {
+                            focused = target.createAccessibilityNodeInfo();
+                        }
+                    } break;
+                    default:
+                        throw new IllegalArgumentException("Unknown focus type: " + focusType);
+                }
+            }
+        } finally {
+            try {
+                mViewRootImpl.mAttachInfo.mIncludeNotImportantViews = false;
+                callback.setFindAccessibilityNodeInfoResult(focused, interactionId);
+            } catch (RemoteException re) {
+                /* ignore - the other side will time out */
+            }
+        }
+    }
+
+    public void focusSearchClientThread(long accessibilityNodeId, int interactionId, int direction,
+            IAccessibilityInteractionConnectionCallback callback, int flags, int interogatingPid,
+            long interrogatingTid) {
+        Message message = mHandler.obtainMessage();
+        message.what = PrivateHandler.MSG_FOCUS_SEARCH;
+        message.arg1 = flags;
+        message.arg2 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
+        SomeArgs args = mPool.acquire();
+        args.argi1 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId);
+        args.argi2 = direction;
+        args.argi3 = interactionId;
+        args.arg1 = callback;
+        message.obj = args;
+        // If the interrogation is performed by the same thread as the main UI
+        // thread in this process, set the message as a static reference so
+        // after this call completes the same thread but in the interrogating
+        // client can handle the message to generate the result.
+        if (interogatingPid == Process.myPid()
+                && interrogatingTid == Looper.getMainLooper().getThread().getId()) {
+            AccessibilityInteractionClient.getInstanceForThread(
+                    interrogatingTid).setSameThreadMessage(message);
+        } else {
+            mHandler.sendMessage(message);
+        }
+    }
+
+    private void focusSearchUiThread(Message message) {
+        final int flags = message.arg1;
+        final int accessibilityViewId = message.arg2;
+        SomeArgs args = (SomeArgs) message.obj;
+        final int virtualDescendantId = args.argi1;
+        final int direction = args.argi2;
+        final int interactionId = args.argi3;
+        final IAccessibilityInteractionConnectionCallback callback =
+            (IAccessibilityInteractionConnectionCallback) args.arg1;
+        mPool.release(args);
+        AccessibilityNodeInfo next = null;
+        try {
+            if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null) {
+                return;
+            }
+            mViewRootImpl.mAttachInfo.mIncludeNotImportantViews =
+                (flags & INCLUDE_NOT_IMPORTANT_VIEWS) != 0;
+            View root = null;
+            if (accessibilityViewId != AccessibilityNodeInfo.UNDEFINED) {
+                root = findViewByAccessibilityId(accessibilityViewId);
+            } else {
+                root = mViewRootImpl.mView;
+            }
+            if (root != null && isDisplayedOnScreen(root)) {
+                if ((direction & View.FOCUS_ACCESSIBILITY) ==  View.FOCUS_ACCESSIBILITY) {
+                    AccessibilityNodeProvider provider = root.getAccessibilityNodeProvider();
+                    if (provider != null) {
+                        next = provider.accessibilityFocusSearch(direction,
+                                virtualDescendantId);
+                    } else if (virtualDescendantId == View.NO_ID) {
+                        View nextView = root.focusSearch(direction);
+                        if (nextView != null) {
+                            // If the focus search reached a node with a provider
+                            // we delegate to the provider to find the next one.
+                            provider = nextView.getAccessibilityNodeProvider();
+                            if (provider != null) {
+                                next = provider.accessibilityFocusSearch(direction,
+                                        virtualDescendantId);
+                            } else {
+                                next = nextView.createAccessibilityNodeInfo();
+                             }
+                        }
+                    }
+                } else {
+                    View nextView = root.focusSearch(direction);
+                    if (nextView != null) {
+                        next = nextView.createAccessibilityNodeInfo();
+                    }
+                }
+            }
+        } finally {
+            try {
+                mViewRootImpl.mAttachInfo.mIncludeNotImportantViews = false;
+                callback.setFindAccessibilityNodeInfoResult(next, interactionId);
+            } catch (RemoteException re) {
+                /* ignore - the other side will time out */
+            }
+        }
+    }
+
+    public void performAccessibilityActionClientThread(long accessibilityNodeId, int action,
+            int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
+            int interogatingPid, long interrogatingTid) {
+        Message message = mHandler.obtainMessage();
+        message.what = PrivateHandler.MSG_PERFORM_ACCESSIBILITY_ACTION;
+        message.arg1 = flags;
+        message.arg2 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
+        SomeArgs args = mPool.acquire();
+        args.argi1 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId);
+        args.argi2 = action;
+        args.argi3 = interactionId;
+        args.arg1 = callback;
+        message.obj = args;
+        // If the interrogation is performed by the same thread as the main UI
+        // thread in this process, set the message as a static reference so
+        // after this call completes the same thread but in the interrogating
+        // client can handle the message to generate the result.
+        if (interogatingPid == Process.myPid()
+                && interrogatingTid == Looper.getMainLooper().getThread().getId()) {
+            AccessibilityInteractionClient.getInstanceForThread(
+                    interrogatingTid).setSameThreadMessage(message);
+        } else {
+            mHandler.sendMessage(message);
+        }
+    }
+
+    private void perfromAccessibilityActionUiThread(Message message) {
+        final int flags = message.arg1;
+        final int accessibilityViewId = message.arg2;
+        SomeArgs args = (SomeArgs) message.obj;
+        final int virtualDescendantId = args.argi1;
+        final int action = args.argi2;
+        final int interactionId = args.argi3;
+        final IAccessibilityInteractionConnectionCallback callback =
+            (IAccessibilityInteractionConnectionCallback) args.arg1;
+        mPool.release(args);
+        boolean succeeded = false;
+        try {
+            if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null) {
+                return;
+            }
+            mViewRootImpl.mAttachInfo.mIncludeNotImportantViews =
+                (flags & INCLUDE_NOT_IMPORTANT_VIEWS) != 0;
+            View target = null;
+            if (accessibilityViewId != AccessibilityNodeInfo.UNDEFINED) {
+                target = findViewByAccessibilityId(accessibilityViewId);
+            } else {
+                target = mViewRootImpl.mView;
+            }
+            if (target != null && isDisplayedOnScreen(target)) {
+                AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider();
+                if (provider != null) {
+                    succeeded = provider.performAccessibilityAction(action, virtualDescendantId);
+                } else if (virtualDescendantId == View.NO_ID) {
+                    succeeded = target.performAccessibilityAction(action);
+                }
+            }
+        } finally {
+            try {
+                mViewRootImpl.mAttachInfo.mIncludeNotImportantViews = false;
+                callback.setPerformAccessibilityActionResult(succeeded, interactionId);
+            } catch (RemoteException re) {
+                /* ignore - the other side will time out */
+            }
+        }
+    }
+
+    private View findViewByAccessibilityId(int accessibilityId) {
+        View root = mViewRootImpl.mView;
+        if (root == null) {
+            return null;
+        }
+        View foundView = root.findViewByAccessibilityId(accessibilityId);
+        if (foundView != null && !isDisplayedOnScreen(foundView)) {
+            return null;
+        }
+        return foundView;
+    }
+
+    /**
+     * Computes whether a view is visible on the screen.
+     *
+     * @param view The view to check.
+     * @return Whether the view is visible on the screen.
+     */
+    private boolean isDisplayedOnScreen(View view) {
+        // The first two checks are made also made by isShown() which
+        // however traverses the tree up to the parent to catch that.
+        // Therefore, we do some fail fast check to minimize the up
+        // tree traversal.
+        return (view.mAttachInfo != null
+                && view.mAttachInfo.mWindowVisibility == View.VISIBLE
+                && view.getAlpha() > 0
+                && view.isShown()
+                && view.getGlobalVisibleRect(mViewRootImpl.mTempRect));
+    }
+
+    /**
+     * This class encapsulates a prefetching strategy for the accessibility APIs for
+     * querying window content. It is responsible to prefetch a batch of
+     * AccessibilityNodeInfos in addition to the one for a requested node.
+     */
+    private class AccessibilityNodePrefetcher {
+
+        private static final int MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE = 50;
+
+        public void prefetchAccessibilityNodeInfos(View view, int virtualViewId, int prefetchFlags,
+                List<AccessibilityNodeInfo> outInfos) {
+            AccessibilityNodeProvider provider = view.getAccessibilityNodeProvider();
+            if (provider == null) {
+                AccessibilityNodeInfo root = view.createAccessibilityNodeInfo();
+                if (root != null) {
+                    outInfos.add(root);
+                    if ((prefetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) != 0) {
+                        prefetchPredecessorsOfRealNode(view, outInfos);
+                    }
+                    if ((prefetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS) != 0) {
+                        prefetchSiblingsOfRealNode(view, outInfos);
+                    }
+                    if ((prefetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS) != 0) {
+                        prefetchDescendantsOfRealNode(view, outInfos);
+                    }
+                }
+            } else {
+                AccessibilityNodeInfo root = provider.createAccessibilityNodeInfo(virtualViewId);
+                if (root != null) {
+                    outInfos.add(root);
+                    if ((prefetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) != 0) {
+                        prefetchPredecessorsOfVirtualNode(root, view, provider, outInfos);
+                    }
+                    if ((prefetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS) != 0) {
+                        prefetchSiblingsOfVirtualNode(root, view, provider, outInfos);
+                    }
+                    if ((prefetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS) != 0) {
+                        prefetchDescendantsOfVirtualNode(root, provider, outInfos);
+                    }
+                }
+            }
+        }
+
+        private void prefetchPredecessorsOfRealNode(View view,
+                List<AccessibilityNodeInfo> outInfos) {
+            ViewParent parent = view.getParentForAccessibility();
+            while (parent instanceof View
+                    && outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
+                View parentView = (View) parent;
+                final long parentNodeId = AccessibilityNodeInfo.makeNodeId(
+                        parentView.getAccessibilityViewId(), AccessibilityNodeInfo.UNDEFINED);
+                AccessibilityNodeInfo info = parentView.createAccessibilityNodeInfo();
+                if (info != null) {
+                    outInfos.add(info);
+                }
+                parent = parent.getParentForAccessibility();
+            }
+        }
+
+        private void prefetchSiblingsOfRealNode(View current,
+                List<AccessibilityNodeInfo> outInfos) {
+            ViewParent parent = current.getParentForAccessibility();
+            if (parent instanceof ViewGroup) {
+                ViewGroup parentGroup = (ViewGroup) parent;
+                ChildListForAccessibility children = ChildListForAccessibility.obtain(parentGroup,
+                        false);
+                final int childCount = children.getChildCount();
+                for (int i = 0; i < childCount; i++) {
+                    if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
+                        children.recycle();
+                        return;
+                    }
+                    View child = children.getChildAt(i);
+                    if (child.getAccessibilityViewId() != current.getAccessibilityViewId()
+                            &&  isDisplayedOnScreen(child)) {
+                        AccessibilityNodeInfo info = null;
+                        AccessibilityNodeProvider provider = child.getAccessibilityNodeProvider();
+                        if (provider == null) {
+                            info = child.createAccessibilityNodeInfo();
+                        } else {
+                            info = provider.createAccessibilityNodeInfo(
+                                    AccessibilityNodeInfo.UNDEFINED);
+                        }
+                        if (info != null) {
+                            outInfos.add(info);
+                        }
+                    }
+                }
+                children.recycle();
+            }
+        }
+
+        private void prefetchDescendantsOfRealNode(View root,
+                List<AccessibilityNodeInfo> outInfos) {
+            if (!(root instanceof ViewGroup)) {
+                return;
+            }
+            ViewGroup rootGroup = (ViewGroup) root;
+            HashMap<View, AccessibilityNodeInfo> addedChildren =
+                new HashMap<View, AccessibilityNodeInfo>();
+            ChildListForAccessibility children = ChildListForAccessibility.obtain(rootGroup, false);
+            final int childCount = children.getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
+                    children.recycle();
+                    return;
+                }
+                View child = children.getChildAt(i);
+                if ( isDisplayedOnScreen(child)) {
+                    AccessibilityNodeProvider provider = child.getAccessibilityNodeProvider();
+                    if (provider == null) {
+                        AccessibilityNodeInfo info = child.createAccessibilityNodeInfo();
+                        if (info != null) {
+                            outInfos.add(info);
+                            addedChildren.put(child, null);
+                        }
+                    } else {
+                        AccessibilityNodeInfo info = provider.createAccessibilityNodeInfo(
+                               AccessibilityNodeInfo.UNDEFINED);
+                        if (info != null) {
+                            outInfos.add(info);
+                            addedChildren.put(child, info);
+                        }
+                    }
+                }
+            }
+            children.recycle();
+            if (outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
+                for (Map.Entry<View, AccessibilityNodeInfo> entry : addedChildren.entrySet()) {
+                    View addedChild = entry.getKey();
+                    AccessibilityNodeInfo virtualRoot = entry.getValue();
+                    if (virtualRoot == null) {
+                        prefetchDescendantsOfRealNode(addedChild, outInfos);
+                    } else {
+                        AccessibilityNodeProvider provider =
+                            addedChild.getAccessibilityNodeProvider();
+                        prefetchDescendantsOfVirtualNode(virtualRoot, provider, outInfos);
+                    }
+                }
+            }
+        }
+
+        private void prefetchPredecessorsOfVirtualNode(AccessibilityNodeInfo root,
+                View providerHost, AccessibilityNodeProvider provider,
+                List<AccessibilityNodeInfo> outInfos) {
+            long parentNodeId = root.getParentNodeId();
+            int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(parentNodeId);
+            while (accessibilityViewId != AccessibilityNodeInfo.UNDEFINED) {
+                if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
+                    return;
+                }
+                final int virtualDescendantId =
+                    AccessibilityNodeInfo.getVirtualDescendantId(parentNodeId);
+                if (virtualDescendantId != AccessibilityNodeInfo.UNDEFINED
+                        || accessibilityViewId == providerHost.getAccessibilityViewId()) {
+                    AccessibilityNodeInfo parent = provider.createAccessibilityNodeInfo(
+                            virtualDescendantId);
+                    if (parent != null) {
+                        outInfos.add(parent);
+                    }
+                    parentNodeId = parent.getParentNodeId();
+                    accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
+                            parentNodeId);
+                } else {
+                    prefetchPredecessorsOfRealNode(providerHost, outInfos);
+                    return;
+                }
+            }
+        }
+
+        private void prefetchSiblingsOfVirtualNode(AccessibilityNodeInfo current, View providerHost,
+                AccessibilityNodeProvider provider, List<AccessibilityNodeInfo> outInfos) {
+            final long parentNodeId = current.getParentNodeId();
+            final int parentAccessibilityViewId =
+                AccessibilityNodeInfo.getAccessibilityViewId(parentNodeId);
+            final int parentVirtualDescendantId =
+                AccessibilityNodeInfo.getVirtualDescendantId(parentNodeId);
+            if (parentVirtualDescendantId != AccessibilityNodeInfo.UNDEFINED
+                    || parentAccessibilityViewId == providerHost.getAccessibilityViewId()) {
+                AccessibilityNodeInfo parent =
+                    provider.createAccessibilityNodeInfo(parentVirtualDescendantId);
+                if (parent != null) {
+                    SparseLongArray childNodeIds = parent.getChildNodeIds();
+                    final int childCount = childNodeIds.size();
+                    for (int i = 0; i < childCount; i++) {
+                        if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
+                            return;
+                        }
+                        final long childNodeId = childNodeIds.get(i);
+                        if (childNodeId != current.getSourceNodeId()) {
+                            final int childVirtualDescendantId =
+                                AccessibilityNodeInfo.getVirtualDescendantId(childNodeId);
+                            AccessibilityNodeInfo child = provider.createAccessibilityNodeInfo(
+                                    childVirtualDescendantId);
+                            if (child != null) {
+                                outInfos.add(child);
+                            }
+                        }
+                    }
+                }
+            } else {
+                prefetchSiblingsOfRealNode(providerHost, outInfos);
+            }
+        }
+
+        private void prefetchDescendantsOfVirtualNode(AccessibilityNodeInfo root,
+                AccessibilityNodeProvider provider, List<AccessibilityNodeInfo> outInfos) {
+            SparseLongArray childNodeIds = root.getChildNodeIds();
+            final int initialOutInfosSize = outInfos.size();
+            final int childCount = childNodeIds.size();
+            for (int i = 0; i < childCount; i++) {
+                if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
+                    return;
+                }
+                final long childNodeId = childNodeIds.get(i);
+                AccessibilityNodeInfo child = provider.createAccessibilityNodeInfo(
+                        AccessibilityNodeInfo.getVirtualDescendantId(childNodeId));
+                if (child != null) {
+                    outInfos.add(child);
+                }
+            }
+            if (outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
+                final int addedChildCount = outInfos.size() - initialOutInfosSize;
+                for (int i = 0; i < addedChildCount; i++) {
+                    AccessibilityNodeInfo child = outInfos.get(initialOutInfosSize + i);
+                    prefetchDescendantsOfVirtualNode(child, provider, outInfos);
+                }
+            }
+        }
+    }
+
+    private class PrivateHandler extends Handler {
+        private final static int MSG_PERFORM_ACCESSIBILITY_ACTION = 1;
+        private final static int MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID = 2;
+        private final static int MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID = 3;
+        private final static int MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT = 4;
+        private final static int MSG_FIND_FOCUS = 5;
+        private final static int MSG_FOCUS_SEARCH = 6;
+
+        public PrivateHandler() {
+            super(Looper.getMainLooper());
+        }
+
+        @Override
+        public String getMessageName(Message message) {
+            final int type = message.what;
+            switch (type) {
+                case MSG_PERFORM_ACCESSIBILITY_ACTION:
+                    return "MSG_PERFORM_ACCESSIBILITY_ACTION";
+                case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID:
+                    return "MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID";
+                case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID:
+                    return "MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID";
+                case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT:
+                    return "MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT";
+                case MSG_FIND_FOCUS:
+                    return "MSG_FIND_FOCUS";
+                case MSG_FOCUS_SEARCH:
+                    return "MSG_FOCUS_SEARCH";
+                default:
+                    throw new IllegalArgumentException("Unknown message type: " + type);
+            }
+        }
+
+        @Override
+        public void handleMessage(Message message) {
+            final int type = message.what;
+            switch (type) {
+                case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID: {
+                    findAccessibilityNodeInfoByAccessibilityIdUiThread(message);
+                } break;
+                case MSG_PERFORM_ACCESSIBILITY_ACTION: {
+                    perfromAccessibilityActionUiThread(message);
+                } break;
+                case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID: {
+                    findAccessibilityNodeInfoByViewIdUiThread(message);
+                } break;
+                case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT: {
+                    findAccessibilityNodeInfosByTextUiThread(message);
+                } break;
+                case MSG_FIND_FOCUS: {
+                    findFocusUiThread(message);
+                } break;
+                case MSG_FOCUS_SEARCH: {
+                    focusSearchUiThread(message);
+                } break;
+                default:
+                    throw new IllegalArgumentException("Unknown message type: " + type);
+            }
+        }
+    }
+}
diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java
index 3529b8e..8a01c15 100644
--- a/core/java/android/view/FocusFinder.java
+++ b/core/java/android/view/FocusFinder.java
@@ -17,10 +17,12 @@
 package android.view;
 
 import android.graphics.Rect;
+import android.view.ViewGroup.ChildListForAccessibility;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.Stack;
 
 /**
  * The algorithm used for finding the next focusable view in a given direction
@@ -30,7 +32,7 @@
 
     private static ThreadLocal<FocusFinder> tlFocusFinder =
             new ThreadLocal<FocusFinder>() {
-
+                @Override
                 protected FocusFinder initialValue() {
                     return new FocusFinder();
                 }
@@ -48,6 +50,10 @@
     Rect mBestCandidateRect = new Rect();
     SequentialFocusComparator mSequentialFocusComparator = new SequentialFocusComparator();
 
+    private final ArrayList<View> mTempList = new ArrayList<View>();
+
+    private Stack<View> mTempStack;
+
     // enforce thread local access
     private FocusFinder() {}
 
@@ -60,7 +66,30 @@
      * @return The next focusable view, or null if none exists.
      */
     public final View findNextFocus(ViewGroup root, View focused, int direction) {
+        return findNextFocus(root, focused, mFocusedRect, direction);
+    }
 
+    /**
+     * Find the next view to take focus in root's descendants, searching from
+     * a particular rectangle in root's coordinates.
+     * @param root Contains focusedRect. Cannot be null.
+     * @param focusedRect The starting point of the search.
+     * @param direction Direction to look.
+     * @return The next focusable view, or null if none exists.
+     */
+    public View findNextFocusFromRect(ViewGroup root, Rect focusedRect, int direction) {
+        return findNextFocus(root, null, focusedRect, direction);
+    }
+
+    private View findNextFocus(ViewGroup root, View focused, Rect focusedRect, int direction) {
+        if ((direction & View.FOCUS_ACCESSIBILITY) != View.FOCUS_ACCESSIBILITY) {
+            return findNextInputFocus(root, focused, focusedRect, direction);
+        } else {
+            return findNextAccessibilityFocus(root, focused, direction);
+        }
+    }
+
+    private View findNextInputFocus(ViewGroup root, View focused, Rect focusedRect, int direction) {
         if (focused != null) {
             // check for user specified next focus
             View userSetNextFocus = focused.findUserSetNextFocus(root, direction);
@@ -79,90 +108,154 @@
             switch (direction) {
                 case View.FOCUS_RIGHT:
                 case View.FOCUS_DOWN:
-                    setFocusBottomRight(root);
+                    setFocusTopLeft(root);
                     break;
                 case View.FOCUS_FORWARD:
                     if (root.isLayoutRtl()) {
-                        setFocusTopLeft(root);
-                    } else {
                         setFocusBottomRight(root);
+                    } else {
+                        setFocusTopLeft(root);
                     }
                     break;
 
                 case View.FOCUS_LEFT:
                 case View.FOCUS_UP:
-                    setFocusTopLeft(root);
+                    setFocusBottomRight(root);
                     break;
                 case View.FOCUS_BACKWARD:
                     if (root.isLayoutRtl()) {
-                        setFocusBottomRight(root);
-                    } else {
                         setFocusTopLeft(root);
+                    } else {
+                        setFocusBottomRight(root);
                     break;
                 }
             }
         }
-        return findNextFocus(root, focused, mFocusedRect, direction);
+
+        ArrayList<View> focusables = mTempList;
+        focusables.clear();
+        root.addFocusables(focusables, direction);
+        if (focusables.isEmpty()) {
+            // The focus cannot change.
+            return null;
+        }
+
+        try {
+            switch (direction) {
+                case View.FOCUS_FORWARD:
+                case View.FOCUS_BACKWARD:
+                    return findNextInputFocusInRelativeDirection(focusables, root, focused,
+                            focusedRect, direction);
+                case View.FOCUS_UP:
+                case View.FOCUS_DOWN:
+                case View.FOCUS_LEFT:
+                case View.FOCUS_RIGHT:
+                    return findNextInputFocusInAbsoluteDirection(focusables, root, focused,
+                            focusedRect, direction);
+                default:
+                    throw new IllegalArgumentException("Unknown direction: " + direction);
+            }
+        } finally {
+            focusables.clear();
+        }
     }
 
-    private void setFocusTopLeft(ViewGroup root) {
+    /**
+     * Find the next view to take accessibility focus in root's descendants,
+     * starting from the view that currently is accessibility focused.
+     *
+     * @param root The root which also contains the focused view.
+     * @param focused The current accessibility focused view.
+     * @param direction Direction to look.
+     * @return The next focusable view, or null if none exists.
+     */
+    private View findNextAccessibilityFocus(ViewGroup root, View focused, int direction) {
+        switch (direction) {
+            case View.ACCESSIBILITY_FOCUS_IN:
+            case View.ACCESSIBILITY_FOCUS_OUT:
+            case View.ACCESSIBILITY_FOCUS_FORWARD:
+            case View.ACCESSIBILITY_FOCUS_BACKWARD: {
+                return findNextHierarchicalAcessibilityFocus(root, focused, direction);
+            }
+            case View.ACCESSIBILITY_FOCUS_LEFT:
+            case View.ACCESSIBILITY_FOCUS_RIGHT:
+            case View.ACCESSIBILITY_FOCUS_UP:
+            case View.ACCESSIBILITY_FOCUS_DOWN: {
+                return findNextDirectionalAccessibilityFocus(root, focused, direction);
+            }
+            default:
+                throw new IllegalArgumentException("Unknown direction: " + direction);
+        }
+    }
+
+    private View findNextHierarchicalAcessibilityFocus(ViewGroup root, View focused,
+            int direction) {
+        View current = (focused != null) ? focused : root;
+        switch (direction) {
+            case View.ACCESSIBILITY_FOCUS_IN: {
+                return findNextAccessibilityFocusIn(current);
+            }
+            case View.ACCESSIBILITY_FOCUS_OUT: {
+                return findNextAccessibilityFocusOut(current);
+            }
+            case View.ACCESSIBILITY_FOCUS_FORWARD: {
+                return findNextAccessibilityFocusForward(current);
+            }
+            case View.ACCESSIBILITY_FOCUS_BACKWARD: {
+                return findNextAccessibilityFocusBackward(current);
+            }
+        }
+        return null;
+    }
+
+    private View findNextDirectionalAccessibilityFocus(ViewGroup root, View focused,
+            int direction) {
+        ArrayList<View> focusables = mTempList;
+        focusables.clear();
+        root.addFocusables(focusables, direction, View.FOCUSABLES_ACCESSIBILITY);
+        Rect focusedRect = getFocusedRect(root, focused, direction);
+        final int inputFocusDirection = getCorrespondingInputFocusDirection(direction);
+        View next = findNextInputFocusInAbsoluteDirection(focusables, root,
+                focused, focusedRect, inputFocusDirection);
+        focusables.clear();
+        return next;
+    }
+
+    private View findNextInputFocusInRelativeDirection(ArrayList<View> focusables, ViewGroup root,
+            View focused, Rect focusedRect, int direction) {
+        try {
+            // Note: This sort is stable.
+            mSequentialFocusComparator.setRoot(root);
+            Collections.sort(focusables, mSequentialFocusComparator);
+        } finally {
+            mSequentialFocusComparator.recycle();
+        }
+
+        final int count = focusables.size();
+        switch (direction) {
+            case View.FOCUS_FORWARD:
+                return getForwardFocusable(root, focused, focusables, count);
+            case View.FOCUS_BACKWARD:
+                return getBackwardFocusable(root, focused, focusables, count);
+        }
+        return focusables.get(count - 1);
+    }
+
+    private void setFocusBottomRight(ViewGroup root) {
         final int rootBottom = root.getScrollY() + root.getHeight();
         final int rootRight = root.getScrollX() + root.getWidth();
         mFocusedRect.set(rootRight, rootBottom,
                 rootRight, rootBottom);
     }
 
-    private void setFocusBottomRight(ViewGroup root) {
+    private void setFocusTopLeft(ViewGroup root) {
         final int rootTop = root.getScrollY();
         final int rootLeft = root.getScrollX();
         mFocusedRect.set(rootLeft, rootTop, rootLeft, rootTop);
     }
 
-    /**
-     * Find the next view to take focus in root's descendants, searching from
-     * a particular rectangle in root's coordinates.
-     * @param root Contains focusedRect. Cannot be null.
-     * @param focusedRect The starting point of the search.
-     * @param direction Direction to look.
-     * @return The next focusable view, or null if none exists.
-     */
-    public View findNextFocusFromRect(ViewGroup root, Rect focusedRect, int direction) {
-        return findNextFocus(root, null, focusedRect, direction);
-    }
-
-    private View findNextFocus(ViewGroup root, View focused, Rect focusedRect, int direction) {
-        ArrayList<View> focusables = root.getFocusables(direction);
-        if (focusables.isEmpty()) {
-            // The focus cannot change.
-            return null;
-        }
-
-        if (direction == View.FOCUS_FORWARD || direction == View.FOCUS_BACKWARD) {
-            if (focused != null && !focusables.contains(focused)) {
-                // Add the currently focused view to the list to have it sorted
-                // along with the other views.
-                focusables.add(focused);
-            }
-
-            try {
-                // Note: This sort is stable.
-                mSequentialFocusComparator.setRoot(root);
-                Collections.sort(focusables, mSequentialFocusComparator);
-            } finally {
-                mSequentialFocusComparator.recycle();
-            }
-
-            final int count = focusables.size();
-            switch (direction) {
-                case View.FOCUS_FORWARD:
-                    return getForwardFocusable(root, focused, focusables, count);
-
-                case View.FOCUS_BACKWARD:
-                    return getBackwardFocusable(root, focused, focusables, count);
-            }
-            return null;
-        }
-
+    View findNextInputFocusInAbsoluteDirection(ArrayList<View> focusables, ViewGroup root, View focused,
+            Rect focusedRect, int direction) {
         // initialize the best candidate to something impossible
         // (so the first plausible view will become the best choice)
         mBestCandidateRect.set(focusedRect);
@@ -201,6 +294,140 @@
         return closest;
     }
 
+    private View findNextAccessibilityFocusIn(View view) {
+        // We have to traverse the full view tree to make sure
+        // we consider views in the order specified by their
+        // parent layout managers since some managers could be
+        // LTR while some could be RTL.
+        if (mTempStack == null) {
+            mTempStack = new Stack<View>();
+        }
+        Stack<View> fringe = mTempStack;
+        fringe.clear();
+        fringe.add(view);
+        while (!fringe.isEmpty()) {
+            View current = fringe.pop();
+            if (current.getAccessibilityNodeProvider() != null) {
+                fringe.clear();
+                return current;
+            }
+            if (current != view && current.includeForAccessibility()) {
+                fringe.clear();
+                return current;
+            }
+            if (current instanceof ViewGroup) {
+                ViewGroup currentGroup = (ViewGroup) current;
+                ChildListForAccessibility children = ChildListForAccessibility.obtain(
+                        currentGroup, true);
+                final int childCount = children.getChildCount();
+                for (int i = childCount - 1; i >= 0; i--) {
+                    fringe.push(children.getChildAt(i));
+                }
+                children.recycle();
+            }
+        }
+        return null;
+    }
+
+    private View findNextAccessibilityFocusOut(View view) {
+        ViewParent parent = view.getParentForAccessibility();
+        if (parent instanceof View) {
+            return (View) parent;
+        }
+        return null;
+    }
+
+    private View findNextAccessibilityFocusForward(View view) {
+        // We have to traverse the full view tree to make sure
+        // we consider views in the order specified by their
+        // parent layout managers since some managers could be
+        // LTR while some could be RTL.
+        View current = view;
+        while (current != null) {
+            ViewParent parent = current.getParent();
+            if (!(parent instanceof ViewGroup)) {
+                return null;
+            }
+            ViewGroup parentGroup = (ViewGroup) parent;
+            // Ask the parent to find a sibling after the current view
+            // that can take accessibility focus.
+            ChildListForAccessibility children = ChildListForAccessibility.obtain(
+                    parentGroup, true);
+            final int fromIndex = children.getChildIndex(current) + 1;
+            final int childCount = children.getChildCount();
+            for (int i = fromIndex; i < childCount; i++) {
+                View child = children.getChildAt(i);
+                View next = null;
+                if (child.getAccessibilityNodeProvider() != null) {
+                    next = child;
+                } else if (child.includeForAccessibility()) {
+                    next = child;
+                } else {
+                    next = findNextAccessibilityFocusIn(child);
+                }
+                if (next != null) {
+                    children.recycle();
+                    return next;
+                }
+            }
+            children.recycle();
+            // Reaching a regarded for accessibility predecessor without
+            // finding a next view to take focus means that at this level
+            // there is no next accessibility focusable sibling.
+            if (parentGroup.includeForAccessibility()) {
+                return null;
+            }
+            // Try asking a predecessor to find a focusable.
+            current = parentGroup;
+        }
+        return null;
+    }
+
+    private View findNextAccessibilityFocusBackward(View view) {
+        // We have to traverse the full view tree to make sure
+        // we consider views in the order specified by their
+        // parent layout managers since some managers could be
+        // LTR while some could be RTL.
+        View current = view;
+        while (current != null) {
+            ViewParent parent = current.getParent();
+            if (!(parent instanceof ViewGroup)) {
+                return null;
+            }
+            ViewGroup parentGroup = (ViewGroup) parent;
+            // Ask the parent to find a sibling after the current view
+            // to take accessibility focus
+            ChildListForAccessibility children = ChildListForAccessibility.obtain(
+                    parentGroup, true);
+            final int fromIndex = children.getChildIndex(current) - 1;
+            for (int i = fromIndex; i >= 0; i--) {
+                View child = children.getChildAt(i);
+                View next = null;
+                if (child.getAccessibilityNodeProvider() != null) {
+                    next = child;
+                } else if (child.includeForAccessibility()) {
+                    next = child;
+                } else {
+                    next = findNextAccessibilityFocusIn(child);
+                }
+                if (next != null) {
+                    children.recycle();
+                    return next;
+                }
+            }
+            children.recycle();
+            // Reaching a regarded for accessibility predecessor without
+            // finding a previous view to take focus means that at this level
+            // there is no previous accessibility focusable sibling.
+            if (parentGroup.includeForAccessibility()) {
+                return null;
+            }
+            // Try asking a predecessor to find a focusable.
+            current = parentGroup;
+        }
+        return null;
+    }
+
     private static View getForwardFocusable(ViewGroup root, View focused,
                                             ArrayList<View> focusables, int count) {
         return (root.isLayoutRtl()) ?
@@ -235,6 +462,47 @@
         return focusables.get(count - 1);
     }
 
+    private Rect getFocusedRect(ViewGroup root, View focused, int direction) {
+        Rect focusedRect = mFocusedRect;
+        if (focused != null) {
+            focused.getFocusedRect(focusedRect);
+            root.offsetDescendantRectToMyCoords(focused, focusedRect);
+        } else {
+            switch (direction) {
+                case View.FOCUS_RIGHT:
+                case View.FOCUS_DOWN:
+                    final int rootTop = root.getScrollY();
+                    final int rootLeft = root.getScrollX();
+                    focusedRect.set(rootLeft, rootTop, rootLeft, rootTop);
+                    break;
+
+                case View.FOCUS_LEFT:
+                case View.FOCUS_UP:
+                    final int rootBottom = root.getScrollY() + root.getHeight();
+                    final int rootRight = root.getScrollX() + root.getWidth();
+                    focusedRect.set(rootRight, rootBottom, rootRight, rootBottom);
+                    break;
+            }
+        }
+        return focusedRect;
+    }
+
+    private int getCorrespondingInputFocusDirection(int accessFocusDirection) {
+        switch (accessFocusDirection) {
+            case View.ACCESSIBILITY_FOCUS_LEFT:
+                return View.FOCUS_LEFT;
+            case View.ACCESSIBILITY_FOCUS_RIGHT:
+                return View.FOCUS_RIGHT;
+            case View.ACCESSIBILITY_FOCUS_UP:
+                return View.FOCUS_UP;
+            case View.ACCESSIBILITY_FOCUS_DOWN:
+                return View.FOCUS_DOWN;
+            default:
+                throw new IllegalArgumentException("Cannot map accessiblity focus"
+                        + " direction: " + accessFocusDirection);
+        }
+    }
+
     /**
      * Is rect1 a better candidate than rect2 for a focus search in a particular
      * direction from a source rect?  This is the core routine that determines
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 8fe8e40..b70d7b5 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -80,6 +80,8 @@
     void prepareAppTransition(int transit, boolean alwaysKeepCurrent);
     int getPendingAppTransition();
     void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim);
+    void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
+            int startHeight);
     void overridePendingAppTransitionThumb(in Bitmap srcThumb, int startX, int startY,
             IRemoteCallback startedCallback);
     void executeAppTransition();
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 4ebb679..4848a7a 100755
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -16,9 +16,12 @@
 
 package android.view;
 
+import android.content.Context;
 import android.hardware.input.InputManager;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.Vibrator;
+import android.os.NullVibrator;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -46,8 +49,11 @@
     private final int mSources;
     private final int mKeyboardType;
     private final KeyCharacterMap mKeyCharacterMap;
+    private final boolean mHasVibrator;
     private final ArrayList<MotionRange> mMotionRanges = new ArrayList<MotionRange>();
 
+    private Vibrator mVibrator; // guarded by mMotionRanges during initialization
+
     /**
      * A mask for input source classes.
      * 
@@ -304,7 +310,7 @@
 
     // Called by native code.
     private InputDevice(int id, int generation, String name, String descriptor, int sources,
-            int keyboardType, KeyCharacterMap keyCharacterMap) {
+            int keyboardType, KeyCharacterMap keyCharacterMap, boolean hasVibrator) {
         mId = id;
         mGeneration = generation;
         mName = name;
@@ -312,6 +318,7 @@
         mSources = sources;
         mKeyboardType = keyboardType;
         mKeyCharacterMap = keyCharacterMap;
+        mHasVibrator = hasVibrator;
     }
 
     private InputDevice(Parcel in) {
@@ -322,6 +329,7 @@
         mSources = in.readInt();
         mKeyboardType = in.readInt();
         mKeyCharacterMap = KeyCharacterMap.CREATOR.createFromParcel(in);
+        mHasVibrator = in.readInt() != 0;
 
         for (;;) {
             int axis = in.readInt();
@@ -522,6 +530,31 @@
     }
 
     /**
+     * Gets the vibrator service associated with the device, if there is one.
+     * Even if the device does not have a vibrator, the result is never null.
+     * Use {@link Vibrator#hasVibrator} to determine whether a vibrator is
+     * present.
+     *
+     * Note that the vibrator associated with the device may be different from
+     * the system vibrator.  To obtain an instance of the system vibrator instead, call
+     * {@link Context#getSystemService} with {@link Context#VIBRATOR_SERVICE} as argument.
+     *
+     * @return The vibrator service associated with the device, never null.
+     */
+    public Vibrator getVibrator() {
+        synchronized (mMotionRanges) {
+            if (mVibrator == null) {
+                if (mHasVibrator) {
+                    mVibrator = InputManager.getInstance().getInputDeviceVibrator(mId);
+                } else {
+                    mVibrator = NullVibrator.getInstance();
+                }
+            }
+            return mVibrator;
+        }
+    }
+
+    /**
      * Provides information about the range of values for a particular {@link MotionEvent} axis.
      *
      * @see InputDevice#getMotionRange(int)
@@ -617,6 +650,7 @@
         out.writeInt(mSources);
         out.writeInt(mKeyboardType);
         mKeyCharacterMap.writeToParcel(out, flags);
+        out.writeInt(mHasVibrator ? 1 : 0);
 
         final int numRanges = mMotionRanges.size();
         for (int i = 0; i < numRanges; i++) {
@@ -657,6 +691,8 @@
         }
         description.append("\n");
 
+        description.append("  Has Vibrator: ").append(mHasVibrator).append("\n");
+
         description.append("  Sources: 0x").append(Integer.toHexString(mSources)).append(" (");
         appendSourceDescriptionIfApplicable(description, SOURCE_KEYBOARD, "keyboard");
         appendSourceDescriptionIfApplicable(description, SOURCE_DPAD, "dpad");
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 32029ba..214dc5c 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -676,7 +676,6 @@
      *
      * @param surfaceTexture The {@link SurfaceTexture} that the view should use.
      * @see SurfaceTexture#detachFromGLContext()
-     * @hide
      */
     public void setSurfaceTexture(SurfaceTexture surfaceTexture) {
         if (surfaceTexture == null) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 1fa19d1..0ded5f9 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -24,6 +24,7 @@
 import android.graphics.Bitmap;
 import android.graphics.Camera;
 import android.graphics.Canvas;
+import android.graphics.Insets;
 import android.graphics.Interpolator;
 import android.graphics.LinearGradient;
 import android.graphics.Matrix;
@@ -975,6 +976,14 @@
     public static final int FOCUSABLES_TOUCH_MODE = 0x00000001;
 
     /**
+     * View flag indicating whether {@link #addFocusables(ArrayList, int, int)}
+     * should add only accessibility focusable Views.
+     *
+     * @hide
+     */
+    public static final int FOCUSABLES_ACCESSIBILITY = 0x00000002;
+
+    /**
      * Use with {@link #focusSearch(int)}. Move focus to the previous selectable
      * item.
      */
@@ -1006,6 +1015,54 @@
      */
     public static final int FOCUS_DOWN = 0x00000082;
 
+    // Accessibility focus directions.
+
+    /**
+     * The accessibility focus which is the current user position when
+     * interacting with the accessibility framework.
+     */
+    public static final int FOCUS_ACCESSIBILITY =  0x00001000;
+
+    /**
+     * Use with {@link #focusSearch(int)}. Move acessibility focus left.
+     */
+    public static final int ACCESSIBILITY_FOCUS_LEFT = FOCUS_LEFT | FOCUS_ACCESSIBILITY;
+
+    /**
+     * Use with {@link #focusSearch(int)}. Move acessibility focus up.
+     */
+    public static final int ACCESSIBILITY_FOCUS_UP = FOCUS_UP | FOCUS_ACCESSIBILITY;
+
+    /**
+     * Use with {@link #focusSearch(int)}. Move acessibility focus right.
+     */
+    public static final int ACCESSIBILITY_FOCUS_RIGHT = FOCUS_RIGHT | FOCUS_ACCESSIBILITY;
+
+    /**
+     * Use with {@link #focusSearch(int)}. Move acessibility focus down.
+     */
+    public static final int ACCESSIBILITY_FOCUS_DOWN = FOCUS_DOWN | FOCUS_ACCESSIBILITY;
+
+    /**
+     * Use with {@link #focusSearch(int)}. Move acessibility focus to the next view.
+     */
+    public static final int ACCESSIBILITY_FOCUS_FORWARD = FOCUS_FORWARD | FOCUS_ACCESSIBILITY;
+
+    /**
+     * Use with {@link #focusSearch(int)}. Move acessibility focus to the previous view.
+     */
+    public static final int ACCESSIBILITY_FOCUS_BACKWARD = FOCUS_BACKWARD | FOCUS_ACCESSIBILITY;
+
+    /**
+     * Use with {@link #focusSearch(int)}. Move acessibility focus in a view.
+     */
+    public static final int ACCESSIBILITY_FOCUS_IN = 0x00000004 | FOCUS_ACCESSIBILITY;
+
+    /**
+     * Use with {@link #focusSearch(int)}. Move acessibility focus out of a view.
+     */
+    public static final int ACCESSIBILITY_FOCUS_OUT = 0x00000008 | FOCUS_ACCESSIBILITY;
+
     /**
      * Bits of {@link #getMeasuredWidthAndState()} and
      * {@link #getMeasuredWidthAndState()} that provide the actual measured size.
@@ -1330,7 +1387,7 @@
         R.attr.state_accelerated,       VIEW_STATE_ACCELERATED,
         R.attr.state_hovered,           VIEW_STATE_HOVERED,
         R.attr.state_drag_can_accept,   VIEW_STATE_DRAG_CAN_ACCEPT,
-        R.attr.state_drag_hovered,      VIEW_STATE_DRAG_HOVERED,
+        R.attr.state_drag_hovered,      VIEW_STATE_DRAG_HOVERED
     };
 
     static {
@@ -1452,7 +1509,8 @@
             | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER
             | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT
             | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED
-            | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED;
+            | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED
+            | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED;
 
     /**
      * Temporary Rect currently for use in setBackground().  This will probably
@@ -1784,7 +1842,6 @@
      */
     private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT;
 
-
     /**
      * Indicates that the view is tracking some sort of transient state
      * that the app should not need to be aware of, but that the framework
@@ -1992,6 +2049,50 @@
     public static final int TEXT_ALIGNMENT_RESOLVED_DEFAULT =
             TEXT_ALIGNMENT_GRAVITY << TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT;
 
+    // Accessiblity constants for mPrivateFlags2
+
+    /**
+     * Shift for accessibility related bits in {@link #mPrivateFlags2}.
+     */
+    static final int IMPORTANT_FOR_ACCESSIBILITY_SHIFT = 20;
+
+    /**
+     * Automatically determine whether a view is important for accessibility.
+     */
+    public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0x00000000;
+
+    /**
+     * The view is important for accessibility.
+     */
+    public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 0x00000001;
+
+    /**
+     * The view is not important for accessibility.
+     */
+    public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 0x00000002;
+
+    /**
+     * The default whether the view is important for accessiblity.
+     */
+    static final int IMPORTANT_FOR_ACCESSIBILITY_DEFAULT = IMPORTANT_FOR_ACCESSIBILITY_AUTO;
+
+    /**
+     * Mask for obtainig the bits which specify how to determine
+     * whether a view is important for accessibility.
+     */
+    static final int IMPORTANT_FOR_ACCESSIBILITY_MASK = (IMPORTANT_FOR_ACCESSIBILITY_AUTO
+        | IMPORTANT_FOR_ACCESSIBILITY_YES | IMPORTANT_FOR_ACCESSIBILITY_NO)
+        << IMPORTANT_FOR_ACCESSIBILITY_SHIFT;
+
+    /**
+     * Flag indicating whether a view has accessibility focus.
+     */
+    static final int ACCESSIBILITY_FOCUSED = 0x00000040 << IMPORTANT_FOR_ACCESSIBILITY_SHIFT;
+
+    /**
+     * Flag indicating whether a view state for accessibility has changed.
+     */
+    static final int ACCESSIBILITY_STATE_CHANGED = 0x00000080 << IMPORTANT_FOR_ACCESSIBILITY_SHIFT;
 
     /* End of masks for mPrivateFlags2 */
 
@@ -2598,6 +2699,12 @@
     protected int mPaddingBottom;
 
     /**
+     * The layout insets in pixels, that is the distance in pixels between the
+     * visible edges of this view its bounds.
+     */
+    private Insets mLayoutInsets;
+
+    /**
      * Briefly describes the view and is primarily used for accessibility support.
      */
     private CharSequence mContentDescription;
@@ -2952,7 +3059,8 @@
         // Set layout and text direction defaults
         mPrivateFlags2 = (LAYOUT_DIRECTION_DEFAULT << LAYOUT_DIRECTION_MASK_SHIFT) |
                 (TEXT_DIRECTION_DEFAULT << TEXT_DIRECTION_MASK_SHIFT) |
-                (TEXT_ALIGNMENT_DEFAULT << TEXT_ALIGNMENT_MASK_SHIFT);
+                (TEXT_ALIGNMENT_DEFAULT << TEXT_ALIGNMENT_MASK_SHIFT) |
+                (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << IMPORTANT_FOR_ACCESSIBILITY_SHIFT);
         mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
         setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS);
         mUserPaddingStart = -1;
@@ -3340,6 +3448,9 @@
                     final int textAlignment = a.getInt(attr, TEXT_ALIGNMENT_DEFAULT);
                     mPrivateFlags2 |= TEXT_ALIGNMENT_FLAGS[textAlignment];
                     break;
+                case R.styleable.View_importantForAccessibility:
+                    setImportantForAccessibility(a.getInt(attr,
+                            IMPORTANT_FOR_ACCESSIBILITY_DEFAULT));
             }
         }
 
@@ -3970,6 +4081,10 @@
 
             onFocusChanged(true, direction, previouslyFocusedRect);
             refreshDrawableState();
+
+            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+                notifyAccessibilityStateChanged();
+            }
         }
     }
 
@@ -4050,16 +4165,21 @@
             }
 
             onFocusChanged(false, 0, null);
+
             refreshDrawableState();
 
             ensureInputFocusOnFirstFocusable();
+
+            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+                notifyAccessibilityStateChanged();
+            }
         }
     }
 
     void ensureInputFocusOnFirstFocusable() {
         View root = getRootView();
         if (root != null) {
-            root.requestFocus(FOCUS_FORWARD);
+            root.requestFocus();
         }
     }
 
@@ -4077,6 +4197,10 @@
 
             onFocusChanged(false, 0, null);
             refreshDrawableState();
+
+            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+                notifyAccessibilityStateChanged();
+            }
         }
     }
 
@@ -4127,7 +4251,10 @@
      */
     protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
         if (gainFocus) {
-            sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
+            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+                sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
+                requestAccessibilityFocus();
+            }
         }
 
         InputMethodManager imm = InputMethodManager.peekInstance();
@@ -4237,7 +4364,7 @@
      */
     public void sendAccessibilityEventUnchecked(AccessibilityEvent event) {
         if (mAccessibilityDelegate != null) {
-           mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event);
+            mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event);
         } else {
             sendAccessibilityEventUncheckedInternal(event);
         }
@@ -4257,6 +4384,31 @@
         if ((event.getEventType() & POPULATING_ACCESSIBILITY_EVENT_TYPES) != 0) {
             dispatchPopulateAccessibilityEvent(event);
         }
+        // Intercept accessibility focus events fired by virtual nodes to keep
+        // track of accessibility focus position in such nodes.
+        final int eventType = event.getEventType();
+        switch (eventType) {
+            case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
+                final long virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
+                        event.getSourceNodeId());
+                if (virtualNodeId != AccessibilityNodeInfo.UNDEFINED) {
+                    ViewRootImpl viewRootImpl = getViewRootImpl();
+                    if (viewRootImpl != null) {
+                        viewRootImpl.setAccessibilityFocusedHost(this);
+                    }
+                }
+            } break;
+            case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
+                final long virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
+                        event.getSourceNodeId());
+                if (virtualNodeId != AccessibilityNodeInfo.UNDEFINED) {
+                    ViewRootImpl viewRootImpl = getViewRootImpl();
+                    if (viewRootImpl != null) {
+                        viewRootImpl.setAccessibilityFocusedHost(null);
+                    }
+                }
+            } break;
+        }
         // In the beginning we called #isShown(), so we know that getParent() is not null.
         getParent().requestSendAccessibilityEvent(this, event);
     }
@@ -4399,7 +4551,7 @@
         event.setContentDescription(mContentDescription);
 
         if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED && mAttachInfo != null) {
-            ArrayList<View> focusablesTempList = mAttachInfo.mFocusablesTempList;
+            ArrayList<View> focusablesTempList = mAttachInfo.mTempArrayList;
             getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD,
                     FOCUSABLES_ALL);
             event.setItemCount(focusablesTempList.size());
@@ -4488,10 +4640,9 @@
         info.setBoundsInScreen(bounds);
 
         if ((mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
-            ViewParent parent = getParent();
+            ViewParent parent = getParentForAccessibility();
             if (parent instanceof View) {
-                View parentView = (View) parent;
-                info.setParent(parentView);
+                info.setParent((View) parent);
             }
         }
 
@@ -4503,6 +4654,7 @@
         info.setClickable(isClickable());
         info.setFocusable(isFocusable());
         info.setFocused(isFocused());
+        info.setAccessibilityFocused(isAccessibilityFocused());
         info.setSelected(isSelected());
         info.setLongClickable(isLongClickable());
 
@@ -4597,10 +4749,11 @@
      * true for views that do not have textual representation (For example,
      * ImageButton).
      *
-     * @return The content descriptiopn.
+     * @return The content description.
      *
      * @attr ref android.R.styleable#View_contentDescription
      */
+    @ViewDebug.ExportedProperty(category = "accessibility")
     public CharSequence getContentDescription() {
         return mContentDescription;
     }
@@ -5650,8 +5803,9 @@
      * Adds any focusable views that are descendants of this view (possibly
      * including this view if it is focusable itself) to views. This method
      * adds all focusable views regardless if we are in touch mode or
-     * only views focusable in touch mode if we are in touch mode depending on
-     * the focusable mode paramater.
+     * only views focusable in touch mode if we are in touch mode or
+     * only views that can take accessibility focus if accessibility is enabeld
+     * depending on the focusable mode paramater.
      *
      * @param views Focusable views found so far or null if all we are interested is
      *        the number of focusables.
@@ -5662,18 +5816,24 @@
      * @see #FOCUSABLES_TOUCH_MODE
      */
     public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
+        if (views == null) {
+            return;
+        }
+        if ((focusableMode & FOCUSABLES_ACCESSIBILITY) == FOCUSABLES_ACCESSIBILITY) {
+            if (AccessibilityManager.getInstance(mContext).isEnabled()
+                    && includeForAccessibility()) {
+                views.add(this);
+                return;
+            }
+        }
         if (!isFocusable()) {
             return;
         }
-
-        if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE &&
-                isInTouchMode() && !isFocusableInTouchMode()) {
+        if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE
+                && isInTouchMode() && !isFocusableInTouchMode()) {
             return;
         }
-
-        if (views != null) {
-            views.add(this);
-        }
+        views.add(this);
     }
 
     /**
@@ -5734,6 +5894,149 @@
     }
 
     /**
+     * Returns whether this View is accessibility focused.
+     *
+     * @return True if this View is accessibility focused.
+     */
+    boolean isAccessibilityFocused() {
+        return (mPrivateFlags2 & ACCESSIBILITY_FOCUSED) != 0;
+    }
+
+    /**
+     * Call this to try to give accessibility focus to this view.
+     *
+     * A view will not actually take focus if {@link AccessibilityManager#isEnabled()}
+     * returns false or the view is no visible or the view already has accessibility
+     * focus.
+     *
+     * See also {@link #focusSearch(int)}, which is what you call to say that you
+     * have focus, and you want your parent to look for the next one.
+     *
+     * @return Whether this view actually took accessibility focus.
+     *
+     * @hide
+     */
+    public boolean requestAccessibilityFocus() {
+        if (!AccessibilityManager.getInstance(mContext).isEnabled()) {
+            return false;
+        }
+        if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) {
+            return false;
+        }
+        if ((mPrivateFlags2 & ACCESSIBILITY_FOCUSED) == 0) {
+            mPrivateFlags2 |= ACCESSIBILITY_FOCUSED;
+            ViewRootImpl viewRootImpl = getViewRootImpl();
+            if (viewRootImpl != null) {
+                viewRootImpl.setAccessibilityFocusedHost(this);
+            }
+            invalidate();
+            sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
+            notifyAccessibilityStateChanged();
+            // Try to give input focus to this view - not a descendant.
+            requestFocusNoSearch(View.FOCUS_DOWN, null);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Call this to try to clear accessibility focus of this view.
+     *
+     * See also {@link #focusSearch(int)}, which is what you call to say that you
+     * have focus, and you want your parent to look for the next one.
+     *
+     * @hide
+     */
+    public void clearAccessibilityFocus() {
+        if ((mPrivateFlags2 & ACCESSIBILITY_FOCUSED) != 0) {
+            mPrivateFlags2 &= ~ACCESSIBILITY_FOCUSED;
+            ViewRootImpl viewRootImpl = getViewRootImpl();
+            if (viewRootImpl != null) {
+                viewRootImpl.setAccessibilityFocusedHost(null);
+            }
+            invalidate();
+            sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
+            notifyAccessibilityStateChanged();
+            // Try to move accessibility focus to the input focus.
+            View rootView = getRootView();
+            if (rootView != null) {
+                View inputFocus = rootView.findFocus();
+                if (inputFocus != null) {
+                    inputFocus.requestAccessibilityFocus();
+                }
+            }
+        }
+    }
+
+    /**
+     * Find the best view to take accessibility focus from a hover.
+     * This function finds the deepest actionable view and if that
+     * fails ask the parent to take accessibility focus from hover.
+     *
+     * @param x The X hovered location in this view coorditantes.
+     * @param y The Y hovered location in this view coorditantes.
+     * @return Whether the request was handled.
+     *
+     * @hide
+     */
+    public boolean requestAccessibilityFocusFromHover(float x, float y) {
+        if (onRequestAccessibilityFocusFromHover(x, y)) {
+            return true;
+        }
+        ViewParent parent = mParent;
+        if (parent instanceof View) {
+            View parentView = (View) parent;
+
+            float[] position = mAttachInfo.mTmpTransformLocation;
+            position[0] = x;
+            position[1] = y;
+
+            // Compensate for the transformation of the current matrix.
+            if (!hasIdentityMatrix()) {
+                getMatrix().mapPoints(position);
+            }
+
+            // Compensate for the parent scroll and the offset
+            // of this view stop from the parent top.
+            position[0] += mLeft - parentView.mScrollX;
+            position[1] += mTop - parentView.mScrollY;
+
+            return parentView.requestAccessibilityFocusFromHover(position[0], position[1]);
+        }
+        return false;
+    }
+
+    /**
+     * Requests to give this View focus from hover.
+     *
+     * @param x The X hovered location in this view coorditantes.
+     * @param y The Y hovered location in this view coorditantes.
+     * @return Whether the request was handled.
+     *
+     * @hide
+     */
+    public boolean onRequestAccessibilityFocusFromHover(float x, float y) {
+        if (includeForAccessibility()
+                && (isActionableForAccessibility() || hasListenersForAccessibility())) {
+            return requestAccessibilityFocus();
+        }
+        return false;
+    }
+
+    /**
+     * Clears accessibility focus without calling any callback methods
+     * normally invoked in {@link #clearAccessibilityFocus()}. This method
+     * is used for clearing accessibility focus when giving this focus to
+     * another view.
+     */
+    void clearAccessibilityFocusNoCallbacks() {
+        if ((mPrivateFlags2 & ACCESSIBILITY_FOCUSED) != 0) {
+            mPrivateFlags2 &= ~ACCESSIBILITY_FOCUSED;
+            invalidate();
+        }
+    }
+
+    /**
      * Call this to try to give focus to a specific view or to one of its
      * descendants.
      *
@@ -5753,7 +6056,6 @@
         return requestFocus(View.FOCUS_DOWN);
     }
 
-
     /**
      * Call this to try to give focus to a specific view or to one of its
      * descendants and give it a hint about what direction focus is heading.
@@ -5805,6 +6107,10 @@
      * @return Whether this view or one of its descendants actually took focus.
      */
     public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
+        return requestFocusNoSearch(direction, previouslyFocusedRect);
+    }
+
+    private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) {
         // need to be focusable
         if ((mViewFlags & FOCUSABLE_MASK) != FOCUSABLE ||
                 (mViewFlags & VISIBILITY_MASK) != VISIBLE) {
@@ -5864,6 +6170,248 @@
     }
 
     /**
+     * Gets the mode for determining 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.
+     *
+     * @return The mode for determining whether a View is important for accessibility.
+     *
+     * @attr ref android.R.styleable#View_importantForAccessibility
+     *
+     * @see #IMPORTANT_FOR_ACCESSIBILITY_YES
+     * @see #IMPORTANT_FOR_ACCESSIBILITY_NO
+     * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO
+     */
+    @ViewDebug.ExportedProperty(category = "accessibility", mapping = {
+            @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_AUTO,
+                    to = "IMPORTANT_FOR_ACCESSIBILITY_AUTO"),
+            @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_YES,
+                    to = "IMPORTANT_FOR_ACCESSIBILITY_YES"),
+            @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO,
+                    to = "IMPORTANT_FOR_ACCESSIBILITY_NO")
+        })
+    public int getImportantForAccessibility() {
+        return (mPrivateFlags2 & IMPORTANT_FOR_ACCESSIBILITY_MASK)
+                >> IMPORTANT_FOR_ACCESSIBILITY_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.
+     *
+     * @param mode How to determine whether this view is important for accessibility.
+     *
+     * @attr ref android.R.styleable#View_importantForAccessibility
+     *
+     * @see #IMPORTANT_FOR_ACCESSIBILITY_YES
+     * @see #IMPORTANT_FOR_ACCESSIBILITY_NO
+     * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO
+     */
+    public void setImportantForAccessibility(int mode) {
+        if (mode != getImportantForAccessibility()) {
+            mPrivateFlags2 &= ~IMPORTANT_FOR_ACCESSIBILITY_MASK;
+            mPrivateFlags2 |= (mode << IMPORTANT_FOR_ACCESSIBILITY_SHIFT)
+                    & IMPORTANT_FOR_ACCESSIBILITY_MASK;
+            notifyAccessibilityStateChanged();
+        }
+    }
+
+    /**
+     * Gets whether this view should be exposed for accessibility.
+     *
+     * @return Whether the view is exposed for accessibility.
+     *
+     * @hide
+     */
+    public boolean isImportantForAccessibility() {
+        final int mode = (mPrivateFlags2 & IMPORTANT_FOR_ACCESSIBILITY_MASK)
+                >> IMPORTANT_FOR_ACCESSIBILITY_SHIFT;
+        switch (mode) {
+            case IMPORTANT_FOR_ACCESSIBILITY_YES:
+                return true;
+            case IMPORTANT_FOR_ACCESSIBILITY_NO:
+                return false;
+            case IMPORTANT_FOR_ACCESSIBILITY_AUTO:
+                return isActionableForAccessibility() || hasListenersForAccessibility();
+            default:
+                throw new IllegalArgumentException("Unknow important for accessibility mode: "
+                        + mode);
+        }
+    }
+
+    /**
+     * Gets the parent for accessibility purposes. Note that the parent for
+     * accessibility is not necessary the immediate parent. It is the first
+     * predecessor that is important for accessibility.
+     *
+     * @return The parent for accessibility purposes.
+     */
+    public ViewParent getParentForAccessibility() {
+        if (mParent instanceof View) {
+            View parentView = (View) mParent;
+            if (parentView.includeForAccessibility()) {
+                return mParent;
+            } else {
+                return mParent.getParentForAccessibility();
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Adds the children of a given View for accessibility. Since some Views are
+     * not important for accessibility the children for accessibility are not
+     * necessarily direct children of the riew, rather they are the first level of
+     * descendants important for accessibility.
+     *
+     * @param children The list of children for accessibility.
+     */
+    public void addChildrenForAccessibility(ArrayList<View> children) {
+        if (includeForAccessibility()) {
+            children.add(this);
+        }
+    }
+
+    /**
+     * Whether to regard this view for accessibility. A view is regarded for
+     * accessibility if it is important for accessibility or the querying
+     * accessibility service has explicitly requested that view not
+     * important for accessibility are regarded.
+     *
+     * @return Whether to regard the view for accessibility.
+     */
+    boolean includeForAccessibility() {
+        if (mAttachInfo != null) {
+            if (!mAttachInfo.mIncludeNotImportantViews) {
+                return isImportantForAccessibility();
+            } else {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns whether the View is considered actionable from
+     * accessibility perspective. Such view are important for
+     * accessiiblity.
+     *
+     * @return True if the view is actionable for accessibility.
+     */
+    private boolean isActionableForAccessibility() {
+        return (isClickable() || isLongClickable() || isFocusable());
+    }
+
+    /**
+     * Returns whether the View has registered callbacks wich makes it
+     * important for accessiiblity.
+     *
+     * @return True if the view is actionable for accessibility.
+     */
+    private boolean hasListenersForAccessibility() {
+        ListenerInfo info = getListenerInfo();
+        return mTouchDelegate != null || info.mOnKeyListener != null
+                || info.mOnTouchListener != null || info.mOnGenericMotionListener != null
+                || info.mOnHoverListener != null || info.mOnDragListener != null;
+    }
+
+    /**
+     * Notifies accessibility services that some view's important for
+     * accessibility state has changed. Note that such notifications
+     * are made 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.
+     *
+     * @hide
+     *
+     * TODO: Makse sure this method is called for any view state change
+     *       that is interesting for accessilility purposes.
+     */
+    public void notifyAccessibilityStateChanged() {
+        if ((mPrivateFlags2 & ACCESSIBILITY_STATE_CHANGED) == 0) {
+            mPrivateFlags2 |= ACCESSIBILITY_STATE_CHANGED;
+            if (mParent != null) {
+                mParent.childAccessibilityStateChanged(this);
+            }
+        }
+    }
+
+    /**
+     * Reset the state indicating the this view has requested clients
+     * interested in its accessiblity state to be notified.
+     *
+     * @hide
+     */
+    public void resetAccessibilityStateChanged() {
+        mPrivateFlags2 &= ~ACCESSIBILITY_STATE_CHANGED;
+    }
+
+    /**
+     * Performs the specified accessibility action on the view. For
+     * possible accessibility actions look at {@link AccessibilityNodeInfo}.
+     *
+     * @param action The action to perform.
+     * @return Whether the action was performed.
+     */
+    public boolean performAccessibilityAction(int action) {
+        switch (action) {
+            case AccessibilityNodeInfo.ACTION_CLICK: {
+                final long now = SystemClock.uptimeMillis();
+                // Send down.
+                MotionEvent event = MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN,
+                        getWidth() / 2, getHeight() / 2, 0);
+                onTouchEvent(event);
+                // Send up.
+                event.setAction(MotionEvent.ACTION_UP);
+                onTouchEvent(event);
+                // Clean up.
+                event.recycle();
+            } break;
+            case AccessibilityNodeInfo.ACTION_FOCUS: {
+                if (!hasFocus()) {
+                    // Get out of touch mode since accessibility
+                    // wants to move focus around.
+                    getViewRootImpl().ensureTouchMode(false);
+                    return requestFocus();
+                }
+            } break;
+            case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: {
+                if (hasFocus()) {
+                    clearFocus();
+                    return !isFocused();
+                }
+            } break;
+            case AccessibilityNodeInfo.ACTION_SELECT: {
+                if (!isSelected()) {
+                    setSelected(true);
+                    return isSelected();
+                }
+            } break;
+            case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: {
+                if (isSelected()) {
+                    setSelected(false);
+                    return !isSelected();
+                }
+            } break;
+            case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: {
+                if (!isAccessibilityFocused()) {
+                    return requestAccessibilityFocus();
+                }
+            } break;
+            case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: {
+                if (isAccessibilityFocused()) {
+                    clearAccessibilityFocus();
+                    return true;
+                }
+            } break;
+        }
+        return false;
+    }
+
+    /**
      * @hide
      */
     public void dispatchStartTemporaryDetach() {
@@ -6757,21 +7305,27 @@
         // The root view may receive hover (or touch) events that are outside the bounds of
         // the window.  This code ensures that we only send accessibility events for
         // hovers that are actually within the bounds of the root view.
-        final int action = event.getAction();
+        final int action = event.getActionMasked();
         if (!mSendingHoverAccessibilityEvents) {
             if ((action == MotionEvent.ACTION_HOVER_ENTER
                     || action == MotionEvent.ACTION_HOVER_MOVE)
                     && !hasHoveredChild()
                     && pointInView(event.getX(), event.getY())) {
-                mSendingHoverAccessibilityEvents = true;
                 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
+                mSendingHoverAccessibilityEvents = true;
+                requestAccessibilityFocusFromHover((int) event.getX(), (int) event.getY());
             }
         } else {
             if (action == MotionEvent.ACTION_HOVER_EXIT
-                    || (action == MotionEvent.ACTION_HOVER_MOVE
+                    || (action == MotionEvent.ACTION_MOVE
                             && !pointInView(event.getX(), event.getY()))) {
                 mSendingHoverAccessibilityEvents = false;
                 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
+                // If the window does not have input focus we take away accessibility
+                // focus as soon as the user stop hovering over the view.
+                if (!mAttachInfo.mHasWindowFocus) {
+                    getViewRootImpl().setAccessibilityFocusedHost(null);
+                }
             }
         }
 
@@ -6795,6 +7349,7 @@
             dispatchGenericMotionEventInternal(event);
             return true;
         }
+
         return false;
     }
 
@@ -6806,7 +7361,6 @@
      */
     private boolean isHoverable() {
         final int viewFlags = mViewFlags;
-        //noinspection SimplifiableIfStatement
         if ((viewFlags & ENABLED_MASK) == DISABLED) {
             return false;
         }
@@ -7130,6 +7684,9 @@
                  */
                 if (mParent != null) mParent.focusableViewAvailable(this);
             }
+            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+                notifyAccessibilityStateChanged();
+            }
         }
 
         if ((flags & VISIBILITY_MASK) == VISIBLE) {
@@ -7161,6 +7718,7 @@
 
             if (((mViewFlags & VISIBILITY_MASK) == GONE)) {
                 if (hasFocus()) clearFocus();
+                clearAccessibilityFocus();
                 destroyDrawingCache();
                 if (mParent instanceof View) {
                     // GONE views noop invalidation, so invalidate the parent
@@ -7185,9 +7743,10 @@
             mPrivateFlags |= DRAWN;
 
             if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE) && hasFocus()) {
-                // root view becoming invisible shouldn't clear focus
+                // root view becoming invisible shouldn't clear focus and accessibility focus
                 if (getRootView() != this) {
                     clearFocus();
+                    clearAccessibilityFocus();
                 }
             }
             if (mAttachInfo != null) {
@@ -7241,6 +7800,12 @@
                 mParent.recomputeViewAttributes(this);
             }
         }
+
+        if (AccessibilityManager.getInstance(mContext).isEnabled()
+                && ((changed & FOCUSABLE) != 0 || (changed & CLICKABLE) != 0
+                        || (changed & LONG_CLICKABLE) != 0 || (changed & ENABLED) != 0)) {
+            notifyAccessibilityStateChanged();
+        }
     }
 
     /**
@@ -7319,6 +7884,7 @@
      * @param canvas the canvas on which to draw the view
      */
     protected void dispatchDraw(Canvas canvas) {
+
     }
 
     /**
@@ -10227,6 +10793,7 @@
         resolvePadding();
         resolveTextDirection();
         resolveTextAlignment();
+        clearAccessibilityFocus();
         if (isFocused()) {
             InputMethodManager imm = InputMethodManager.peekInstance();
             imm.focusIn(this);
@@ -10457,6 +11024,8 @@
 
         resetResolvedLayoutDirection();
         resetResolvedTextAlignment();
+        resetAccessibilityStateChanged();
+        clearAccessibilityFocus();
     }
 
     /**
@@ -13273,6 +13842,29 @@
     }
 
     /**
+     * @hide
+     */
+    public Insets getLayoutInsets() {
+        if (mLayoutInsets == null) {
+            if (mBackground == null) {
+                mLayoutInsets = Insets.NONE;
+            } else {
+                Rect insetRect = new Rect();
+                boolean hasInsets = mBackground.getLayoutInsets(insetRect);
+                mLayoutInsets = hasInsets ? Insets.of(insetRect) : Insets.NONE;
+            }
+        }
+        return mLayoutInsets;
+    }
+
+    /**
+     * @hide
+     */
+    public void setLayoutInsets(Insets layoutInsets) {
+        mLayoutInsets = layoutInsets;
+    }
+
+    /**
      * Changes the selection state of this view. A view can be selected or not.
      * Note that selection is not the same as focus. Views are typically
      * selected in the context of an AdapterView like ListView or GridView;
@@ -13287,6 +13879,9 @@
             invalidate(true);
             refreshDrawableState();
             dispatchSetSelected(selected);
+            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+                notifyAccessibilityStateChanged();
+            }
         }
     }
 
@@ -13456,7 +14051,7 @@
             position[1] += view.mTop;
 
             viewParent = view.mParent;
-        }
+         }
 
         if (viewParent instanceof ViewRootImpl) {
             // *cough*
@@ -16291,7 +16886,7 @@
         /**
          * Temporary list for use in collecting focusable descendents of a view.
          */
-        final ArrayList<View> mFocusablesTempList = new ArrayList<View>(24);
+        final ArrayList<View> mTempArrayList = new ArrayList<View>(24);
 
         /**
          * The id of the window for accessibility purposes.
@@ -16299,6 +16894,17 @@
         int mAccessibilityWindowId = View.NO_ID;
 
         /**
+         * Whether to ingore not exposed for accessibility Views when
+         * reporting the view tree to accessibility services.
+         */
+        boolean mIncludeNotImportantViews;
+
+        /**
+         * The drawable for highlighting accessibility focus.
+         */
+        Drawable mAccessibilityFocusDrawable;
+
+        /**
          * Creates a new set of attachment information with the specified
          * events handler and thread.
          *
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 9d06145..9134966 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -197,7 +197,7 @@
      * gesture and the touch up event of a subsequent tap for the latter tap to be
      * considered as a tap i.e. to perform a click.
      */
-    private static final int TOUCH_EXPLORATION_TAP_SLOP = 80;
+    private static final int TOUCH_EXPLORE_TAP_SLOP = 80;
 
     /**
      * Delay before dispatching a recurring accessibility event in milliseconds.
@@ -238,7 +238,7 @@
     private final int mDoubleTapTouchSlop;
     private final int mPagingTouchSlop;
     private final int mDoubleTapSlop;
-    private final int mScaledTouchExplorationTapSlop;
+    private final int mScaledTouchExploreTapSlop;
     private final int mWindowTouchSlop;
     private final int mMaximumDrawingCacheSize;
     private final int mOverscrollDistance;
@@ -265,7 +265,7 @@
         mDoubleTapTouchSlop = DOUBLE_TAP_TOUCH_SLOP;
         mPagingTouchSlop = PAGING_TOUCH_SLOP;
         mDoubleTapSlop = DOUBLE_TAP_SLOP;
-        mScaledTouchExplorationTapSlop = TOUCH_EXPLORATION_TAP_SLOP;
+        mScaledTouchExploreTapSlop = TOUCH_EXPLORE_TAP_SLOP;
         mWindowTouchSlop = WINDOW_TOUCH_SLOP;
         //noinspection deprecation
         mMaximumDrawingCacheSize = MAXIMUM_DRAWING_CACHE_SIZE;
@@ -302,7 +302,7 @@
         mMaximumFlingVelocity = (int) (density * MAXIMUM_FLING_VELOCITY + 0.5f);
         mScrollbarSize = (int) (density * SCROLL_BAR_SIZE + 0.5f);
         mDoubleTapSlop = (int) (sizeAndDensity * DOUBLE_TAP_SLOP + 0.5f);
-        mScaledTouchExplorationTapSlop = (int) (density * TOUCH_EXPLORATION_TAP_SLOP + 0.5f);
+        mScaledTouchExploreTapSlop = (int) (density * TOUCH_EXPLORE_TAP_SLOP + 0.5f);
         mWindowTouchSlop = (int) (sizeAndDensity * WINDOW_TOUCH_SLOP + 0.5f);
 
         final Display display = WindowManagerImpl.getDefault().getDefaultDisplay();
@@ -559,8 +559,8 @@
      *
      * @hide
      */
-    public int getScaledTouchExplorationTapSlop() {
-        return mScaledTouchExplorationTapSlop;
+    public int getScaledTouchExploreTapSlop() {
+        return mScaledTouchExploreTapSlop;
     }
 
     /**
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 8f6badf..cb37a1c 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -141,6 +141,18 @@
     public static final String DEBUG_LATENCY_TAG = "ViewLatency";
 
     /**
+     * Enables detailed logging of accessibility focus operations.
+     * @hide
+     */
+    public static final boolean DEBUG_ACCESSIBILITY_FOCUS = false;
+
+    /**
+     * Tag for logging of accessibility focus operations
+     * @hide
+     */
+    public static final String DEBUG_ACCESSIBILITY_FOCUS_TAG = "AccessibilityFocus";
+
+    /**
      * <p>Enables or disables views consistency check. Even when this property is enabled,
      * view consistency checks happen only if {@link false} is set
      * to true. The value of this property can be configured externally in one of the
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 121b544..6371963 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -45,6 +45,7 @@
 import com.android.internal.util.Predicate;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashSet;
 
 /**
@@ -169,6 +170,12 @@
      */
     protected int mGroupFlags;
 
+    /*
+     * THe layout mode: either {@link #UNDEFINED_LAYOUT_MODE}, {@link #COMPONENT_BOUNDS} or
+     * {@link #LAYOUT_BOUNDS}
+     */
+    private int mLayoutMode = UNDEFINED_LAYOUT_MODE;
+
     /**
      * NOTE: If you change the flags below make sure to reflect the changes
      *       the DisplayList class
@@ -334,6 +341,22 @@
      */
     public static final int PERSISTENT_ALL_CACHES = 0x3;
 
+    // Layout Modes
+
+    private static final int UNDEFINED_LAYOUT_MODE = -1;
+
+    /**
+     * This constant is a {@link #setLayoutMode(int) layoutMode}.
+     * Component bounds are the raw values of {@link #getLeft() left}, {@link #getTop() top},
+     * {@link #getRight() right} and {@link #getBottom() bottom}.
+     */
+    public static final int COMPONENT_BOUNDS = 0;
+
+    /**
+     * This constant is a {@link #setLayoutMode(int) layoutMode}.
+     */
+    public static final int LAYOUT_BOUNDS = 1;
+
     /**
      * We clip to padding when FLAG_CLIP_TO_PADDING and FLAG_PADDING_NOT_NULL
      * are set at the same time.
@@ -611,13 +634,13 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
-        ViewParent parent = getParent();
+        ViewParent parent = mParent;
         if (parent == null) {
             return false;
         }
         final boolean propagate = onRequestSendAccessibilityEvent(child, event);
-        //noinspection SimplifiableIfStatement
         if (!propagate) {
             return false;
         }
@@ -1552,6 +1575,33 @@
         return mFirstHoverTarget != null;
     }
 
+    @Override
+    public void addChildrenForAccessibility(ArrayList<View> childrenForAccessibility) {
+        View[] children = mChildren;
+        final int childrenCount = mChildrenCount;
+        for (int i = 0; i < childrenCount; i++) {
+            View child = children[i];
+            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
+                    && (child.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
+                if (child.includeForAccessibility()) {
+                    childrenForAccessibility.add(child);
+                } else {
+                    child.addChildrenForAccessibility(childrenForAccessibility);
+                }
+            }
+        }
+    }
+
+    /**
+     * @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.
@@ -2294,33 +2344,43 @@
 
     @Override
     boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
-        boolean handled = super.dispatchPopulateAccessibilityEventInternal(event);
-        if (handled) {
-            return handled;
+        boolean handled = false;
+        if (includeForAccessibility()) {
+            handled = super.dispatchPopulateAccessibilityEventInternal(event);
+            if (handled) {
+                return handled;
+            }
         }
         // Let our children have a shot in populating the event.
-        for (int i = 0, count = getChildCount(); i < count; i++) {
-            View child = getChildAt(i);
+        ChildListForAccessibility children = ChildListForAccessibility.obtain(this, true);
+        final int childCount = children.getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View child = children.getChildAt(i);
             if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
-                handled = getChildAt(i).dispatchPopulateAccessibilityEvent(event);
+                handled = child.dispatchPopulateAccessibilityEvent(event);
                 if (handled) {
+                    children.recycle();
                     return handled;
                 }
             }
         }
+        children.recycle();
         return false;
     }
 
     @Override
     void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(ViewGroup.class.getName());
-        for (int i = 0, count = mChildrenCount; i < count; i++) {
-            View child = mChildren[i];
-            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
-                    && (child.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
+        if (mAttachInfo != null) {
+            ArrayList<View> childrenForAccessibility = mAttachInfo.mTempArrayList;
+            childrenForAccessibility.clear();
+            addChildrenForAccessibility(childrenForAccessibility);
+            final int childrenForAccessibilityCount = childrenForAccessibility.size();
+            for (int i = 0; i < childrenForAccessibilityCount; i++) {
+                View child = childrenForAccessibility.get(i);
                 info.addChild(child);
             }
+            childrenForAccessibility.clear();
         }
     }
 
@@ -2331,6 +2391,20 @@
     }
 
     /**
+     * @hide
+     */
+    @Override
+    public void resetAccessibilityStateChanged() {
+        super.resetAccessibilityStateChanged();
+        View[] children = mChildren;
+        final int childCount = mChildrenCount;
+        for (int i = 0; i < childCount; i++) {
+            View child = children[i];
+            child.resetAccessibilityStateChanged();
+        }
+    }
+
+    /**
      * {@inheritDoc}
      */
     @Override
@@ -3400,6 +3474,10 @@
             clearChildFocus(view);
             ensureInputFocusOnFirstFocusable();
         }
+
+        if (view.isAccessibilityFocused()) {
+            view.clearAccessibilityFocus();
+        }
     }
 
     /**
@@ -4129,6 +4207,9 @@
     @Override
     public final void layout(int l, int t, int r, int b) {
         if (mTransition == null || !mTransition.isChangingLayout()) {
+            if (mTransition != null) {
+                mTransition.layoutChange(this);
+            }
             super.layout(l, t, r, b);
         } else {
             // record the fact that we noop'd it; request layout when transition finishes
@@ -4368,6 +4449,50 @@
     }
 
     /**
+     * Returns the basis of alignment during the layout of this view group:
+     * either {@link #COMPONENT_BOUNDS} or {@link #LAYOUT_BOUNDS}.
+     *
+     * @return the layout mode to use during layout operations
+     *
+     * @see #setLayoutMode(int)
+     */
+    public int getLayoutMode() {
+        if (mLayoutMode == UNDEFINED_LAYOUT_MODE) {
+            ViewParent parent = getParent();
+            if (parent instanceof ViewGroup) {
+                ViewGroup viewGroup = (ViewGroup) parent;
+                return viewGroup.getLayoutMode();
+            } else {
+                int targetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
+                boolean preJellyBean = targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN;
+                return preJellyBean ? COMPONENT_BOUNDS : LAYOUT_BOUNDS;
+            }
+
+        }
+        return mLayoutMode;
+    }
+
+    /**
+     * Sets the basis of alignment during alignment of this view group.
+     * Valid values are either {@link #COMPONENT_BOUNDS} or {@link #LAYOUT_BOUNDS}.
+     * <p>
+     * The default is to query the property of the parent if this view group has a parent.
+     * If this ViewGroup is the root of the view hierarchy the default
+     * value is {@link #LAYOUT_BOUNDS} for target SDK's greater than JellyBean,
+     * {@link #LAYOUT_BOUNDS} otherwise.
+     *
+     * @param layoutMode the layout mode to use during layout operations
+     *
+     * @see #getLayoutMode()
+     */
+    public void setLayoutMode(int layoutMode) {
+        if (mLayoutMode != layoutMode) {
+            mLayoutMode = layoutMode;
+            requestLayout();
+        }
+    }
+
+    /**
      * Returns a new set of layout parameters based on the supplied attributes set.
      *
      * @param attrs the attributes to build the layout parameters from
@@ -5622,4 +5747,218 @@
             }
         }
     }
+
+    /**
+     * Pooled class that orderes the children of a ViewGroup from start
+     * to end based on how they are laid out and the layout direction.
+     */
+    static class ChildListForAccessibility {
+
+        private static final int MAX_POOL_SIZE = 32;
+
+        private static final Object sPoolLock = new Object();
+
+        private static ChildListForAccessibility sPool;
+
+        private static int sPoolSize;
+
+        private boolean mIsPooled;
+
+        private ChildListForAccessibility mNext;
+
+        private final ArrayList<View> mChildren = new ArrayList<View>();
+
+        private final ArrayList<ViewLocationHolder> mHolders = new ArrayList<ViewLocationHolder>();
+
+        public static ChildListForAccessibility obtain(ViewGroup parent, boolean sort) {
+            ChildListForAccessibility list = null;
+            synchronized (sPoolLock) {
+                if (sPool != null) {
+                    list = sPool;
+                    sPool = list.mNext;
+                    list.mNext = null;
+                    list.mIsPooled = false;
+                    sPoolSize--;
+                } else {
+                    list = new ChildListForAccessibility();
+                }
+                list.init(parent, sort);
+                return list;
+            }
+        }
+
+        public void recycle() {
+            if (mIsPooled) {
+                throw new IllegalStateException("Instance already recycled.");
+            }
+            clear();
+            if (sPoolSize < MAX_POOL_SIZE) {
+                mNext = sPool;
+                mIsPooled = true;
+                sPool = this;
+                sPoolSize++;
+            }
+        }
+
+        public int getChildCount() {
+            return mChildren.size();
+        }
+
+        public View getChildAt(int index) {
+            return mChildren.get(index);
+        }
+
+        public int getChildIndex(View child) {
+            return mChildren.indexOf(child);
+        }
+
+        private void init(ViewGroup parent, boolean sort) {
+            ArrayList<View> children = mChildren;
+            final int childCount = parent.getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                View child = parent.getChildAt(i);
+                children.add(child);
+            }
+            if (sort) {
+                ArrayList<ViewLocationHolder> holders = mHolders;
+                for (int i = 0; i < childCount; i++) {
+                    View child = children.get(i);
+                    ViewLocationHolder holder = ViewLocationHolder.obtain(parent, child);
+                    holders.add(holder);
+                }
+                Collections.sort(holders);
+                for (int i = 0; i < childCount; i++) {
+                    ViewLocationHolder holder = holders.get(i);
+                    children.set(i, holder.mView);
+                    holder.recycle();
+                }
+                holders.clear();
+            }
+        }
+
+        private void clear() {
+            mChildren.clear();
+        }
+    }
+
+    /**
+     * Pooled class that holds a View and its location with respect to
+     * a specified root. This enables sorting of views based on their
+     * coordinates without recomputing the position relative to the root
+     * on every comparison.
+     */
+    static class ViewLocationHolder implements Comparable<ViewLocationHolder> {
+
+        private static final int MAX_POOL_SIZE = 32;
+
+        private static final Object sPoolLock = new Object();
+
+        private static ViewLocationHolder sPool;
+
+        private static int sPoolSize;
+
+        private boolean mIsPooled;
+
+        private ViewLocationHolder mNext;
+
+        private final Rect mLocation = new Rect();
+
+        public View mView;
+
+        private int mLayoutDirection;
+
+        public static ViewLocationHolder obtain(ViewGroup root, View view) {
+            ViewLocationHolder holder = null;
+            synchronized (sPoolLock) {
+                if (sPool != null) {
+                    holder = sPool;
+                    sPool = holder.mNext;
+                    holder.mNext = null;
+                    holder.mIsPooled = false;
+                    sPoolSize--;
+                } else {
+                    holder = new ViewLocationHolder();
+                }
+                holder.init(root, view);
+                return holder;
+            }
+        }
+
+        public void recycle() {
+            if (mIsPooled) {
+                throw new IllegalStateException("Instance already recycled.");
+            }
+            clear();
+            if (sPoolSize < MAX_POOL_SIZE) {
+                mNext = sPool;
+                mIsPooled = true;
+                sPool = this;
+                sPoolSize++;
+            }
+        }
+
+        @Override
+        public int compareTo(ViewLocationHolder another) {
+            // This instance is greater than an invalid argument.
+            if (another == null) {
+                return 1;
+            }
+            if (getClass() != another.getClass()) {
+                return 1;
+            }
+            // First is above second.
+            if (mLocation.bottom - another.mLocation.top <= 0) {
+                return -1;
+            }
+            // First is below second.
+            if (mLocation.top - another.mLocation.bottom >= 0) {
+                return 1;
+            }
+            // LTR
+            if (mLayoutDirection == LAYOUT_DIRECTION_LTR) {
+                final int leftDifference = mLocation.left - another.mLocation.left;
+                // First more to the left than second.
+                if (leftDifference != 0) {
+                    return leftDifference;
+                }
+            } else { // RTL
+                final int rightDifference = mLocation.right - another.mLocation.right;
+                // First more to the right than second.
+                if (rightDifference != 0) {
+                    return -rightDifference;
+                }
+            }
+            // Break tie by top.
+            final int topDiference = mLocation.top - another.mLocation.top;
+            if (topDiference != 0) {
+                return topDiference;
+            }
+            // Break tie by height.
+            final int heightDiference = mLocation.height() - another.mLocation.height();
+            if (heightDiference != 0) {
+                return -heightDiference;
+            }
+            // Break tie by width.
+            final int widthDiference = mLocation.width() - another.mLocation.width();
+            if (widthDiference != 0) {
+                return -widthDiference;
+            }
+            // Return nondeterministically one of them since we do
+            // not want to ignore any views.
+            return 1;
+        }
+
+        private void init(ViewGroup root, View view) {
+            Rect viewLocation = mLocation;
+            view.getDrawingRect(viewLocation);
+            root.offsetDescendantRectToMyCoords(view, viewLocation);
+            mView = view;
+            mLayoutDirection = root.getResolvedLayoutDirection();
+        }
+
+        private void clear() {
+            mView = null;
+            mLocation.set(0, 0, 0, 0);
+        }
+    }
 }
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index 75e9151..ddff91d 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -277,4 +277,22 @@
      * View.fitSystemWindows(Rect)} be performed.
      */
     public void requestFitSystemWindows();
+
+    /**
+     * Gets the parent of a given View for accessibility. Since some Views are not
+     * exposed to the accessibility layer the parent for accessibility is not
+     * necessarily the direct parent of the View, rather it is a predecessor.
+     *
+     * @return The parent or <code>null</code> if no such is found.
+     */
+    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
+     */
+    public void childAccessibilityStateChanged(View child);
 }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 2e3ff38..1472993 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -37,6 +37,7 @@
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.Region;
+import android.graphics.drawable.Drawable;
 import android.media.AudioManager;
 import android.os.Binder;
 import android.os.Bundle;
@@ -56,17 +57,11 @@
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
-import android.util.Pool;
-import android.util.Poolable;
-import android.util.PoolableManager;
-import android.util.Pools;
 import android.util.Slog;
-import android.util.SparseLongArray;
 import android.util.TypedValue;
 import android.view.View.AttachInfo;
 import android.view.View.MeasureSpec;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityInteractionClient;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
 import android.view.accessibility.AccessibilityNodeInfo;
@@ -79,6 +74,7 @@
 import android.view.inputmethod.InputMethodManager;
 import android.widget.Scroller;
 
+import com.android.internal.R;
 import com.android.internal.policy.PolicyManager;
 import com.android.internal.view.BaseSurfaceHolder;
 import com.android.internal.view.IInputMethodCallback;
@@ -89,9 +85,7 @@
 import java.io.OutputStream;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.HashSet;
 
 /**
  * The top of a view hierarchy, implementing the needed protocol between View
@@ -181,6 +175,10 @@
     View mFocusedView;
     View mRealFocusedView;  // this is not set to null in touch mode
     View mOldFocusedView;
+
+    View mAccessibilityFocusedHost;
+    AccessibilityNodeInfo mAccessibilityFocusedVirtualView;
+
     int mViewVisibility;
     boolean mAppVisible = true;
     int mOrigWindowType = -1;
@@ -321,7 +319,7 @@
 
     SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent;
 
-    AccessibilityNodePrefetcher mAccessibilityNodePrefetcher;
+    HashSet<View> mTempHashSet;
 
     private final int mDensity;
 
@@ -630,6 +628,10 @@
                 if (mAccessibilityManager.isEnabled()) {
                     mAccessibilityInteractionConnectionManager.ensureConnection();
                 }
+
+                if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
+                    view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+                }
             }
         }
     }
@@ -1418,6 +1420,8 @@
 
                             mView.draw(layerCanvas);
 
+                            drawAccessibilityFocusedDrawableIfNeeded(layerCanvas);
+
                             mResizeBufferStartTime = SystemClock.uptimeMillis();
                             mResizeBufferDuration = mView.getResources().getInteger(
                                     com.android.internal.R.integer.config_mediumAnimTime);
@@ -1712,7 +1716,7 @@
             attachInfo.mTreeObserver.dispatchOnGlobalLayout();
 
             if (AccessibilityManager.getInstance(host.mContext).isEnabled()) {
-                postSendWindowContentChangedCallback();
+                postSendWindowContentChangedCallback(mView);
             }
         }
 
@@ -1880,6 +1884,7 @@
             mResizePaint.setAlpha(mResizeAlpha);
             canvas.drawHardwareLayer(mResizeBuffer, 0.0f, mHardwareYOffset, mResizePaint);
         }
+        drawAccessibilityFocusedDrawableIfNeeded(canvas);
     }
 
     /**
@@ -2234,6 +2239,8 @@
 
                 mView.draw(canvas);
 
+                drawAccessibilityFocusedDrawableIfNeeded(canvas);
+
                 if (ViewDebug.DEBUG_LATENCY) {
                     long now = System.nanoTime();
                     Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- draw() took "
@@ -2274,6 +2281,64 @@
         return true;
     }
 
+    /**
+     * We want to draw a highlight around the current accessibility focused.
+     * Since adding a style for all possible view is not a viable option we
+     * have this specialized drawing method.
+     *
+     * Note: We are doing this here to be able to draw the highlight for
+     *       virtual views in addition to real ones.
+     *
+     * @param canvas The canvas on which to draw.
+     */
+    private void drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas) {
+        if (!AccessibilityManager.getInstance(mView.mContext).isEnabled()) {
+            return;
+        }
+        if (mAccessibilityFocusedHost == null || mAccessibilityFocusedHost.mAttachInfo == null) {
+            return;
+        }
+        Drawable drawable = getAccessibilityFocusedDrawable();
+        if (drawable == null) {
+            return;
+        }
+        AccessibilityNodeProvider provider =
+            mAccessibilityFocusedHost.getAccessibilityNodeProvider();
+        Rect bounds = mView.mAttachInfo.mTmpInvalRect;
+        if (provider == null) {
+            mAccessibilityFocusedHost.getDrawingRect(bounds);
+            if (mView instanceof ViewGroup) {
+                ViewGroup viewGroup = (ViewGroup) mView;
+                viewGroup.offsetDescendantRectToMyCoords(mAccessibilityFocusedHost, bounds);
+            }
+        } else {
+            if (mAccessibilityFocusedVirtualView == null) {
+                mAccessibilityFocusedVirtualView = provider.findAccessibilitiyFocus(View.NO_ID);
+            }
+            mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds);
+            bounds.offset(-mAttachInfo.mWindowLeft, -mAttachInfo.mWindowTop);
+        }
+        drawable.setBounds(bounds);
+        drawable.draw(canvas);
+    }
+
+    private Drawable getAccessibilityFocusedDrawable() {
+        if (mAttachInfo != null) {
+            // Lazily load the accessibility focus drawable.
+            if (mAttachInfo.mAccessibilityFocusDrawable == null) {
+                TypedValue value = new TypedValue();
+                final boolean resolved = mView.mContext.getTheme().resolveAttribute(
+                        R.attr.accessibilityFocusedDrawable, value, true);
+                if (resolved) {
+                    mAttachInfo.mAccessibilityFocusDrawable =
+                        mView.mContext.getResources().getDrawable(value.resourceId);
+                }
+            }
+            return mAttachInfo.mAccessibilityFocusDrawable;
+        }
+        return null;
+    }
+
     void invalidateDisplayLists() {
         final ArrayList<DisplayList> displayLists = mDisplayLists;
         final int count = displayLists.size();
@@ -2407,6 +2472,14 @@
         return handled;
     }
 
+    void setAccessibilityFocusedHost(View host) {
+        if (mAccessibilityFocusedHost != null && mAccessibilityFocusedVirtualView == null) {
+            mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks();
+        }
+        mAccessibilityFocusedHost = host;
+        mAccessibilityFocusedVirtualView = null;
+    }
+
     public void requestChildFocus(View child, View focused) {
         checkThread();
 
@@ -2437,9 +2510,13 @@
         mFocusedView = mRealFocusedView = null;
     }
 
+    @Override
+    public ViewParent getParentForAccessibility() {
+        return null;
+    }
+
     public void focusableViewAvailable(View v) {
         checkThread();
-
         if (mView != null) {
             if (!mView.hasFocus()) {
                 v.requestFocus();
@@ -2547,7 +2624,7 @@
     /**
      * Return true if child is an ancestor of parent, (or equal to the parent).
      */
-    private static boolean isViewDescendantOf(View child, View parent) {
+    static boolean isViewDescendantOf(View child, View parent) {
         if (child == parent) {
             return true;
         }
@@ -2585,13 +2662,9 @@
     private final static int MSG_DISPATCH_DRAG_LOCATION_EVENT = 16;
     private final static int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17;
     private final static int MSG_UPDATE_CONFIGURATION = 18;
-    private final static int MSG_PERFORM_ACCESSIBILITY_ACTION = 19;
-    private final static int MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID = 20;
-    private final static int MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID = 21;
-    private final static int MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT = 22;
-    private final static int MSG_PROCESS_INPUT_EVENTS = 23;
-    private final static int MSG_DISPATCH_SCREEN_STATE = 24;
-    private final static int MSG_INVALIDATE_DISPLAY_LIST = 25;
+    private final static int MSG_PROCESS_INPUT_EVENTS = 19;
+    private final static int MSG_DISPATCH_SCREEN_STATE = 20;
+    private final static int MSG_INVALIDATE_DISPLAY_LIST = 21;
 
     final class ViewRootHandler extends Handler {
         @Override
@@ -2633,14 +2706,6 @@
                     return "MSG_DISPATCH_SYSTEM_UI_VISIBILITY";
                 case MSG_UPDATE_CONFIGURATION:
                     return "MSG_UPDATE_CONFIGURATION";
-                case MSG_PERFORM_ACCESSIBILITY_ACTION:
-                    return "MSG_PERFORM_ACCESSIBILITY_ACTION";
-                case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID:
-                    return "MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID";
-                case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID:
-                    return "MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID";
-                case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT:
-                    return "MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT";
                 case MSG_PROCESS_INPUT_EVENTS:
                     return "MSG_PROCESS_INPUT_EVENTS";
                 case MSG_DISPATCH_SCREEN_STATE:
@@ -2770,8 +2835,28 @@
                         mHasHadWindowFocus = true;
                     }
 
-                    if (hasWindowFocus && mView != null && mAccessibilityManager.isEnabled()) {
-                        mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+                    if (mView != null && mAccessibilityManager.isEnabled()) {
+                        if (hasWindowFocus) {
+                            mView.sendAccessibilityEvent(
+                                    AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+                            // Give accessibility focus to the view that has input
+                            // focus if such, otherwise to the first one.
+                            if (mView instanceof ViewGroup) {
+                                ViewGroup viewGroup = (ViewGroup) mView;
+                                View focused = viewGroup.findFocus();
+                                if (focused != null) {
+                                    focused.requestAccessibilityFocus();
+                                }
+                            }
+                            // There is no accessibility focus, despite our effort
+                            // above, now just give it to the first view.
+                            if (mAccessibilityFocusedHost == null) {
+                                mView.requestAccessibilityFocus();
+                            }
+                        } else {
+                            // Clear accessibility focus when the window loses input focus.
+                            setAccessibilityFocusedHost(null);
+                        }
                     }
                 }
             } break;
@@ -2828,30 +2913,6 @@
                 }
                 updateConfiguration(config, false);
             } break;
-            case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID: {
-                if (mView != null) {
-                    getAccessibilityInteractionController()
-                        .findAccessibilityNodeInfoByAccessibilityIdUiThread(msg);
-                }
-            } break;
-            case MSG_PERFORM_ACCESSIBILITY_ACTION: {
-                if (mView != null) {
-                    getAccessibilityInteractionController()
-                        .perfromAccessibilityActionUiThread(msg);
-                }
-            } break;
-            case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID: {
-                if (mView != null) {
-                    getAccessibilityInteractionController()
-                        .findAccessibilityNodeInfoByViewIdUiThread(msg);
-                }
-            } break;
-            case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT: {
-                if (mView != null) {
-                    getAccessibilityInteractionController()
-                        .findAccessibilityNodeInfosByTextUiThread(msg);
-                }
-            } break;
             case MSG_DISPATCH_SCREEN_STATE: {
                 if (mView != null) {
                     handleScreenStateChange(msg.arg1 == 1);
@@ -2916,29 +2977,29 @@
                 // be when the window is first being added, and mFocused isn't
                 // set yet.
                 final View focused = mView.findFocus();
-                if (focused != null && !focused.isFocusableInTouchMode()) {
-
+                if (focused != null) {
+                    if (focused.isFocusableInTouchMode()) {
+                        return true;
+                    }
                     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
-                        mView.unFocus();
-                        mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(focused, null);
-                        mFocusedView = null;
-                        mOldFocusedView = null;
-                        return true;
                     }
                 }
+                // nothing appropriate to have focus in touch mode, clear it out
+                mView.unFocus();
+                mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(focused, null);
+                mFocusedView = null;
+                mOldFocusedView = null;
+                return true;
             }
         }
         return false;
     }
 
-
     /**
      * Find an ancestor of focused that wants focus after its descendants and is
      * focusable in touch mode.
@@ -2964,25 +3025,45 @@
 
     private boolean leaveTouchMode() {
         if (mView != null) {
+            boolean inputFocusValid = false;
             if (mView.hasFocus()) {
                 // i learned the hard way to not trust mFocusedView :)
                 mFocusedView = mView.findFocus();
                 if (!(mFocusedView instanceof ViewGroup)) {
                     // some view has focus, let it keep it
-                    return false;
-                } else if (((ViewGroup)mFocusedView).getDescendantFocusability() !=
+                    inputFocusValid = true;
+                } else if (((ViewGroup) mFocusedView).getDescendantFocusability() !=
                         ViewGroup.FOCUS_AFTER_DESCENDANTS) {
                     // some view group has focus, and doesn't prefer its children
                     // over itself for focus, so let them keep it.
-                    return false;
+                    inputFocusValid = true;
                 }
             }
-
-            // find the best view to give focus to in this brave new non-touch-mode
-            // world
-            final View focused = focusSearch(null, View.FOCUS_DOWN);
-            if (focused != null) {
-                return focused.requestFocus(View.FOCUS_DOWN);
+            // In accessibility mode we always have a view that has the
+            // accessibility focus and input focus follows it, i.e. we
+            // try to give input focus to the accessibility focused view.
+            if (!AccessibilityManager.getInstance(mView.mContext).isEnabled()) {
+                // If the current input focus is not valid, find the best view to give
+                // focus to in this brave new non-touch-mode world.
+                if (!inputFocusValid) {
+                    final View focused = focusSearch(null, View.FOCUS_DOWN);
+                    if (focused != null) {
+                        return focused.requestFocus(View.FOCUS_DOWN);
+                    }
+                }
+            } else {
+                // If the current input focus is not valid clear it but do not
+                // give it to another view since the accessibility focus is
+                // leading now and the input one follows.
+                if (!inputFocusValid) {
+                    if (mFocusedView != null) {
+                        mView.unFocus();
+                        mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(mFocusedView, null);
+                        mFocusedView = null;
+                        mOldFocusedView = null;
+                        return true;
+                    }
+                }
             }
         }
         return false;
@@ -3487,37 +3568,36 @@
         if (event.getAction() == KeyEvent.ACTION_DOWN) {
             int direction = 0;
             switch (event.getKeyCode()) {
-            case KeyEvent.KEYCODE_DPAD_LEFT:
-                if (event.hasNoModifiers()) {
-                    direction = View.FOCUS_LEFT;
-                }
-                break;
-            case KeyEvent.KEYCODE_DPAD_RIGHT:
-                if (event.hasNoModifiers()) {
-                    direction = View.FOCUS_RIGHT;
-                }
-                break;
-            case KeyEvent.KEYCODE_DPAD_UP:
-                if (event.hasNoModifiers()) {
-                    direction = View.FOCUS_UP;
-                }
-                break;
-            case KeyEvent.KEYCODE_DPAD_DOWN:
-                if (event.hasNoModifiers()) {
-                    direction = View.FOCUS_DOWN;
-                }
-                break;
-            case KeyEvent.KEYCODE_TAB:
-                if (event.hasNoModifiers()) {
-                    direction = View.FOCUS_FORWARD;
-                } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
-                    direction = View.FOCUS_BACKWARD;
-                }
-                break;
+                case KeyEvent.KEYCODE_DPAD_LEFT:
+                    if (event.hasNoModifiers()) {
+                        direction = View.FOCUS_LEFT;
+                    }
+                    break;
+                case KeyEvent.KEYCODE_DPAD_RIGHT:
+                    if (event.hasNoModifiers()) {
+                        direction = View.FOCUS_RIGHT;
+                    }
+                    break;
+                case KeyEvent.KEYCODE_DPAD_UP:
+                    if (event.hasNoModifiers()) {
+                        direction = View.FOCUS_UP;
+                    }
+                    break;
+                case KeyEvent.KEYCODE_DPAD_DOWN:
+                    if (event.hasNoModifiers()) {
+                        direction = View.FOCUS_DOWN;
+                    }
+                    break;
+                case KeyEvent.KEYCODE_TAB:
+                    if (event.hasNoModifiers()) {
+                        direction = View.FOCUS_FORWARD;
+                    } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
+                        direction = View.FOCUS_BACKWARD;
+                    }
+                    break;
             }
-
             if (direction != 0) {
-                View focused = mView != null ? mView.findFocus() : null;
+                View focused = mView.findFocus();
                 if (focused != null) {
                     View v = focused.focusSearch(direction);
                     if (v != null && v != focused) {
@@ -3532,8 +3612,8 @@
                                     v, mTempRect);
                         }
                         if (v.requestFocus(direction, mTempRect)) {
-                            playSoundEffect(
-                                    SoundEffectConstants.getContantForFocusDirection(direction));
+                            playSoundEffect(SoundEffectConstants
+                                    .getContantForFocusDirection(direction));
                             finishInputEvent(q, true);
                             return;
                         }
@@ -3683,22 +3763,11 @@
                     + " called when there is no mView");
         }
         if (mAccessibilityInteractionController == null) {
-            mAccessibilityInteractionController = new AccessibilityInteractionController();
+            mAccessibilityInteractionController = new AccessibilityInteractionController(this);
         }
         return mAccessibilityInteractionController;
     }
 
-    public AccessibilityNodePrefetcher getAccessibilityNodePrefetcher() {
-        if (mView == null) {
-            throw new IllegalStateException("getAccessibilityNodePrefetcher"
-                    + " called when there is no mView");
-        }
-        if (mAccessibilityNodePrefetcher == null) {
-            mAccessibilityNodePrefetcher = new AccessibilityNodePrefetcher();
-        }
-        return mAccessibilityNodePrefetcher;
-    }
-
     private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
             boolean insetsPending) throws RemoteException {
 
@@ -4375,15 +4444,19 @@
      * This event is send at most once every
      * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}.
      */
-    private void postSendWindowContentChangedCallback() {
+    private void postSendWindowContentChangedCallback(View source) {
         if (mSendWindowContentChangedAccessibilityEvent == null) {
             mSendWindowContentChangedAccessibilityEvent =
                 new SendWindowContentChangedAccessibilityEvent();
         }
-        if (!mSendWindowContentChangedAccessibilityEvent.mIsPending) {
-            mSendWindowContentChangedAccessibilityEvent.mIsPending = true;
+        View oldSource = mSendWindowContentChangedAccessibilityEvent.mSource;
+        if (oldSource == null) {
+            mSendWindowContentChangedAccessibilityEvent.mSource = source;
             mHandler.postDelayed(mSendWindowContentChangedAccessibilityEvent,
                     ViewConfiguration.getSendRecurringAccessibilityEventsInterval());
+        } else {
+            View newSource = getCommonPredecessor(oldSource, source);
+            mSendWindowContentChangedAccessibilityEvent.mSource = newSource;
         }
     }
 
@@ -4419,6 +4492,46 @@
         return true;
     }
 
+    @Override
+    public void childAccessibilityStateChanged(View child) {
+        postSendWindowContentChangedCallback(child);
+    }
+
+    private View getCommonPredecessor(View first, View second) {
+        if (mAttachInfo != null) {
+            if (mTempHashSet == null) {
+                mTempHashSet = new HashSet<View>();
+            }
+            HashSet<View> seen = mTempHashSet;
+            seen.clear();
+            View firstCurrent = first;
+            while (firstCurrent != null) {
+                seen.add(firstCurrent);
+                ViewParent firstCurrentParent = firstCurrent.mParent;
+                if (firstCurrentParent instanceof View) {
+                    firstCurrent = (View) firstCurrentParent;
+                } else {
+                    firstCurrent = null;
+                }
+            }
+            View secondCurrent = second;
+            while (secondCurrent != null) {
+                if (seen.contains(secondCurrent)) {
+                    seen.clear();
+                    return secondCurrent;
+                }
+                ViewParent secondCurrentParent = secondCurrent.mParent;
+                if (secondCurrentParent instanceof View) {
+                    secondCurrent = (View) secondCurrentParent;
+                } else {
+                    secondCurrent = null;
+                }
+            }
+            seen.clear();
+        }
+        return null;
+    }
+
     void checkThread() {
         if (mThread != Thread.currentThread()) {
             throw new CalledFromWrongThreadException(
@@ -4953,6 +5066,7 @@
                 }
             } else {
                 ensureNoConnection();
+                setAccessibilityFocusedHost(null);
             }
         }
 
@@ -4991,14 +5105,15 @@
             mViewRootImpl = new WeakReference<ViewRootImpl>(viewRootImpl);
         }
 
+        @Override
         public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId,
                 int interactionId, IAccessibilityInteractionConnectionCallback callback,
-                int prefetchFlags, int interrogatingPid, long interrogatingTid) {
+                int flags, int interrogatingPid, long interrogatingTid) {
             ViewRootImpl viewRootImpl = mViewRootImpl.get();
             if (viewRootImpl != null && viewRootImpl.mView != null) {
                 viewRootImpl.getAccessibilityInteractionController()
                     .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId,
-                        interactionId, callback, prefetchFlags, interrogatingPid, interrogatingTid);
+                        interactionId, callback, flags, interrogatingPid, interrogatingTid);
             } else {
                 // We cannot make the call and notify the caller so it does not wait.
                 try {
@@ -5009,16 +5124,17 @@
             }
         }
 
+        @Override
         public void performAccessibilityAction(long accessibilityNodeId, int action,
                 int interactionId, IAccessibilityInteractionConnectionCallback callback,
-                int interogatingPid, long interrogatingTid) {
+                int flags, int interogatingPid, long interrogatingTid) {
             ViewRootImpl viewRootImpl = mViewRootImpl.get();
             if (viewRootImpl != null && viewRootImpl.mView != null) {
                 viewRootImpl.getAccessibilityInteractionController()
                     .performAccessibilityActionClientThread(accessibilityNodeId, action,
-                            interactionId, callback, interogatingPid, interrogatingTid);
+                            interactionId, callback, flags, interogatingPid, interrogatingTid);
             } else {
-                // We cannot make the call and notify the caller so it does not
+                // We cannot make the call and notify the caller so it does not wait.
                 try {
                     callback.setPerformAccessibilityActionResult(false, interactionId);
                 } catch (RemoteException re) {
@@ -5027,16 +5143,17 @@
             }
         }
 
+        @Override
         public void findAccessibilityNodeInfoByViewId(long accessibilityNodeId, int viewId,
                 int interactionId, IAccessibilityInteractionConnectionCallback callback,
-                int interrogatingPid, long interrogatingTid) {
+                int flags, int interrogatingPid, long interrogatingTid) {
             ViewRootImpl viewRootImpl = mViewRootImpl.get();
             if (viewRootImpl != null && viewRootImpl.mView != null) {
                 viewRootImpl.getAccessibilityInteractionController()
                     .findAccessibilityNodeInfoByViewIdClientThread(accessibilityNodeId, viewId,
-                            interactionId, callback, interrogatingPid, interrogatingTid);
+                            interactionId, callback, flags, interrogatingPid, interrogatingTid);
             } else {
-                // We cannot make the call and notify the caller so it does not
+                // We cannot make the call and notify the caller so it does not wait.
                 try {
                     callback.setFindAccessibilityNodeInfoResult(null, interactionId);
                 } catch (RemoteException re) {
@@ -5045,16 +5162,17 @@
             }
         }
 
+        @Override
         public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text,
                 int interactionId, IAccessibilityInteractionConnectionCallback callback,
-                int interrogatingPid, long interrogatingTid) {
+                int flags, int interrogatingPid, long interrogatingTid) {
             ViewRootImpl viewRootImpl = mViewRootImpl.get();
             if (viewRootImpl != null && viewRootImpl.mView != null) {
                 viewRootImpl.getAccessibilityInteractionController()
                     .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text,
-                            interactionId, callback, interrogatingPid, interrogatingTid);
+                            interactionId, callback, flags, interrogatingPid, interrogatingTid);
             } else {
-                // We cannot make the call and notify the caller so it does not
+                // We cannot make the call and notify the caller so it does not wait.
                 try {
                     callback.setFindAccessibilityNodeInfosResult(null, interactionId);
                 } catch (RemoteException re) {
@@ -5062,606 +5180,54 @@
                 }
             }
         }
-    }
 
-    /**
-     * Computes whether a view is visible on the screen.
-     *
-     * @param view The view to check.
-     * @return Whether the view is visible on the screen.
-     */
-    private boolean isDisplayedOnScreen(View view) {
-        return (view.mAttachInfo != null
-                && view.mAttachInfo.mWindowVisibility == View.VISIBLE
-                && view.getVisibility() == View.VISIBLE
-                && view.getGlobalVisibleRect(mTempRect));
-    }
-
-    /**
-     * Class for managing accessibility interactions initiated from the system
-     * and targeting the view hierarchy. A *ClientThread method is to be
-     * called from the interaction connection this ViewAncestor gives the
-     * system to talk to it and a corresponding *UiThread method that is executed
-     * on the UI thread.
-     */
-    final class AccessibilityInteractionController {
-        private static final int POOL_SIZE = 5;
-
-        private ArrayList<AccessibilityNodeInfo> mTempAccessibilityNodeInfoList =
-            new ArrayList<AccessibilityNodeInfo>();
-
-        // Reusable poolable arguments for interacting with the view hierarchy
-        // to fit more arguments than Message and to avoid sharing objects between
-        // two messages since several threads can send messages concurrently.
-        private final Pool<SomeArgs> mPool = Pools.synchronizedPool(Pools.finitePool(
-                new PoolableManager<SomeArgs>() {
-                    public SomeArgs newInstance() {
-                        return new SomeArgs();
-                    }
-
-                    public void onAcquired(SomeArgs info) {
-                        /* do nothing */
-                    }
-
-                    public void onReleased(SomeArgs info) {
-                        info.clear();
-                    }
-                }, POOL_SIZE)
-        );
-
-        public class SomeArgs implements Poolable<SomeArgs> {
-            private SomeArgs mNext;
-            private boolean mIsPooled;
-
-            public Object arg1;
-            public Object arg2;
-            public int argi1;
-            public int argi2;
-            public int argi3;
-
-            public SomeArgs getNextPoolable() {
-                return mNext;
-            }
-
-            public boolean isPooled() {
-                return mIsPooled;
-            }
-
-            public void setNextPoolable(SomeArgs args) {
-                mNext = args;
-            }
-
-            public void setPooled(boolean isPooled) {
-                mIsPooled = isPooled;
-            }
-
-            private void clear() {
-                arg1 = null;
-                arg2 = null;
-                argi1 = 0;
-                argi2 = 0;
-                argi3 = 0;
-            }
-        }
-
-        public void findAccessibilityNodeInfoByAccessibilityIdClientThread(
-                long accessibilityNodeId, int interactionId,
-                IAccessibilityInteractionConnectionCallback callback, int prefetchFlags,
+        @Override
+        public void findFocus(long accessibilityNodeId, int interactionId, int focusType,
+                IAccessibilityInteractionConnectionCallback callback,  int flags,
                 int interrogatingPid, long interrogatingTid) {
-            Message message = mHandler.obtainMessage();
-            message.what = MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID;
-            message.arg1 = prefetchFlags;
-            SomeArgs args = mPool.acquire();
-            args.argi1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
-            args.argi2 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId);
-            args.argi3 = interactionId;
-            args.arg1 = callback;
-            message.obj = args;
-            // If the interrogation is performed by the same thread as the main UI
-            // thread in this process, set the message as a static reference so
-            // after this call completes the same thread but in the interrogating
-            // client can handle the message to generate the result.
-            if (interrogatingPid == Process.myPid()
-                    && interrogatingTid == Looper.getMainLooper().getThread().getId()) {
-                AccessibilityInteractionClient.getInstanceForThread(
-                        interrogatingTid).setSameThreadMessage(message);
+            ViewRootImpl viewRootImpl = mViewRootImpl.get();
+            if (viewRootImpl != null && viewRootImpl.mView != null) {
+                viewRootImpl.getAccessibilityInteractionController()
+                    .findFocusClientThread(accessibilityNodeId, interactionId, focusType,
+                            callback, flags, interrogatingPid, interrogatingTid);
             } else {
-                mHandler.sendMessage(message);
-            }
-        }
-
-        public void findAccessibilityNodeInfoByAccessibilityIdUiThread(Message message) {
-            final int prefetchFlags = message.arg1;
-            SomeArgs args = (SomeArgs) message.obj;
-            final int accessibilityViewId = args.argi1;
-            final int virtualDescendantId = args.argi2;
-            final int interactionId = args.argi3;
-            final IAccessibilityInteractionConnectionCallback callback =
-                (IAccessibilityInteractionConnectionCallback) args.arg1;
-            mPool.release(args);
-            List<AccessibilityNodeInfo> infos = mTempAccessibilityNodeInfoList;
-            infos.clear();
-            try {
-                View target = null;
-                if (accessibilityViewId == AccessibilityNodeInfo.UNDEFINED) {
-                    target = ViewRootImpl.this.mView;
-                } else {
-                    target = findViewByAccessibilityId(accessibilityViewId);
-                }
-                if (target != null && isDisplayedOnScreen(target)) {
-                    getAccessibilityNodePrefetcher().prefetchAccessibilityNodeInfos(target,
-                            virtualDescendantId, prefetchFlags, infos);
-                }
-            } finally {
+                // We cannot make the call and notify the caller so it does not wait.
                 try {
-                    callback.setFindAccessibilityNodeInfosResult(infos, interactionId);
-                    infos.clear();
+                    callback.setFindAccessibilityNodeInfoResult(null, interactionId);
                 } catch (RemoteException re) {
-                    /* ignore - the other side will time out */
+                    /* best effort - ignore */
                 }
             }
         }
 
-        public void findAccessibilityNodeInfoByViewIdClientThread(long accessibilityNodeId,
-                int viewId, int interactionId, IAccessibilityInteractionConnectionCallback callback,
+        @Override
+        public void focusSearch(long accessibilityNodeId, int interactionId, int direction,
+                IAccessibilityInteractionConnectionCallback callback, int flags,
                 int interrogatingPid, long interrogatingTid) {
-            Message message = mHandler.obtainMessage();
-            message.what = MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID;
-            message.arg1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
-            SomeArgs args = mPool.acquire();
-            args.argi1 = viewId;
-            args.argi2 = interactionId;
-            args.arg1 = callback;
-            message.obj = args;
-            // If the interrogation is performed by the same thread as the main UI
-            // thread in this process, set the message as a static reference so
-            // after this call completes the same thread but in the interrogating
-            // client can handle the message to generate the result.
-            if (interrogatingPid == Process.myPid()
-                    && interrogatingTid == Looper.getMainLooper().getThread().getId()) {
-                AccessibilityInteractionClient.getInstanceForThread(
-                        interrogatingTid).setSameThreadMessage(message);
+            ViewRootImpl viewRootImpl = mViewRootImpl.get();
+            if (viewRootImpl != null && viewRootImpl.mView != null) {
+                viewRootImpl.getAccessibilityInteractionController()
+                    .focusSearchClientThread(accessibilityNodeId, interactionId, direction,
+                            callback, flags, interrogatingPid, interrogatingTid);
             } else {
-                mHandler.sendMessage(message);
-            }
-        }
-
-        public void findAccessibilityNodeInfoByViewIdUiThread(Message message) {
-            final int accessibilityViewId = message.arg1;
-            SomeArgs args = (SomeArgs) message.obj;
-            final int viewId = args.argi1;
-            final int interactionId = args.argi2;
-            final IAccessibilityInteractionConnectionCallback callback =
-                (IAccessibilityInteractionConnectionCallback) args.arg1;
-            mPool.release(args);
-            AccessibilityNodeInfo info = null;
-            try {
-                View root = null;
-                if (accessibilityViewId != AccessibilityNodeInfo.UNDEFINED) {
-                    root = findViewByAccessibilityId(accessibilityViewId);
-                } else {
-                    root = ViewRootImpl.this.mView;
-                }
-                if (root != null) {
-                    View target = root.findViewById(viewId);
-                    if (target != null && isDisplayedOnScreen(target)) {
-                        info = target.createAccessibilityNodeInfo();
-                    }
-                }
-            } finally {
+                // We cannot make the call and notify the caller so it does not wait.
                 try {
-                    callback.setFindAccessibilityNodeInfoResult(info, interactionId);
+                    callback.setFindAccessibilityNodeInfoResult(null, interactionId);
                 } catch (RemoteException re) {
-                    /* ignore - the other side will time out */
+                    /* best effort - ignore */
                 }
             }
         }
-
-        public void findAccessibilityNodeInfosByTextClientThread(long accessibilityNodeId,
-                String text, int interactionId,
-                IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
-                long interrogatingTid) {
-            Message message = mHandler.obtainMessage();
-            message.what = MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT;
-            SomeArgs args = mPool.acquire();
-            args.arg1 = text;
-            args.argi1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
-            args.argi2 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId);
-            args.argi3 = interactionId;
-            args.arg2 = callback;
-            message.obj = args;
-            // If the interrogation is performed by the same thread as the main UI
-            // thread in this process, set the message as a static reference so
-            // after this call completes the same thread but in the interrogating
-            // client can handle the message to generate the result.
-            if (interrogatingPid == Process.myPid()
-                    && interrogatingTid == Looper.getMainLooper().getThread().getId()) {
-                AccessibilityInteractionClient.getInstanceForThread(
-                        interrogatingTid).setSameThreadMessage(message);
-            } else {
-                mHandler.sendMessage(message);
-            }
-        }
-
-        public void findAccessibilityNodeInfosByTextUiThread(Message message) {
-            SomeArgs args = (SomeArgs) message.obj;
-            final String text = (String) args.arg1;
-            final int accessibilityViewId = args.argi1;
-            final int virtualDescendantId = args.argi2;
-            final int interactionId = args.argi3;
-            final IAccessibilityInteractionConnectionCallback callback =
-                (IAccessibilityInteractionConnectionCallback) args.arg2;
-            mPool.release(args);
-            List<AccessibilityNodeInfo> infos = null;
-            try {
-                View target;
-                if (accessibilityViewId != AccessibilityNodeInfo.UNDEFINED) {
-                    target = findViewByAccessibilityId(accessibilityViewId);
-                } else {
-                    target = ViewRootImpl.this.mView;
-                }
-                if (target != null && isDisplayedOnScreen(target)) {
-                    AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider();
-                    if (provider != null) {
-                        infos = provider.findAccessibilityNodeInfosByText(text,
-                                virtualDescendantId);
-                    } else if (virtualDescendantId == AccessibilityNodeInfo.UNDEFINED) {
-                        ArrayList<View> foundViews = mAttachInfo.mFocusablesTempList;
-                        foundViews.clear();
-                        target.findViewsWithText(foundViews, text, View.FIND_VIEWS_WITH_TEXT
-                                | View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION
-                                | View.FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS);
-                        if (!foundViews.isEmpty()) {
-                            infos = mTempAccessibilityNodeInfoList;
-                            infos.clear();
-                            final int viewCount = foundViews.size();
-                            for (int i = 0; i < viewCount; i++) {
-                                View foundView = foundViews.get(i);
-                                if (isDisplayedOnScreen(foundView)) {
-                                    provider = foundView.getAccessibilityNodeProvider();
-                                    if (provider != null) {
-                                        List<AccessibilityNodeInfo> infosFromProvider =
-                                            provider.findAccessibilityNodeInfosByText(text,
-                                                    virtualDescendantId);
-                                        if (infosFromProvider != null) {
-                                            infos.addAll(infosFromProvider);
-                                        }
-                                    } else  {
-                                        infos.add(foundView.createAccessibilityNodeInfo());
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            } finally {
-                try {
-                    callback.setFindAccessibilityNodeInfosResult(infos, interactionId);
-                } catch (RemoteException re) {
-                    /* ignore - the other side will time out */
-                }
-            }
-        }
-
-        public void performAccessibilityActionClientThread(long accessibilityNodeId, int action,
-                int interactionId, IAccessibilityInteractionConnectionCallback callback,
-                int interogatingPid, long interrogatingTid) {
-            Message message = mHandler.obtainMessage();
-            message.what = MSG_PERFORM_ACCESSIBILITY_ACTION;
-            message.arg1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
-            message.arg2 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId);
-            SomeArgs args = mPool.acquire();
-            args.argi1 = action;
-            args.argi2 = interactionId;
-            args.arg1 = callback;
-            message.obj = args;
-            // If the interrogation is performed by the same thread as the main UI
-            // thread in this process, set the message as a static reference so
-            // after this call completes the same thread but in the interrogating
-            // client can handle the message to generate the result.
-            if (interogatingPid == Process.myPid()
-                    && interrogatingTid == Looper.getMainLooper().getThread().getId()) {
-                AccessibilityInteractionClient.getInstanceForThread(
-                        interrogatingTid).setSameThreadMessage(message);
-            } else {
-                mHandler.sendMessage(message);
-            }
-        }
-
-        public void perfromAccessibilityActionUiThread(Message message) {
-            final int accessibilityViewId = message.arg1;
-            final int virtualDescendantId = message.arg2;
-            SomeArgs args = (SomeArgs) message.obj;
-            final int action = args.argi1;
-            final int interactionId = args.argi2;
-            final IAccessibilityInteractionConnectionCallback callback =
-                (IAccessibilityInteractionConnectionCallback) args.arg1;
-            mPool.release(args);
-            boolean succeeded = false;
-            try {
-                View target = findViewByAccessibilityId(accessibilityViewId);
-                if (target != null && isDisplayedOnScreen(target)) {
-                    AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider();
-                    if (provider != null) {
-                        succeeded = provider.performAccessibilityAction(action,
-                                virtualDescendantId);
-                    } else if (virtualDescendantId == AccessibilityNodeInfo.UNDEFINED) {
-                        switch (action) {
-                            case AccessibilityNodeInfo.ACTION_FOCUS: {
-                                if (!target.hasFocus()) {
-                                    // Get out of touch mode since accessibility
-                                    // wants to move focus around.
-                                    ensureTouchMode(false);
-                                    succeeded = target.requestFocus();
-                                }
-                            } break;
-                            case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: {
-                                if (target.hasFocus()) {
-                                    target.clearFocus();
-                                    succeeded = !target.isFocused();
-                                }
-                            } break;
-                            case AccessibilityNodeInfo.ACTION_SELECT: {
-                                if (!target.isSelected()) {
-                                    target.setSelected(true);
-                                    succeeded = target.isSelected();
-                                }
-                            } break;
-                            case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: {
-                                if (target.isSelected()) {
-                                    target.setSelected(false);
-                                    succeeded = !target.isSelected();
-                                }
-                            } break;
-                        }
-                    }
-                }
-            } finally {
-                try {
-                    callback.setPerformAccessibilityActionResult(succeeded, interactionId);
-                } catch (RemoteException re) {
-                    /* ignore - the other side will time out */
-                }
-            }
-        }
-
-        private View findViewByAccessibilityId(int accessibilityId) {
-            View root = ViewRootImpl.this.mView;
-            if (root == null) {
-                return null;
-            }
-            View foundView = root.findViewByAccessibilityId(accessibilityId);
-            if (foundView != null && foundView.getVisibility() != View.VISIBLE) {
-                return null;
-            }
-            return foundView;
-        }
     }
 
     private class SendWindowContentChangedAccessibilityEvent implements Runnable {
-        public volatile boolean mIsPending;
+        public View mSource;
 
         public void run() {
-            if (mView != null) {
-                mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
-                mIsPending = false;
-            }
-        }
-    }
-
-    /**
-     * This class encapsulates a prefetching strategy for the accessibility APIs for
-     * querying window content. It is responsible to prefetch a batch of
-     * AccessibilityNodeInfos in addition to the one for a requested node.
-     */
-    class AccessibilityNodePrefetcher {
-
-        private static final int MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE = 50;
-
-        public void prefetchAccessibilityNodeInfos(View view, int virtualViewId, int prefetchFlags,
-                List<AccessibilityNodeInfo> outInfos) {
-            AccessibilityNodeProvider provider = view.getAccessibilityNodeProvider();
-            if (provider == null) {
-                AccessibilityNodeInfo root = view.createAccessibilityNodeInfo();
-                if (root != null) {
-                    outInfos.add(root);
-                    if ((prefetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) != 0) {
-                        prefetchPredecessorsOfRealNode(view, outInfos);
-                    }
-                    if ((prefetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS) != 0) {
-                        prefetchSiblingsOfRealNode(view, outInfos);
-                    }
-                    if ((prefetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS) != 0) {
-                        prefetchDescendantsOfRealNode(view, outInfos);
-                    }
-                }
-            } else {
-                AccessibilityNodeInfo root = provider.createAccessibilityNodeInfo(virtualViewId);
-                if (root != null) {
-                    outInfos.add(root);
-                    if ((prefetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) != 0) {
-                        prefetchPredecessorsOfVirtualNode(root, view, provider, outInfos);
-                    }
-                    if ((prefetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS) != 0) {
-                        prefetchSiblingsOfVirtualNode(root, view, provider, outInfos);
-                    }
-                    if ((prefetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS) != 0) {
-                        prefetchDescendantsOfVirtualNode(root, provider, outInfos);
-                    }
-                }
-            }
-        }
-
-        private void prefetchPredecessorsOfRealNode(View view,
-                List<AccessibilityNodeInfo> outInfos) {
-            ViewParent parent = view.getParent();
-            while (parent instanceof View
-                    && outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
-                View parentView = (View) parent;
-                final long parentNodeId = AccessibilityNodeInfo.makeNodeId(
-                        parentView.getAccessibilityViewId(), AccessibilityNodeInfo.UNDEFINED);
-                AccessibilityNodeInfo info = parentView.createAccessibilityNodeInfo();
-                if (info != null) {
-                    outInfos.add(info);
-                }
-                parent = parent.getParent();
-            }
-        }
-
-        private void prefetchSiblingsOfRealNode(View current,
-                List<AccessibilityNodeInfo> outInfos) {
-            ViewParent parent = current.getParent();
-            if (parent instanceof ViewGroup) {
-                ViewGroup parentGroup = (ViewGroup) parent;
-                final int childCount = parentGroup.getChildCount();
-                for (int i = 0; i < childCount; i++) {
-                    View child = parentGroup.getChildAt(i);
-                    if (outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE
-                            && child.getAccessibilityViewId() != current.getAccessibilityViewId()
-                            && isDisplayedOnScreen(child)) {
-                        final long childNodeId = AccessibilityNodeInfo.makeNodeId(
-                                child.getAccessibilityViewId(), AccessibilityNodeInfo.UNDEFINED);
-                        AccessibilityNodeInfo info = null;
-                        AccessibilityNodeProvider provider = child.getAccessibilityNodeProvider();
-                        if (provider == null) {
-                            info = child.createAccessibilityNodeInfo();
-                        } else {
-                            info = provider.createAccessibilityNodeInfo(
-                                    AccessibilityNodeInfo.UNDEFINED);
-                        }
-                        if (info != null) {
-                            outInfos.add(info);
-                        }
-                    }
-                }
-            }
-        }
-
-        private void prefetchDescendantsOfRealNode(View root,
-                List<AccessibilityNodeInfo> outInfos) {
-            if (root instanceof ViewGroup) {
-                ViewGroup rootGroup = (ViewGroup) root;
-                HashMap<View, AccessibilityNodeInfo> addedChildren =
-                    new HashMap<View, AccessibilityNodeInfo>();
-                final int childCount = rootGroup.getChildCount();
-                for (int i = 0; i < childCount; i++) {
-                    View child = rootGroup.getChildAt(i);
-                    if (isDisplayedOnScreen(child)
-                            && outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
-                        final long childNodeId = AccessibilityNodeInfo.makeNodeId(
-                                child.getAccessibilityViewId(), AccessibilityNodeInfo.UNDEFINED);
-                        AccessibilityNodeProvider provider = child.getAccessibilityNodeProvider();
-                        if (provider == null) {
-                            AccessibilityNodeInfo info = child.createAccessibilityNodeInfo();
-                            if (info != null) {
-                                outInfos.add(info);
-                                addedChildren.put(child, null);
-                            }
-                        } else {
-                            AccessibilityNodeInfo info = provider.createAccessibilityNodeInfo(
-                                   AccessibilityNodeInfo.UNDEFINED);
-                            if (info != null) {
-                                outInfos.add(info);
-                                addedChildren.put(child, info);
-                            }
-                        }
-                    }
-                }
-                if (outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
-                    for (Map.Entry<View, AccessibilityNodeInfo> entry : addedChildren.entrySet()) {
-                        View addedChild = entry.getKey();
-                        AccessibilityNodeInfo virtualRoot = entry.getValue();
-                        if (virtualRoot == null) {
-                            prefetchDescendantsOfRealNode(addedChild, outInfos);
-                        } else {
-                            AccessibilityNodeProvider provider =
-                                addedChild.getAccessibilityNodeProvider();
-                            prefetchDescendantsOfVirtualNode(virtualRoot, provider, outInfos);
-                        }
-                    }
-                }
-            }
-        }
-
-        private void prefetchPredecessorsOfVirtualNode(AccessibilityNodeInfo root,
-                View providerHost, AccessibilityNodeProvider provider,
-                List<AccessibilityNodeInfo> outInfos) {
-            long parentNodeId = root.getParentNodeId();
-            int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(parentNodeId);
-            while (accessibilityViewId != AccessibilityNodeInfo.UNDEFINED) {
-                final int virtualDescendantId =
-                    AccessibilityNodeInfo.getVirtualDescendantId(parentNodeId);
-                if (virtualDescendantId != AccessibilityNodeInfo.UNDEFINED
-                        || accessibilityViewId == providerHost.getAccessibilityViewId()) {
-                    AccessibilityNodeInfo parent = provider.createAccessibilityNodeInfo(
-                            virtualDescendantId);
-                    if (parent != null) {
-                        outInfos.add(parent);
-                    }
-                    parentNodeId = parent.getParentNodeId();
-                    accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
-                            parentNodeId);
-                } else {
-                    prefetchPredecessorsOfRealNode(providerHost, outInfos);
-                    return;
-                }
-            }
-        }
-
-        private void prefetchSiblingsOfVirtualNode(AccessibilityNodeInfo current, View providerHost,
-                AccessibilityNodeProvider provider, List<AccessibilityNodeInfo> outInfos) {
-            final long parentNodeId = current.getParentNodeId();
-            final int parentAccessibilityViewId =
-                AccessibilityNodeInfo.getAccessibilityViewId(parentNodeId);
-            final int parentVirtualDescendantId =
-                AccessibilityNodeInfo.getVirtualDescendantId(parentNodeId);
-            if (parentVirtualDescendantId != AccessibilityNodeInfo.UNDEFINED
-                    || parentAccessibilityViewId == providerHost.getAccessibilityViewId()) {
-                AccessibilityNodeInfo parent =
-                    provider.createAccessibilityNodeInfo(parentVirtualDescendantId);
-                if (parent != null) {
-                    SparseLongArray childNodeIds = parent.getChildNodeIds();
-                    final int childCount = childNodeIds.size();
-                    for (int i = 0; i < childCount; i++) {
-                        final long childNodeId = childNodeIds.get(i);
-                        if (childNodeId != current.getSourceNodeId()
-                                && outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
-                            final int childVirtualDescendantId =
-                                AccessibilityNodeInfo.getVirtualDescendantId(childNodeId);
-                            AccessibilityNodeInfo child = provider.createAccessibilityNodeInfo(
-                                    childVirtualDescendantId);
-                            if (child != null) {
-                                outInfos.add(child);
-                            }
-                        }
-                    }
-                }
-            } else {
-                prefetchSiblingsOfRealNode(providerHost, outInfos);
-            }
-        }
-
-        private void prefetchDescendantsOfVirtualNode(AccessibilityNodeInfo root,
-                AccessibilityNodeProvider provider, List<AccessibilityNodeInfo> outInfos) {
-            SparseLongArray childNodeIds = root.getChildNodeIds();
-            final int initialOutInfosSize = outInfos.size();
-            final int childCount = childNodeIds.size();
-            for (int i = 0; i < childCount; i++) {
-                if (outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
-                    final long childNodeId = childNodeIds.get(i);
-                    AccessibilityNodeInfo child = provider.createAccessibilityNodeInfo(
-                            AccessibilityNodeInfo.getVirtualDescendantId(childNodeId));
-                    if (child != null) {
-                        outInfos.add(child);
-                    }
-                }
-            }
-            if (outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
-                final int addedChildCount = outInfos.size() - initialOutInfosSize;
-                for (int i = 0; i < addedChildCount; i++) {
-                    AccessibilityNodeInfo child = outInfos.get(initialOutInfosSize + i);
-                    prefetchDescendantsOfVirtualNode(child, provider, outInfos);
-                }
+            if (mSource != null) {
+                mSource.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+                mSource.resetAccessibilityStateChanged();
+                mSource = null;
             }
         }
     }
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index 9152cc3..110c239 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -263,7 +263,7 @@
                 | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
 
         mToneGenerators = new ToneGenerator[AudioSystem.getNumStreamTypes()];
-        mVibrator = new Vibrator();
+        mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
 
         mVoiceCapable = context.getResources().getBoolean(R.bool.config_voice_capable);
         mShowCombinedVolumes = !mVoiceCapable && !useMasterVolume;
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 0998c80..6cb1578 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -508,7 +508,7 @@
     public static final int TYPE_VIEW_SELECTED = 0x00000004;
 
     /**
-     * Represents the event of focusing a {@link android.view.View}.
+     * Represents the event of setting input focus of a {@link android.view.View}.
      */
     public static final int TYPE_VIEW_FOCUSED = 0x00000008;
 
@@ -549,7 +549,8 @@
     public static final int TYPE_TOUCH_EXPLORATION_GESTURE_END = 0x00000400;
 
     /**
-     * Represents the event of changing the content of a window.
+     * Represents the event of changing the content of a window and more
+     * specifically the sub-tree rooted at the event's source.
      */
     public static final int TYPE_WINDOW_CONTENT_CHANGED = 0x00000800;
 
@@ -569,6 +570,16 @@
     public static final int TYPE_ANNOUNCEMENT = 0x00004000;
 
     /**
+     * Represents the event of gaining accessibility focus.
+     */
+    public static final int TYPE_VIEW_ACCESSIBILITY_FOCUSED = 0x00008000;
+
+    /**
+     * Represents the event of clearing accessibility focus.
+     */
+    public static final int TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED = 0x00010000;
+
+    /**
      * Mask for {@link AccessibilityEvent} all types.
      *
      * @see #TYPE_VIEW_CLICKED
@@ -1018,6 +1029,10 @@
                 return "TYPE_VIEW_SCROLLED";
             case TYPE_ANNOUNCEMENT:
                 return "TYPE_ANNOUNCEMENT";
+            case TYPE_VIEW_ACCESSIBILITY_FOCUSED:
+                return "TYPE_VIEW_ACCESSIBILITY_FOCUSED";
+            case TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED:
+                return "TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED";
             default:
                 return null;
         }
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index be74b31..35f0d9d 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -18,7 +18,9 @@
 
 import android.accessibilityservice.IAccessibilityServiceConnection;
 import android.graphics.Rect;
+import android.os.Binder;
 import android.os.Message;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.Log;
@@ -174,7 +176,7 @@
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
                 final float windowScale = connection.findAccessibilityNodeInfoByAccessibilityId(
                         accessibilityWindowId, accessibilityNodeId, interactionId, this,
-                        Thread.currentThread().getId(), prefetchFlags);
+                        prefetchFlags, Thread.currentThread().getId());
                 // If the scale is zero the call has failed.
                 if (windowScale > 0) {
                     List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
@@ -293,6 +295,96 @@
     }
 
     /**
+     * Finds the {@link android.view.accessibility.AccessibilityNodeInfo} that has the
+     * specified focus type. The search is performed in the window whose id is specified
+     * and starts from the node whose accessibility id is specified.
+     *
+     * @param connectionId The id of a connection for interacting with the system.
+     * @param accessibilityWindowId A unique window id. Use
+     *     {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID}
+     *     to query the currently active window.
+     * @param accessibilityNodeId A unique view id or virtual descendant id from
+     *     where to start the search. Use
+     *     {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID}
+     *     to start from the root.
+     * @param focusType The focus type.
+     * @return The accessibility focused {@link AccessibilityNodeInfo}.
+     */
+    public AccessibilityNodeInfo findFocus(int connectionId, int accessibilityWindowId,
+            long accessibilityNodeId, int focusType) {
+        try {
+            IAccessibilityServiceConnection connection = getConnection(connectionId);
+            if (connection != null) {
+                final int interactionId = mInteractionIdCounter.getAndIncrement();
+                final float windowScale = connection.findFocus(accessibilityWindowId,
+                        accessibilityNodeId, focusType, interactionId, this,
+                        Thread.currentThread().getId());
+                // If the scale is zero the call has failed.
+                if (windowScale > 0) {
+                    AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
+                            interactionId);
+                    finalizeAndCacheAccessibilityNodeInfo(info, connectionId, windowScale);
+                    return info;
+                }
+            } else {
+                if (DEBUG) {
+                    Log.w(LOG_TAG, "No connection for connection id: " + connectionId);
+                }
+            }
+        } catch (RemoteException re) {
+            if (DEBUG) {
+                Log.w(LOG_TAG, "Error while calling remote findAccessibilityFocus", re);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Finds the accessibility focused {@link android.view.accessibility.AccessibilityNodeInfo}.
+     * The search is performed in the window whose id is specified and starts from the
+     * node whose accessibility id is specified.
+     *
+     * @param connectionId The id of a connection for interacting with the system.
+     * @param accessibilityWindowId A unique window id. Use
+     *     {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID}
+     *     to query the currently active window.
+     * @param accessibilityNodeId A unique view id or virtual descendant id from
+     *     where to start the search. Use
+     *     {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID}
+     *     to start from the root.
+     * @param direction The direction in which to search for focusable.
+     * @return The accessibility focused {@link AccessibilityNodeInfo}.
+     */
+    public AccessibilityNodeInfo focusSearch(int connectionId, int accessibilityWindowId,
+            long accessibilityNodeId, int direction) {
+        try {
+            IAccessibilityServiceConnection connection = getConnection(connectionId);
+            if (connection != null) {
+                final int interactionId = mInteractionIdCounter.getAndIncrement();
+                final float windowScale = connection.focusSearch(accessibilityWindowId,
+                        accessibilityNodeId, direction, interactionId, this,
+                        Thread.currentThread().getId());
+                // If the scale is zero the call has failed.
+                if (windowScale > 0) {
+                    AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
+                            interactionId);
+                    finalizeAndCacheAccessibilityNodeInfo(info, connectionId, windowScale);
+                    return info;
+                }
+            } else {
+                if (DEBUG) {
+                    Log.w(LOG_TAG, "No connection for connection id: " + connectionId);
+                }
+            }
+        } catch (RemoteException re) {
+            if (DEBUG) {
+                Log.w(LOG_TAG, "Error while calling remote accessibilityFocusSearch", re);
+            }
+        }
+        return null;
+    }
+
+    /**
      * Performs an accessibility action on an {@link AccessibilityNodeInfo}.
      *
      * @param connectionId The id of a connection for interacting with the system.
@@ -382,7 +474,12 @@
                 int interactionId) {
         synchronized (mInstanceLock) {
             final boolean success = waitForResultTimedLocked(interactionId);
-            List<AccessibilityNodeInfo> result = success ? mFindAccessibilityNodeInfosResult : null;
+            List<AccessibilityNodeInfo> result = null;
+            if (success) {
+                result = mFindAccessibilityNodeInfosResult;
+            } else {
+                result = Collections.emptyList();
+            }
             clearResultLocked();
             return result;
         }
@@ -395,13 +492,18 @@
                 int interactionId) {
         synchronized (mInstanceLock) {
             if (interactionId > mInteractionId) {
-                // If the call is not an IPC, i.e. it is made from the same process, we need to
-                // instantiate new result list to avoid passing internal instances to clients.
-                final boolean isIpcCall = (queryLocalInterface(getInterfaceDescriptor()) == null);
-                if (!isIpcCall) {
-                    mFindAccessibilityNodeInfosResult = new ArrayList<AccessibilityNodeInfo>(infos);
+                if (infos != null) {
+                    // If the call is not an IPC, i.e. it is made from the same process, we need to
+                    // instantiate new result list to avoid passing internal instances to clients.
+                    final boolean isIpcCall = (Binder.getCallingPid() != Process.myPid());
+                    if (!isIpcCall) {
+                        mFindAccessibilityNodeInfosResult =
+                            new ArrayList<AccessibilityNodeInfo>(infos);
+                    } else {
+                        mFindAccessibilityNodeInfosResult = infos;
+                    }
                 } else {
-                    mFindAccessibilityNodeInfosResult = infos;
+                    mFindAccessibilityNodeInfosResult = Collections.emptyList();
                 }
                 mInteractionId = interactionId;
             }
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index e37de6f..77fd12a 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -204,6 +204,12 @@
      * @param event The event to send.
      *
      * @throws IllegalStateException if accessibility is not enabled.
+     *
+     * <strong>Note:</strong> The preferred mechanism for sending custom accessibility
+     * events is through calling
+     * {@link android.view.ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)}
+     * instead of this method to allow predecessors to augment/filter events sent by
+     * their descendants.
      */
     public void sendAccessibilityEvent(AccessibilityEvent event) {
         if (!mIsEnabled) {
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index f616dca..1071c65 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -74,29 +74,57 @@
     public static final int FLAG_PREFETCH_SIBLINGS = 0x00000002;
 
     /** @hide */
-    public static final int FLAG_PREFETCH_DESCENDANTS = 0x00000003;
+    public static final int FLAG_PREFETCH_DESCENDANTS = 0x00000004;
+
+    /** @hide */
+    public static final int INCLUDE_NOT_IMPORTANT_VIEWS = 0x00000008;
 
     // Actions.
 
     /**
-     * Action that focuses the node.
+     * Action that gives input focus to the node.
      */
-    public static final int ACTION_FOCUS =  0x00000001;
+    public static final int ACTION_FOCUS = 0x00000001;
 
     /**
-     * Action that unfocuses the node.
+     * Action that clears input focus of the node.
      */
-    public static final int ACTION_CLEAR_FOCUS =  0x00000002;
+    public static final int ACTION_CLEAR_FOCUS = 0x00000002;
 
     /**
      * Action that selects the node.
      */
-    public static final int ACTION_SELECT =  0x00000004;
+    public static final int ACTION_SELECT = 0x00000004;
 
     /**
      * Action that unselects the node.
      */
-    public static final int ACTION_CLEAR_SELECTION =  0x00000008;
+    public static final int ACTION_CLEAR_SELECTION = 0x00000008;
+
+    /**
+     * Action that gives accessibility focus to the node.
+     */
+    public static final int ACTION_ACCESSIBILITY_FOCUS = 0x00000010;
+
+    /**
+     * Action that clears accessibility focus of the node.
+     */
+    public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 0x00000020;
+
+    /**
+     * Action that clicks on the node info./AccessibilityNodeInfoCache.java
+     */
+    public static final int ACTION_CLICK = 0x00000040;
+
+    /**
+     * The input focus.
+     */
+    public static final int FOCUS_INPUT = 1;
+
+    /**
+     * The accessibility focus.
+     */
+    public static final int FOCUS_ACCESSIBILITY = 2;
 
     // Boolean attributes.
 
@@ -120,6 +148,8 @@
 
     private static final int PROPERTY_SCROLLABLE = 0x00000200;
 
+    private static final int PROPERTY_ACCESSIBILITY_FOCUSED = 0x00000400;
+
     /**
      * Bits that provide the id of a virtual descendant of a view.
      */
@@ -248,6 +278,57 @@
             (root != null) ? root.getAccessibilityViewId() : UNDEFINED;
         mSourceNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
     }
+    
+    /**
+     * Find the view that has the input focus. The search starts from
+     * the view represented by this node info.
+     *
+     * @param focus The focus to find. One of {@link #FOCUS_INPUT} or
+     *         {@link #FOCUS_ACCESSIBILITY}.
+     * @return The node info of the focused view or null.
+     *
+     * @see #FOCUS_INPUT
+     * @see #FOCUS_ACCESSIBILITY
+     */
+    public AccessibilityNodeInfo findFocus(int focus) {
+        enforceSealed();
+        if (!canPerformRequestOverConnection(mSourceNodeId)) {
+            return null;
+        }
+        return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId, mWindowId,
+                mSourceNodeId, focus);
+    }
+
+    /**
+     * Searches for the nearest view in the specified direction that can take
+     * the input focus.
+     *
+     * @param direction The direction. Can be one of:
+     *     {@link View#FOCUS_DOWN},
+     *     {@link View#FOCUS_UP},
+     *     {@link View#FOCUS_LEFT},
+     *     {@link View#FOCUS_RIGHT},
+     *     {@link View#FOCUS_FORWARD},
+     *     {@link View#FOCUS_BACKWARD},
+     *     {@link View#ACCESSIBILITY_FOCUS_IN},
+     *     {@link View#ACCESSIBILITY_FOCUS_OUT},
+     *     {@link View#ACCESSIBILITY_FOCUS_FORWARD},
+     *     {@link View#ACCESSIBILITY_FOCUS_BACKWARD},
+     *     {@link View#ACCESSIBILITY_FOCUS_UP},
+     *     {@link View#ACCESSIBILITY_FOCUS_RIGHT},
+     *     {@link View#ACCESSIBILITY_FOCUS_DOWN},
+     *     {@link View#ACCESSIBILITY_FOCUS_LEFT}.
+     *
+     * @return The node info for the view that can take accessibility focus.
+     */
+    public AccessibilityNodeInfo focusSearch(int direction) {
+        enforceSealed();
+        if (!canPerformRequestOverConnection(mSourceNodeId)) {
+            return null;
+        }
+        return AccessibilityInteractionClient.getInstance().focusSearch(mConnectionId, mWindowId,
+                mSourceNodeId, direction);
+    }
 
     /**
      * Gets the id of the window from which the info comes from.
@@ -642,6 +723,31 @@
     }
 
     /**
+     * Gets whether this node is accessibility focused.
+     *
+     * @return True if the node is accessibility focused.
+     */
+    public boolean isAccessibilityFocused() {
+        return getBooleanProperty(PROPERTY_ACCESSIBILITY_FOCUSED);
+    }
+
+    /**
+     * Sets whether this node is accessibility focused.
+     * <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 focused True if the node is accessibility focused.
+     *
+     * @throws IllegalStateException If called from an AccessibilityService.
+     */
+    public void setAccessibilityFocused(boolean focused) {
+        setBooleanProperty(PROPERTY_ACCESSIBILITY_FOCUSED, focused);
+    }
+
+    /**
      * Gets whether this node is selected.
      *
      * @return True if the node is selected.
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java b/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
index dfbfc70..d2609bb 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
@@ -18,6 +18,7 @@
 
 import android.util.Log;
 import android.util.LongSparseArray;
+import android.util.SparseLongArray;
 
 /**
  * Simple cache for AccessibilityNodeInfos. The cache is mapping an
@@ -54,20 +55,25 @@
      * @param event An event.
      */
     public void onAccessibilityEvent(AccessibilityEvent event) {
-        final int eventType = event.getEventType();
-        switch (eventType) {
-            case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
-            case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:
-            case AccessibilityEvent.TYPE_VIEW_SCROLLED:
-                clear();
-                break;
-            case AccessibilityEvent.TYPE_VIEW_FOCUSED:
-            case AccessibilityEvent.TYPE_VIEW_SELECTED:
-            case AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED:
-            case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED:
-                final long accessibilityNodeId = event.getSourceNodeId();
-                remove(accessibilityNodeId);
-                break;
+        if (ENABLED) {
+            final int eventType = event.getEventType();
+            switch (eventType) {
+                case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: {
+                    clear();
+                } break;
+                case AccessibilityEvent.TYPE_VIEW_FOCUSED:
+                case AccessibilityEvent.TYPE_VIEW_SELECTED:
+                case AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED:
+                case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: {
+                    final long accessibilityNodeId = event.getSourceNodeId();
+                    remove(accessibilityNodeId);
+                } break;
+                case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:
+                case AccessibilityEvent.TYPE_VIEW_SCROLLED: {
+                    final long accessibilityNodeId = event.getSourceNodeId();
+                    clearSubTree(accessibilityNodeId);
+                } break;
+            }
         }
     }
 
@@ -167,4 +173,23 @@
             }
         }
     }
+
+    /**
+     * Clears a subtree rooted at the node with the given id.
+     *
+     * @param rootNodeId The root id.
+     */
+    private void clearSubTree(long rootNodeId) {
+        AccessibilityNodeInfo current = mCacheImpl.get(rootNodeId);
+        if (current == null) {
+            return;
+        }
+        mCacheImpl.remove(rootNodeId);
+        SparseLongArray childNodeIds = current.getChildNodeIds();
+        final int childCount = childNodeIds.size();
+        for (int i = 0; i < childCount; i++) {
+            final long childNodeId = childNodeIds.valueAt(i);
+            clearSubTree(childNodeId);
+        }
+    }
 }
diff --git a/core/java/android/view/accessibility/AccessibilityNodeProvider.java b/core/java/android/view/accessibility/AccessibilityNodeProvider.java
index 5890417..19e35dd 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeProvider.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeProvider.java
@@ -87,6 +87,7 @@
      * @return A populated {@link AccessibilityNodeInfo} for a virtual descendant or the
      *     host View.
      *
+     * @see View#createAccessibilityNodeInfo()
      * @see AccessibilityNodeInfo
      */
     public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) {
@@ -102,6 +103,7 @@
      * @param virtualViewId A client defined virtual view id.
      * @return True if the action was performed.
      *
+     * @see View#performAccessibilityAction(int)
      * @see #createAccessibilityNodeInfo(int)
      * @see AccessibilityNodeInfo
      */
@@ -127,4 +129,58 @@
             int virtualViewId) {
         return null;
     }
+
+    /**
+     * Finds the accessibility focused {@link AccessibilityNodeInfo}. The search is
+     * relative to the virtual view, i.e. a descendant of the host View, with the
+     * given <code>virtualViewId</code> or the host View itself
+     * <code>virtualViewId</code> equals to {@link View#NO_ID}.
+     *
+     * <strong>Note:</strong> Normally the system is responsible to transparently find
+     *     accessibility focused view starting from a given root but for virtual view
+     *     hierarchies it is a responsibility of this provider's implementor to find
+     *     the accessibility focused virtual view.
+     *
+     * @param virtualViewId A client defined virtual view id which defined
+     *     the root of the tree in which to perform the search.
+     * @return A list of node info.
+     *
+     * @see #createAccessibilityNodeInfo(int)
+     * @see AccessibilityNodeInfo
+     */
+    public AccessibilityNodeInfo findAccessibilitiyFocus(int virtualViewId) {
+        return null;
+    }
+
+    /**
+     * Finds {@link AccessibilityNodeInfo} to take accessibility focus in the given
+     * <code>direction</code>. The search is relative to the virtual view, i.e. a
+     * descendant of the host View, with the given <code>virtualViewId</code> or
+     * the host View itself <code>virtualViewId</code> equals to {@link View#NO_ID}.
+     *
+     * <strong>Note:</strong> Normally the system is responsible to transparently find
+     *     the next view to take accessibility focus but for virtual view hierarchies
+     *     it is a responsibility of this provider's implementor to compute the next
+     *     focusable.
+     *
+     * @param direction The direction in which to search for a focus candidate.
+     *     Values are
+     *     {@link View#ACCESSIBILITY_FOCUS_IN},
+     *     {@link View#ACCESSIBILITY_FOCUS_OUT},
+     *     {@link View#ACCESSIBILITY_FOCUS_FORWARD},
+     *     {@link View#ACCESSIBILITY_FOCUS_BACKWARD},
+     *     {@link View#ACCESSIBILITY_FOCUS_UP},
+     *     {@link View#ACCESSIBILITY_FOCUS_DOWN},
+     *     {@link View#ACCESSIBILITY_FOCUS_LEFT},
+     *     {@link View#ACCESSIBILITY_FOCUS_RIGHT}.
+     * @param virtualViewId A client defined virtual view id which defined
+     *     the root of the tree in which to perform the search.
+     * @return A list of node info.
+     *
+     * @see #createAccessibilityNodeInfo(int)
+     * @see AccessibilityNodeInfo
+     */
+    public AccessibilityNodeInfo accessibilityFocusSearch(int direction, int virtualViewId) {
+        return null;
+    }
 }
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index d25b3db..78a7d46 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -62,6 +62,7 @@
     private static final int PROPERTY_PASSWORD = 0x00000004;
     private static final int PROPERTY_FULL_SCREEN = 0x00000080;
     private static final int PROPERTY_SCROLLABLE = 0x00000100;
+    private static final int PROPERTY_IMPORTANT_FOR_ACCESSIBILITY = 0x00000200;
 
     private static final int GET_SOURCE_PREFETCH_FLAGS =
         AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS
@@ -77,7 +78,7 @@
     private boolean mIsInPool;
 
     boolean mSealed;
-    int mBooleanProperties;
+    int mBooleanProperties = PROPERTY_IMPORTANT_FOR_ACCESSIBILITY;
     int mCurrentItemIndex = UNDEFINED;
     int mItemCount = UNDEFINED;
     int mFromIndex = UNDEFINED;
@@ -134,6 +135,8 @@
      */
     public void setSource(View root, int virtualDescendantId) {
         enforceNotSealed();
+        final boolean important = (root != null) ? root.isImportantForAccessibility() : true;
+        setBooleanProperty(PROPERTY_IMPORTANT_FOR_ACCESSIBILITY, important);
         mSourceWindowId = (root != null) ? root.getAccessibilityWindowId() : UNDEFINED;
         final int rootViewId = (root != null) ? root.getAccessibilityViewId() : UNDEFINED;
         mSourceNodeId = AccessibilityNodeInfo.makeNodeId(rootViewId, virtualDescendantId);
@@ -274,6 +277,23 @@
     }
 
     /**
+     * Gets if the source is important for accessibility.
+     *
+     * <strong>Note:</strong> Used only internally to determine whether
+     * to deliver the event to a given accessibility service since some
+     * services may want to regard all views for accessibility while others
+     * may want to regard only the important views for accessibility.
+     *
+     * @return True if the source is important for accessibility,
+     *        false otherwise.
+     *
+     * @hide
+     */
+    public boolean isImportantForAccessibility() {
+        return getBooleanProperty(PROPERTY_IMPORTANT_FOR_ACCESSIBILITY);
+    }
+
+    /**
      * Gets the number of items that can be visited.
      *
      * @return The number of items.
@@ -755,7 +775,7 @@
      */
     void clear() {
         mSealed = false;
-        mBooleanProperties = 0;
+        mBooleanProperties = PROPERTY_IMPORTANT_FOR_ACCESSIBILITY;
         mCurrentItemIndex = UNDEFINED;
         mItemCount = UNDEFINED;
         mFromIndex = UNDEFINED;
diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
index fc3651c..8182d29 100644
--- a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
@@ -28,18 +28,26 @@
 oneway interface IAccessibilityInteractionConnection {
 
     void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId, int interactionId,
-        IAccessibilityInteractionConnectionCallback callback, int prefetchFlags,
-        int interrogatingPid, long interrogatingTid);
+        IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
+        long interrogatingTid);
 
     void findAccessibilityNodeInfoByViewId(long accessibilityNodeId, int id, int interactionId,
-        IAccessibilityInteractionConnectionCallback callback,
-        int interrogatingPid, long interrogatingTid);
+        IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
+        long interrogatingTid);
 
     void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text, int interactionId,
-        IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
+        IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
+        long interrogatingTid);
+
+    void findFocus(long accessibilityNodeId, int interactionId, int focusType,
+        IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
+        long interrogatingTid);
+
+    void focusSearch(long accessibilityNodeId, int interactionId, int direction,
+        IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
         long interrogatingTid);
 
     void performAccessibilityAction(long accessibilityNodeId, int action, int interactionId,
-        IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
+        IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
         long interrogatingTid);
 }
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 320c75d..5b5134a 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -19,7 +19,7 @@
 
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.accessibilityservice.IAccessibilityServiceConnection;
-import android.accessibilityservice.IEventListener;
+import android.accessibilityservice.IAccessibilityServiceClient;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.IAccessibilityInteractionConnection;
@@ -49,7 +49,8 @@
 
     void removeAccessibilityInteractionConnection(IWindow windowToken);
 
-    void registerUiTestAutomationService(IEventListener listener, in AccessibilityServiceInfo info);
+    void registerUiTestAutomationService(IAccessibilityServiceClient client,
+        in AccessibilityServiceInfo info);
 
-    void unregisterUiTestAutomationService(IEventListener listener);
+    void unregisterUiTestAutomationService(IAccessibilityServiceClient client);
 }
diff --git a/core/java/android/view/textservice/SpellCheckerInfo.java b/core/java/android/view/textservice/SpellCheckerInfo.java
index d05c1af..2167862 100644
--- a/core/java/android/view/textservice/SpellCheckerInfo.java
+++ b/core/java/android/view/textservice/SpellCheckerInfo.java
@@ -45,7 +45,6 @@
     private final ResolveInfo mService;
     private final String mId;
     private final int mLabel;
-    private final boolean mSupportsSentenceSpellCheck;
 
     /**
      * The spell checker setting activity's name, used by the system settings to
@@ -98,9 +97,6 @@
             label = sa.getResourceId(com.android.internal.R.styleable.SpellChecker_label, 0);
             settingsActivityComponent = sa.getString(
                     com.android.internal.R.styleable.SpellChecker_settingsActivity);
-            mSupportsSentenceSpellCheck = sa.getBoolean(
-                    com.android.internal.R.styleable.SpellChecker_supportsSentenceSpellCheck,
-                    false);
             sa.recycle();
 
             final int depth = parser.getDepth();
@@ -142,7 +138,6 @@
      */
     public SpellCheckerInfo(Parcel source) {
         mLabel = source.readInt();
-        mSupportsSentenceSpellCheck = source.readInt() != 0;
         mId = source.readString();
         mSettingsActivityName = source.readString();
         mService = ResolveInfo.CREATOR.createFromParcel(source);
@@ -158,13 +153,6 @@
     }
 
     /**
-     * @hide
-     */
-    public boolean isSentenceSpellCheckSupported() {
-        return mSupportsSentenceSpellCheck;
-    }
-
-    /**
      * Return the component of the service that implements.
      */
     public ComponentName getComponent() {
@@ -188,7 +176,6 @@
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(mLabel);
-        dest.writeInt(mSupportsSentenceSpellCheck ? 1 : 0);
         dest.writeString(mId);
         dest.writeString(mSettingsActivityName);
         mService.writeToParcel(dest, flags);
diff --git a/core/java/android/view/textservice/SpellCheckerSession.java b/core/java/android/view/textservice/SpellCheckerSession.java
index 9dc05e4..628da3c 100644
--- a/core/java/android/view/textservice/SpellCheckerSession.java
+++ b/core/java/android/view/textservice/SpellCheckerSession.java
@@ -91,8 +91,6 @@
      * This meta-data must reference an XML resource.
      **/
     public static final String SERVICE_META_DATA = "android.view.textservice.scs";
-    private static final String SUPPORT_SENTENCE_SPELL_CHECK = "SupportSentenceSpellCheck";
-
 
     private static final int MSG_ON_GET_SUGGESTION_MULTIPLE = 1;
     private static final int MSG_ON_GET_SUGGESTION_MULTIPLE_FOR_SENTENCE = 2;
@@ -191,7 +189,9 @@
      * Get candidate strings for a substring of the specified text.
      * @param textInfo text metadata for a spell checker
      * @param suggestionsLimit the maximum number of suggestions that will be returned
+     * @deprecated use {@link SpellCheckerSession#getSentenceSuggestions(TextInfo[], int)} instead
      */
+    @Deprecated
     public void getSuggestions(TextInfo textInfo, int suggestionsLimit) {
         getSuggestions(new TextInfo[] {textInfo}, suggestionsLimit, false);
     }
@@ -201,13 +201,14 @@
      * @param textInfos an array of text metadata for a spell checker
      * @param suggestionsLimit the maximum number of suggestions that will be returned
      * @param sequentialWords true if textInfos can be treated as sequential words.
+     * @deprecated use {@link SpellCheckerSession#getSentenceSuggestions(TextInfo[], int)} instead
      */
+    @Deprecated
     public void getSuggestions(
             TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) {
         if (DBG) {
             Log.w(TAG, "getSuggestions from " + mSpellCheckerInfo.getId());
         }
-        // TODO: Handle multiple words suggestions by using WordBreakIterator
         mSpellCheckerSessionListenerImpl.getSuggestionsMultiple(
                 textInfos, suggestionsLimit, sequentialWords);
     }
@@ -281,7 +282,7 @@
                         break;
                     case TASK_GET_SUGGESTIONS_MULTIPLE_FOR_SENTENCE:
                         if (DBG) {
-                            Log.w(TAG, "Get suggestions from the spell checker.");
+                            Log.w(TAG, "Get sentence suggestions from the spell checker.");
                         }
                         try {
                             session.onGetSentenceSuggestionsMultiple(
@@ -492,11 +493,4 @@
     public ISpellCheckerSessionListener getSpellCheckerSessionListener() {
         return mSpellCheckerSessionListenerImpl;
     }
-
-    /**
-     * @return true if the spell checker supports sentence level spell checking APIs
-     */
-    public boolean isSentenceSpellCheckSupported() {
-        return mSubtype.containsExtraValueKey(SUPPORT_SENTENCE_SPELL_CHECK);
-    }
 }
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index 79bd5d3..ab798e8 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -513,18 +513,18 @@
                     String databaseIdentifier =
                             (String) map.get("databaseIdentifier");
                     String url = (String) map.get("url");
-                    long currentQuota =
-                            ((Long) map.get("currentQuota")).longValue();
-                    long totalUsedQuota =
-                            ((Long) map.get("totalUsedQuota")).longValue();
-                    long estimatedSize =
-                            ((Long) map.get("estimatedSize")).longValue();
+                    long quota =
+                            ((Long) map.get("quota")).longValue();
+                    long totalQuota =
+                            ((Long) map.get("totalQuota")).longValue();
+                    long estimatedDatabaseSize =
+                            ((Long) map.get("estimatedDatabaseSize")).longValue();
                     WebStorage.QuotaUpdater quotaUpdater =
                         (WebStorage.QuotaUpdater) map.get("quotaUpdater");
 
                     mWebChromeClient.onExceededDatabaseQuota(url,
-                            databaseIdentifier, currentQuota, estimatedSize,
-                            totalUsedQuota, quotaUpdater);
+                            databaseIdentifier, quota, estimatedDatabaseSize,
+                            totalQuota, quotaUpdater);
                 }
                 break;
 
@@ -532,15 +532,15 @@
                 if (mWebChromeClient != null) {
                     HashMap<String, Object> map =
                             (HashMap<String, Object>) msg.obj;
-                    long spaceNeeded =
-                            ((Long) map.get("spaceNeeded")).longValue();
-                    long totalUsedQuota =
-                        ((Long) map.get("totalUsedQuota")).longValue();
+                    long requiredStorage =
+                            ((Long) map.get("requiredStorage")).longValue();
+                    long quota =
+                        ((Long) map.get("quota")).longValue();
                     WebStorage.QuotaUpdater quotaUpdater =
                         (WebStorage.QuotaUpdater) map.get("quotaUpdater");
 
-                    mWebChromeClient.onReachedMaxAppCacheSize(spaceNeeded,
-                            totalUsedQuota, quotaUpdater);
+                    mWebChromeClient.onReachedMaxAppCacheSize(requiredStorage,
+                            quota, quotaUpdater);
                 }
                 break;
 
@@ -1462,19 +1462,21 @@
      * @param url The URL that caused the quota overflow.
      * @param databaseIdentifier The identifier of the database that the
      *     transaction that caused the overflow was running on.
-     * @param currentQuota The current quota the origin is allowed.
-     * @param estimatedSize The estimated size of the database.
-     * @param totalUsedQuota is the sum of all origins' quota.
+     * @param quota The current quota the origin is allowed.
+     * @param estimatedDatabaseSize The estimated size of the database.
+     * @param totalQuota is the sum of all origins' quota.
      * @param quotaUpdater An instance of a class encapsulating a callback
      *     to WebViewCore to run when the decision to allow or deny more
      *     quota has been made.
      */
     public void onExceededDatabaseQuota(
-            String url, String databaseIdentifier, long currentQuota,
-            long estimatedSize, long totalUsedQuota,
+            String url, String databaseIdentifier, long quota,
+            long estimatedDatabaseSize, long totalQuota,
             WebStorage.QuotaUpdater quotaUpdater) {
         if (mWebChromeClient == null) {
-            quotaUpdater.updateQuota(currentQuota);
+            // Native-side logic prevents the quota being updated to a smaller
+            // value.
+            quotaUpdater.updateQuota(quota);
             return;
         }
 
@@ -1482,9 +1484,9 @@
         HashMap<String, Object> map = new HashMap();
         map.put("databaseIdentifier", databaseIdentifier);
         map.put("url", url);
-        map.put("currentQuota", currentQuota);
-        map.put("estimatedSize", estimatedSize);
-        map.put("totalUsedQuota", totalUsedQuota);
+        map.put("quota", quota);
+        map.put("estimatedDatabaseSize", estimatedDatabaseSize);
+        map.put("totalQuota", totalQuota);
         map.put("quotaUpdater", quotaUpdater);
         exceededQuota.obj = map;
         sendMessage(exceededQuota);
@@ -1493,24 +1495,26 @@
     /**
      * Called by WebViewCore to inform the Java side that the appcache has
      * exceeded its max size.
-     * @param spaceNeeded is the amount of disk space that would be needed
-     * in order for the last appcache operation to succeed.
-     * @param totalUsedQuota is the sum of all origins' quota.
+     * @param requiredStorage is the amount of storage, in bytes, that would be
+     * needed in order for the last appcache operation to succeed.
+     * @param quota is the current quota (for all origins).
      * @param quotaUpdater An instance of a class encapsulating a callback
      * to WebViewCore to run when the decision to allow or deny a bigger
      * app cache size has been made.
      */
-    public void onReachedMaxAppCacheSize(long spaceNeeded,
-            long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) {
+    public void onReachedMaxAppCacheSize(long requiredStorage,
+            long quota, WebStorage.QuotaUpdater quotaUpdater) {
         if (mWebChromeClient == null) {
-            quotaUpdater.updateQuota(0);
+            // Native-side logic prevents the quota being updated to a smaller
+            // value.
+            quotaUpdater.updateQuota(quota);
             return;
         }
 
         Message msg = obtainMessage(REACHED_APPCACHE_MAXSIZE);
         HashMap<String, Object> map = new HashMap();
-        map.put("spaceNeeded", spaceNeeded);
-        map.put("totalUsedQuota", totalUsedQuota);
+        map.put("requiredStorage", requiredStorage);
+        map.put("quota", quota);
         map.put("quotaUpdater", quotaUpdater);
         msg.obj = map;
         sendMessage(msg);
@@ -1707,7 +1711,7 @@
 
     void onIsSupportedCallback(boolean isSupported) {
         Message msg = obtainMessage(SEARCHBOX_IS_SUPPORTED_CALLBACK);
-        msg.obj = new Boolean(isSupported);
+        msg.obj = Boolean.valueOf(isSupported);
         sendMessage(msg);
     }
 
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index 5f7ef41..2997c1a 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -26,7 +26,7 @@
  * Manages the cookies used by an application's {@link WebView} instances.
  * Cookies are manipulated according to RFC2109.
  */
-public final class CookieManager {
+public class CookieManager {
 
     private static CookieManager sRef;
 
diff --git a/core/java/android/webkit/GeolocationPermissions.java b/core/java/android/webkit/GeolocationPermissions.java
index 1160d57..a916884 100755
--- a/core/java/android/webkit/GeolocationPermissions.java
+++ b/core/java/android/webkit/GeolocationPermissions.java
@@ -50,7 +50,7 @@
 // Within WebKit, Geolocation permissions may be applied either temporarily
 // (for the duration of the page) or permanently. This class deals only with
 // permanent permissions.
-public final class GeolocationPermissions {
+public class GeolocationPermissions {
     /**
      * A callback interface used by the host application to set the Geolocation
      * permission state for an origin.
@@ -252,7 +252,7 @@
         }
         if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
             boolean allowed = nativeGetAllowed(origin);
-            callback.onReceiveValue(new Boolean(allowed));
+            callback.onReceiveValue(Boolean.valueOf(allowed));
         } else {
             Map values = new HashMap<String, Object>();
             values.put(ORIGIN, origin);
diff --git a/core/java/android/webkit/JsResult.java b/core/java/android/webkit/JsResult.java
index 07b686f..e4e6851 100644
--- a/core/java/android/webkit/JsResult.java
+++ b/core/java/android/webkit/JsResult.java
@@ -22,8 +22,6 @@
  * and provides a means for the client to indicate whether this action should proceed.
  */
 public class JsResult {
-    // This is a basic result of a confirm or prompt dialog.
-    protected boolean mResult;
     /**
      * Callback interface, implemented by the WebViewProvider implementation to receive
      * notifications when the JavaScript result represented by a JsResult instance has
@@ -32,11 +30,10 @@
     public interface ResultReceiver {
         public void onJsResultComplete(JsResult result);
     }
-    /**
-     * This is the caller of the prompt and is the object that is waiting.
-     * @hide
-     */
-    protected final ResultReceiver mReceiver;
+    // This is the caller of the prompt and is the object that is waiting.
+    private final ResultReceiver mReceiver;
+    // This is a basic result of a confirm or prompt dialog.
+    private boolean mResult;
 
     /**
      * Handle the result if the user cancelled the dialog.
@@ -69,7 +66,7 @@
     }
 
     /* Notify the caller that the JsResult has completed */
-    protected final void wakeUp() {
+    private final void wakeUp() {
         mReceiver.onJsResultComplete(this);
     }
 }
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 5cb0d41..4e8790b 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -216,37 +216,54 @@
     }
 
    /**
-    * Tell the client that the database quota for the origin has been exceeded.
-    * @param url The URL that triggered the notification
-    * @param databaseIdentifier The identifier of the database that caused the
-    *     quota overflow.
-    * @param currentQuota The current quota for the origin.
-    * @param estimatedSize The estimated size of the database.
-    * @param totalUsedQuota is the sum of all origins' quota.
-    * @param quotaUpdater A callback to inform the WebCore thread that a new
-    *     quota is available. This callback must always be executed at some
-    *     point to ensure that the sleeping WebCore thread is woken up.
+    * Tell the client that the quota has been exceeded for the Web SQL Database
+    * API for a particular origin and request a new quota. The client must
+    * respond by invoking the
+    * {@link WebStorage.QuotaUpdater#updateQuota(long) updateQuota(long)}
+    * method of the supplied {@link WebStorage.QuotaUpdater} instance. The
+    * minimum value that can be set for the new quota is the current quota. The
+    * default implementation responds with the current quota, so the quota will
+    * not be increased.
+    * @param url The URL of the page that triggered the notification
+    * @param databaseIdentifier The identifier of the database where the quota
+    *                           was exceeded.
+    * @param quota The quota for the origin, in bytes
+    * @param estimatedDatabaseSize The estimated size of the offending
+    *                              database, in bytes
+    * @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.
     */
+    // Note that the callback must always be executed at some point to ensure
+    // that the sleeping WebCore thread is woken up.
     public void onExceededDatabaseQuota(String url, String databaseIdentifier,
-        long currentQuota, long estimatedSize, long totalUsedQuota,
-        WebStorage.QuotaUpdater quotaUpdater) {
+            long quota, long estimatedDatabaseSize, long totalQuota,
+            WebStorage.QuotaUpdater quotaUpdater) {
         // This default implementation passes the current quota back to WebCore.
         // WebCore will interpret this that new quota was declined.
-        quotaUpdater.updateQuota(currentQuota);
+        quotaUpdater.updateQuota(quota);
     }
 
    /**
-    * Tell the client that the Application Cache has exceeded its max size.
-    * @param spaceNeeded is the amount of disk space that would be needed
-    * in order for the last appcache operation to succeed.
-    * @param totalUsedQuota is the sum of all origins' quota.
-    * @param quotaUpdater A callback to inform the WebCore thread that a new
-    * app cache size is available. This callback must always be executed at
-    * some point to ensure that the sleeping WebCore thread is woken up.
+    * Tell the client that the quota has been reached for the Application Cache
+    * API and request a new quota. The client must respond by invoking the
+    * {@link WebStorage.QuotaUpdater#updateQuota(long) updateQuota(long)}
+    * method of the supplied {@link WebStorage.QuotaUpdater} instance. The
+    * minimum value that can be set for the new quota is the current quota. The
+    * default implementation responds with the current quota, so the quota will
+    * not be increased.
+    * @param requiredStorage The amount of storage required by the Application
+    *                        Cache operation that triggered this notification,
+    *                        in bytes.
+    * @param quota The quota, in bytes
+    * @param quotaUpdater An instance of {@link WebStorage.QuotaUpdater} which
+    *                     must be used to inform the WebView of the new quota.
     */
-    public void onReachedMaxAppCacheSize(long spaceNeeded, long totalUsedQuota,
+    // Note that the callback must always be executed at some point to ensure
+    // that the sleeping WebCore thread is woken up.
+    public void onReachedMaxAppCacheSize(long requiredStorage, long quota,
             WebStorage.QuotaUpdater quotaUpdater) {
-        quotaUpdater.updateQuota(0);
+        quotaUpdater.updateQuota(quota);
     }
 
     /**
diff --git a/core/java/android/webkit/WebIconDatabase.java b/core/java/android/webkit/WebIconDatabase.java
index 54dfab3..9299b71 100644
--- a/core/java/android/webkit/WebIconDatabase.java
+++ b/core/java/android/webkit/WebIconDatabase.java
@@ -35,7 +35,7 @@
  * WebIconDatabase object is a single instance and all methods operate on that
  * single object.
  */
-public final class WebIconDatabase {
+public class WebIconDatabase {
     private static final String LOGTAG = "WebIconDatabase";
     // Global instance of a WebIconDatabase
     private static WebIconDatabase sIconDatabase;
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index cddd7ab..ba48da1 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -170,45 +170,66 @@
     }
 
     /**
-     * Set whether the WebView supports zoom
+     * Sets whether the WebView should support zooming using its on-screen zoom
+     * controls and gestures. The particular zoom mechanisms that should be used
+     * can be set with {@link #setBuiltInZoomControls}. This setting does not
+     * affect zooming performed using the {@link WebView#zoomIn()} and
+     * {@link WebView#zoomOut()} methods.
+     * @param support Whether the WebView should support zoom.
      */
     public void setSupportZoom(boolean support) {
         throw new MustOverrideException();
     }
 
     /**
-     * Returns whether the WebView supports zoom
+     * Returns true if the WebView supports zoom. The default is true.
+     * @return True if the WebView supports zoom.
      */
     public boolean supportZoom() {
         throw new MustOverrideException();
     }
 
     /**
-     * Sets whether the zoom mechanism built into WebView is used.
+     * Sets whether the WebView should use its built-in zoom mechanisms. The
+     * built-in zoom mechanisms comprise on-screen zoom controls, which are
+     * displayed over the WebView's content, and the use of a pinch gesture to
+     * control zooming. Whether or not these on-screen controls are displayed
+     * can be set with {@link #setDisplayZoomControls}.
+     * <p>
+     * The built-in mechanisms are the only currently supported zoom
+     * mechanisms, so it is recommended that this setting is always enabled.
+     * @param enabled Whether the WebView should use its built-in zoom mechanisms.
      */
+    // This method was intended to select between the built-in zoom mechanisms
+    // and the separate zoom controls. The latter were obtained using
+    // {@link WebView#getZoomControls}, which is now hidden.
     public void setBuiltInZoomControls(boolean enabled) {
         throw new MustOverrideException();
     }
 
     /**
-     * Returns true if the zoom mechanism built into WebView is being used.
+     * Returns true if the zoom mechanisms built into WebView are being used.
+     * The default is false.
+     * @return True if the zoom mechanisms built into WebView are being used.
      */
     public boolean getBuiltInZoomControls() {
         throw new MustOverrideException();
     }
 
     /**
-     * Sets whether the on screen zoom buttons are used.
-     * A combination of built in zoom controls enabled
-     * and on screen zoom controls disabled allows for pinch to zoom
-     * to work without the on screen controls
+     * Sets whether the WebView should display on-screen zoom controls when
+     * using the built-in zoom mechanisms. See {@link #setBuiltInZoomControls}.
+     * @param enabled Whether the WebView should display on-screen zoom controls.
      */
     public void setDisplayZoomControls(boolean enabled) {
         throw new MustOverrideException();
     }
 
     /**
-     * Returns true if the on screen zoom buttons are being used.
+     * Returns true if the WebView displays on-screen zoom controls when using
+     * the built-in zoom mechanisms. The default is true.
+     * @return True if the WebView displays on-screen zoom controls when using
+     * the built-in zoom mechanisms.
      */
     public boolean getDisplayZoomControls() {
         throw new MustOverrideException();
diff --git a/core/java/android/webkit/WebStorage.java b/core/java/android/webkit/WebStorage.java
index 3745258..041791b 100644
--- a/core/java/android/webkit/WebStorage.java
+++ b/core/java/android/webkit/WebStorage.java
@@ -25,19 +25,34 @@
 import java.util.Set;
 
 /**
- * Functionality for manipulating the webstorage databases.
+ * This class is used to manage the JavaScript storage APIs provided by the
+ * {@link WebView}. It manages the Application Cache API, the Web SQL Database
+ * API and the HTML5 Web Storage API.
+ *
+ * The Web SQL Database API provides storage which is private to a given
+ * origin, where an origin comprises the host, scheme and port of a URI.
+ * Similarly, use of the Application Cache API can be attributed to an origin.
+ * This class provides access to the storage use and quotas for these APIs for
+ * a given origin. Origins are represented using {@link WebStorage.Origin}.
  */
-public final class WebStorage {
+public class WebStorage {
 
     /**
-     * Encapsulates a callback function to be executed when a new quota is made
-     * available. 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 this the setDatabaseQuota method is
-     * executed once a decision to either allow or deny new quota is made,
-     * otherwise the WebCore thread will remain asleep.
+     * Encapsulates a callback function which is used to provide a new quota
+     * for a JavaScript storage API. See
+     * {@link WebChromeClient#onExceededDatabaseQuota} and
+     * {@link WebChromeClient#onReachedMaxAppCacheSize}.
      */
+    // 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.
     public interface QuotaUpdater {
+        /**
+         * Provide a new quota, specified in bytes.
+         * @param newQuota The new quota, in bytes
+         */
         public void updateQuota(long newQuota);
     };
 
@@ -70,7 +85,9 @@
     private Handler mUIHandler = null;
 
     /**
-     * Class containing the HTML5 database quota and usage for an origin.
+     * This class encapsulates information about the amount of storage
+     * currently used by an origin for the JavaScript storage APIs.
+     * See {@link WebStorage} for details.
      */
     public static class Origin {
         private String mOrigin = null;
@@ -93,28 +110,32 @@
         }
 
         /**
-         * An origin string is created using WebCore::SecurityOrigin::toString().
-         * Note that WebCore::SecurityOrigin uses 0 (which is not printed) for
-         * the port if the port is the default for the protocol. Eg
-         * http://www.google.com and http://www.google.com:80 both record a port
-         * of 0 and hence toString() == 'http://www.google.com' for both.
-         * @return The origin string.
+         * Get the string representation of this origin.
+         * @return The string representation of this origin
          */
+        // An origin string is created using WebCore::SecurityOrigin::toString().
+        // Note that WebCore::SecurityOrigin uses 0 (which is not printed) for
+        // the port if the port is the default for the protocol. Eg
+        // http://www.google.com and http://www.google.com:80 both record a port
+        // of 0 and hence toString() == 'http://www.google.com' for both.
         public String getOrigin() {
             return mOrigin;
         }
 
         /**
-         * Returns the quota for this origin's HTML5 database.
-         * @return The quota in bytes.
+         * Get the quota for this origin, for the Web SQL Database API, in
+         * bytes. If this origin does not use the Web SQL Database API, this
+         * quota will be set to zero.
+         * @return The quota, in bytes.
          */
         public long getQuota() {
             return mQuota;
         }
 
         /**
-         * Returns the usage for this origin's HTML5 database.
-         * @return The usage in bytes.
+         * Get the total amount of storage currently being used by this origin,
+         * for all JavaScript storage APIs, in bytes.
+         * @return The total amount of storage, in bytes.
          */
         public long getUsage() {
             return mUsage;
@@ -122,8 +143,8 @@
     }
 
     /**
-     * @hide
      * Message handler, UI side
+     * @hide
      */
     public void createUIHandler() {
         if (mUIHandler == null) {
@@ -156,8 +177,8 @@
     }
 
     /**
+     * Message handler, WebCore side
      * @hide
-     * Message handler, webcore side
      */
     public synchronized void createHandler() {
         if (mHandler == null) {
@@ -231,19 +252,22 @@
 
     /*
      * When calling getOrigins(), getUsageForOrigin() and getQuotaForOrigin(),
-     * we need to get the values from webcore, but we cannot block while doing so
-     * as we used to do, as this could result in a full deadlock (other webcore
+     * we need to get the values from WebCore, but we cannot block while doing so
+     * as we used to do, as this could result in a full deadlock (other WebCore
      * messages received while we are still blocked here, see http://b/2127737).
      *
      * We have to do everything asynchronously, by providing a callback function.
-     * We post a message on the webcore thread (mHandler) that will get the result
-     * from webcore, and we post it back on the UI thread (using mUIHandler).
+     * We post a message on the WebCore thread (mHandler) that will get the result
+     * from WebCore, and we post it back on the UI thread (using mUIHandler).
      * We can then use the callback function to return the value.
      */
 
     /**
-     * Returns a list of origins having a database. The Map is of type
-     * Map<String, Origin>.
+     * Get the origins currently using either the Application Cache or Web SQL
+     * Database APIs. This method operates asynchronously, with the result
+     * being provided via a {@link ValueCallback}. The origins are provided as
+     * a map, of type {@code Map<String, WebStorage.Origin>}, from the string
+     * representation of the origin to a {@link WebStorage.Origin} object.
      */
     public void getOrigins(ValueCallback<Map> callback) {
         if (callback != null) {
@@ -269,7 +293,11 @@
     }
 
     /**
-     * Returns the use for a given origin
+     * Get the amount of storage currently being used by both the Application
+     * Cache and Web SQL Database APIs by the given origin. The amount is given
+     * in bytes and the origin is specified using its string representation.
+     * This method operates asynchronously, with the result being provided via
+     * a {@link ValueCallback}.
      */
     public void getUsageForOrigin(String origin, ValueCallback<Long> callback) {
         if (callback == null) {
@@ -292,7 +320,11 @@
     }
 
     /**
-     * Returns the quota for a given origin
+     * Get the storage quota for the Web SQL Database API for the given origin.
+     * The quota is given in bytes and the origin is specified using its string
+     * representation. This method operates asynchronously, with the result
+     * being provided via a {@link ValueCallback}. Note that a quota is not
+     * enforced on a per-origin basis for the Application Cache API.
      */
     public void getQuotaForOrigin(String origin, ValueCallback<Long> callback) {
         if (callback == null) {
@@ -315,7 +347,10 @@
     }
 
     /**
-     * Set the quota for a given origin
+     * Set the storage quota for the Web SQL Database API for the given origin.
+     * The quota is specified in bytes and the origin is specified using its string
+     * representation. Note that a quota is not enforced on a per-origin basis
+     * for the Application Cache API.
      */
     public void setQuotaForOrigin(String origin, long quota) {
         if (origin != null) {
@@ -329,7 +364,9 @@
     }
 
     /**
-     * Delete a given origin
+     * Clear the storage currently being used by both the Application Cache and
+     * Web SQL Database APIs by the given origin. The origin is specified using
+     * its string representation.
      */
     public void deleteOrigin(String origin) {
         if (origin != null) {
@@ -343,7 +380,9 @@
     }
 
     /**
-     * Delete all databases
+     * Clear all storage currently being used by the JavaScript storage APIs.
+     * This includes the Application Cache, Web SQL Database and the HTML5 Web
+     * Storage APIs.
      */
     public void deleteAllData() {
         if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
@@ -381,8 +420,8 @@
     }
 
     /**
-     * Get the global instance of WebStorage.
-     * @return A single instance of WebStorage.
+     * Get the singleton instance of this class.
+     * @return The singleton {@link WebStorage} instance.
      */
     public static WebStorage getInstance() {
       if (sWebStorage == null) {
@@ -404,7 +443,7 @@
     }
 
     /**
-     * Run on the webcore thread
+     * Run on the WebCore thread
      * set the local values with the current ones
      */
     private void syncValues() {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 5498622..bd10cca 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1530,17 +1530,15 @@
     }
 
     /**
-     * Returns a view containing zoom controls i.e. +/- buttons. The caller is
-     * in charge of installing this view to the view hierarchy. This view will
-     * become visible when the user starts scrolling via touch and fade away if
-     * the user does not interact with it.
+     * Gets the zoom controls for the WebView, as a separate View. The caller is
+     * responsible for inserting this View into the layout hierarchy.
      * <p/>
-     * API version 3 introduces a built-in zoom mechanism that is shown
-     * automatically by the MapView. This is the preferred approach for
-     * showing the zoom UI.
+     * API Level 3 introduced built-in zoom mechanisms for the WebView, as
+     * opposed to these separate zoom controls. The built-in mechanisms are
+     * preferred and can be enabled using
+     * {@link WebSettings#setBuiltInZoomControls}.
      *
-     * @deprecated The built-in zoom mechanism is preferred, see
-     *             {@link WebSettings#setBuiltInZoomControls(boolean)}.
+     * @deprecated The built-in zoom mechanisms are preferred.
      * @hide since API version 16.
      */
     @Deprecated
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index 851fd22..893849b9 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -4677,6 +4677,9 @@
      * Select the word at the indicated content coordinates.
      */
     boolean selectText(int x, int y) {
+        if (mWebViewCore == null) {
+            return false;
+        }
         mWebViewCore.sendMessage(EventHub.SELECT_WORD_AT, x, y);
         return true;
     }
@@ -7144,7 +7147,8 @@
         if (mFindIsUp) return false;
         boolean result = false;
         result = mWebViewPrivate.super_requestFocus(direction, previouslyFocusedRect);
-        if (mWebViewCore.getSettings().getNeedInitialFocus() && !mWebView.isInTouchMode()) {
+        if (mWebViewCore.getSettings().getNeedInitialFocus()
+                && !mWebView.isInTouchMode()) {
             // For cases such as GMail, where we gain focus from a direction,
             // we want to move to the first available link.
             // FIXME: If there are no visible links, we may not want to
@@ -7165,7 +7169,7 @@
                 default:
                     return result;
             }
-            // TODO: Send initial focus request to webkit (b/6108927)
+            mWebViewCore.sendMessage(EventHub.SET_INITIAL_FOCUS, fakeKeyDirection);
         }
         return result;
     }
@@ -8089,10 +8093,6 @@
             mWebView.invalidate();
         }
 
-        if (mPictureListener != null) {
-            mPictureListener.onNewPicture(getWebView(), capturePicture());
-        }
-
         // update the zoom information based on the new picture
         mZoomManager.onNewPicture(draw);
 
@@ -8100,6 +8100,10 @@
             mViewManager.postReadyToDrawAll();
         }
         scrollEditWithCursor();
+
+        if (mPictureListener != null) {
+            mPictureListener.onNewPicture(getWebView(), capturePicture());
+        }
     }
 
     /**
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index c83d106..aea23c0 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -430,38 +430,38 @@
      * Notify the browser that the origin has exceeded it's database quota.
      * @param url The URL that caused the overflow.
      * @param databaseIdentifier The identifier of the database.
-     * @param currentQuota The current quota for the origin.
-     * @param estimatedSize The estimated size of the database.
+     * @param quota The current quota for the origin.
+     * @param estimatedDatabaseSize The estimated size of the database.
      */
     protected void exceededDatabaseQuota(String url,
                                          String databaseIdentifier,
-                                         long currentQuota,
-                                         long estimatedSize) {
+                                         long quota,
+                                         long estimatedDatabaseSize) {
         // Inform the callback proxy of the quota overflow. Send an object
         // that encapsulates a call to the nativeSetDatabaseQuota method to
         // awaken the sleeping webcore thread when a decision from the
         // client to allow or deny quota is available.
         mCallbackProxy.onExceededDatabaseQuota(url, databaseIdentifier,
-                currentQuota, estimatedSize, getUsedQuota(),
+                quota, estimatedDatabaseSize, getUsedQuota(),
                 new WebStorage.QuotaUpdater() {
                         @Override
-                        public void updateQuota(long quota) {
-                            nativeSetNewStorageLimit(mNativeClass, quota);
+                        public void updateQuota(long newQuota) {
+                            nativeSetNewStorageLimit(mNativeClass, newQuota);
                         }
                 });
     }
 
     /**
      * Notify the browser that the appcache has exceeded its max size.
-     * @param spaceNeeded is the amount of disk space that would be needed
-     * in order for the last appcache operation to succeed.
+     * @param requiredStorage is the amount of storage, in bytes, that would be
+     * needed in order for the last appcache operation to succeed.
      */
-    protected void reachedMaxAppCacheSize(long spaceNeeded) {
-        mCallbackProxy.onReachedMaxAppCacheSize(spaceNeeded, getUsedQuota(),
+    protected void reachedMaxAppCacheSize(long requiredStorage) {
+        mCallbackProxy.onReachedMaxAppCacheSize(requiredStorage, getUsedQuota(),
                 new WebStorage.QuotaUpdater() {
                     @Override
-                    public void updateQuota(long quota) {
-                        nativeSetNewStorageLimit(mNativeClass, quota);
+                    public void updateQuota(long newQuota) {
+                        nativeSetNewStorageLimit(mNativeClass, newQuota);
                     }
                 });
     }
@@ -1176,6 +1176,7 @@
 
         // key was pressed (down and up)
         static final int KEY_PRESS = 223;
+        static final int SET_INITIAL_FOCUS = 224;
 
         // Private handler for WebCore messages.
         private Handler mHandler;
@@ -1748,6 +1749,9 @@
                                     WebViewClassic.UPDATE_MATCH_COUNT, request).sendToTarget();
                             break;
                         }
+                        case SET_INITIAL_FOCUS:
+                            nativeSetInitialFocus(mNativeClass, msg.arg1);
+                            break;
                     }
                 }
             };
@@ -1768,6 +1772,9 @@
 
         @Override
         public boolean dispatchWebKitEvent(MotionEvent event, int eventType, int flags) {
+            if (mNativeClass == 0) {
+                return false;
+            }
             switch (eventType) {
                 case WebViewInputDispatcher.EVENT_TYPE_CLICK:
                     return nativeMouseClick(mNativeClass);
@@ -3071,6 +3078,7 @@
     private native void nativeClearTextSelection(int nativeClass);
     private native boolean nativeSelectWordAt(int nativeClass, int x, int y);
     private native void nativeSelectAll(int nativeClass);
+    private native void nativeSetInitialFocus(int nativeClass, int keyDirection);
 
     private static native void nativeCertTrustChanged();
 }
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 057aabe..e68049c 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2062,6 +2062,10 @@
 
             child = mAdapter.getView(position, scrapView, this);
 
+            if (child.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
+                child.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+            }
+
             if (ViewDebug.TRACE_RECYCLER) {
                 ViewDebug.trace(child, ViewDebug.RecyclerTraceType.BIND_VIEW,
                         position, getChildCount());
@@ -2082,6 +2086,11 @@
             }
         } else {
             child = mAdapter.getView(position, null, this);
+
+            if (child.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
+                child.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+            }
+
             if (mCacheColorHint != 0) {
                 child.setDrawingCacheBackgroundColor(mCacheColorHint);
             }
diff --git a/core/java/android/widget/AbsSpinner.java b/core/java/android/widget/AbsSpinner.java
index efdfae3..f279f8e 100644
--- a/core/java/android/widget/AbsSpinner.java
+++ b/core/java/android/widget/AbsSpinner.java
@@ -191,6 +191,10 @@
             if (view == null) {
                 // Make a new one
                 view = mAdapter.getView(selectedPosition, null, this);
+
+                if (view.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
+                    view.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+                }
             }
 
             if (view != null) {
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index 97a864c..abfc577 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -24,14 +24,15 @@
 import android.util.SparseArray;
 import android.view.ContextMenu;
 import android.view.ContextMenu.ContextMenuInfo;
+import android.view.MotionEvent;
 import android.view.SoundEffectConstants;
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
 
-
 /**
  * An AdapterView is a view whose children are determined by an {@link Adapter}.
  *
@@ -232,6 +233,11 @@
 
     public AdapterView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
+
+        // If not explicitly specified this view is important for accessibility.
+        if (getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
+            setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+        }
     }
 
     /**
@@ -643,6 +649,12 @@
     public void setEmptyView(View emptyView) {
         mEmptyView = emptyView;
 
+        // If not explicitly specified this view is important for accessibility.
+        if (emptyView != null
+                && emptyView.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
+            emptyView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+        }
+
         final T adapter = getAdapter();
         final boolean empty = ((adapter == null) || adapter.isEmpty());
         updateEmptyStatus(empty);
@@ -846,12 +858,14 @@
                 }
             } else {
                 fireOnSelected();
+                performAccessibilityActionsOnSelected();
             }
         }
     }
 
     void selectionChanged() {
-        if (mOnItemSelectedListener != null) {
+        if (mOnItemSelectedListener != null
+                || AccessibilityManager.getInstance(mContext).isEnabled()) {
             if (mInLayout || mBlockLayoutRequests) {
                 // If we are in a layout traversal, defer notification
                 // by posting. This ensures that the view tree is
@@ -863,20 +877,16 @@
                 post(mSelectionNotifier);
             } else {
                 fireOnSelected();
+                performAccessibilityActionsOnSelected();
             }
         }
-
-        // we fire selection events here not in View
-        if (mSelectedPosition != ListView.INVALID_POSITION && isShown() && !isInTouchMode()) {
-            sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
-        }
     }
 
     private void fireOnSelected() {
-        if (mOnItemSelectedListener == null)
+        if (mOnItemSelectedListener == null) {
             return;
-
-        int selection = this.getSelectedItemPosition();
+        }
+        final int selection = getSelectedItemPosition();
         if (selection >= 0) {
             View v = getSelectedView();
             mOnItemSelectedListener.onItemSelected(this, v, selection,
@@ -886,6 +896,17 @@
         }
     }
 
+    private void performAccessibilityActionsOnSelected() {
+        if (!AccessibilityManager.getInstance(mContext).isEnabled()) {
+            return;
+        }
+        final int position = getSelectedItemPosition();
+        if (position >= 0) {
+            // we fire selection events here not in View
+            sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
+        }
+    }
+
     @Override
     public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
         View selectedView = getSelectedView();
@@ -936,6 +957,24 @@
         event.setItemCount(getCount());
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    public boolean onRequestAccessibilityFocusFromHover(float x, float y) {
+        // We prefer to five focus to the child instead of this view.
+        // Usually the children are not actionable for accessibility,
+        // and they will not take accessibility focus, so we give it.
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View child = getChildAt(i);
+            if (isTransformedTouchPointInView(x, y, child, null)) {
+                return child.requestAccessibilityFocus();
+            }
+        }
+        return super.onRequestAccessibilityFocusFromHover(x, y);
+    }
+
     private boolean isScrollableForAccessibility() {
         T adapter = getAdapter();
         if (adapter != null) {
@@ -1012,6 +1051,9 @@
             mNeedSync = false;
             checkSelectionChanged();
         }
+
+        //TODO: Hmm, we do not know the old state so this is sub-optimal
+        notifyAccessibilityStateChanged();
     }
 
     void checkSelectionChanged() {
diff --git a/core/java/android/widget/AdapterViewAnimator.java b/core/java/android/widget/AdapterViewAnimator.java
index bb00049..c557963 100644
--- a/core/java/android/widget/AdapterViewAnimator.java
+++ b/core/java/android/widget/AdapterViewAnimator.java
@@ -414,6 +414,10 @@
             // get the fresh child from the adapter
             final View updatedChild = mAdapter.getView(modulo(i, adapterCount), null, this);
 
+            if (updatedChild.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
+                updatedChild.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+            }
+
             if (mViewsMap.containsKey(index)) {
                 final FrameLayout fl = (FrameLayout) mViewsMap.get(index).view;
                 // add the new child to the frame, if it exists
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index c5066b6..108b720 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -279,8 +279,13 @@
         // re-order the number spinners to match the current date format
         reorderSpinners();
 
-        // set content descriptions
+        // accessibility
         setContentDescriptions();
+
+        // If not explicitly specified this view is important for accessibility.
+        if (getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
+            setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+        }
     }
 
     /**
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index cbff58c..040a385 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1681,7 +1681,7 @@
         final int itemCount = clipData.getItemCount();
         for (int i=0; i < itemCount; i++) {
             Item item = clipData.getItemAt(i);
-            content.append(item.coerceToText(mTextView.getContext()));
+            content.append(item.coerceToStyledText(mTextView.getContext()));
         }
 
         final int offset = mTextView.getOffsetForPosition(event.getX(), event.getY());
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 60dd55c..1cb676f 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -20,6 +20,7 @@
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.Insets;
 import android.graphics.Paint;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -559,9 +560,9 @@
         int flags = (gravity & mask) >> shift;
         switch (flags) {
             case (AXIS_SPECIFIED | AXIS_PULL_BEFORE):
-                return LEADING;
+                return horizontal ? LEFT : TOP;
             case (AXIS_SPECIFIED | AXIS_PULL_AFTER):
-                return TRAILING;
+                return horizontal ? RIGHT : BOTTOM;
             case (AXIS_SPECIFIED | AXIS_PULL_BEFORE | AXIS_PULL_AFTER):
                 return FILL;
             case AXIS_SPECIFIED:
@@ -1042,12 +1043,15 @@
             int rightMargin = getMargin(c, true, false);
             int bottomMargin = getMargin(c, false, false);
 
-            // Alignment offsets: the location of the view relative to its alignment group.
-            int alignmentOffsetX = boundsX.getOffset(c, hAlign, leftMargin + pWidth + rightMargin);
-            int alignmentOffsetY = boundsY.getOffset(c, vAlign, topMargin + pHeight + bottomMargin);
+            int sumMarginsX = leftMargin + rightMargin;
+            int sumMarginsY = topMargin + bottomMargin;
 
-            int width = hAlign.getSizeInCell(c, pWidth, cellWidth - leftMargin - rightMargin);
-            int height = vAlign.getSizeInCell(c, pHeight, cellHeight - topMargin - bottomMargin);
+            // Alignment offsets: the location of the view relative to its alignment group.
+            int alignmentOffsetX = boundsX.getOffset(this, c, hAlign, pWidth + sumMarginsX, true);
+            int alignmentOffsetY = boundsY.getOffset(this, c, vAlign, pHeight + sumMarginsY, false);
+
+            int width = hAlign.getSizeInCell(c, pWidth, cellWidth - sumMarginsX);
+            int height = vAlign.getSizeInCell(c, pHeight, cellHeight - sumMarginsY);
 
             int dx = x1 + gravityOffsetX + alignmentOffsetX;
 
@@ -1181,7 +1185,7 @@
                 View c = getChildAt(i);
                 LayoutParams lp = getLayoutParams(c);
                 Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
-                groupBounds.getValue(i).include(c, spec, GridLayout.this, this);
+                groupBounds.getValue(i).include(GridLayout.this, c, spec, this);
             }
         }
 
@@ -2138,16 +2142,30 @@
             return before + after;
         }
 
-        protected int getOffset(View c, Alignment alignment, int size) {
-            return before - alignment.getAlignmentValue(c, size);
+        private int getAlignmentValue(GridLayout gl, View c, int size, Alignment a, boolean horiz) {
+            boolean useLayoutBounds = gl.getLayoutMode() == LAYOUT_BOUNDS;
+            if (!useLayoutBounds) {
+                return a.getAlignmentValue(c, size);
+            } else {
+                Insets insets = c.getLayoutInsets();
+                int leadingInset = horiz ? insets.left : insets.top; // RTL?
+                int trailingInset = horiz ? insets.right : insets.bottom; // RTL?
+                int totalInset = leadingInset + trailingInset;
+                return leadingInset + a.getAlignmentValue(c, size - totalInset);
+            }
         }
 
-        protected final void include(View c, Spec spec, GridLayout gridLayout, Axis axis) {
+        protected int getOffset(GridLayout gl, View c, Alignment a, int size, boolean horizontal) {
+            return before - getAlignmentValue(gl, c, size, a, horizontal);
+        }
+
+        protected final void include(GridLayout gl, View c, Spec spec, Axis axis) {
             this.flexibility &= spec.getFlexibility();
-            int size = gridLayout.getMeasurementIncludingMargin(c, axis.horizontal);
-            Alignment alignment = gridLayout.getAlignment(spec.alignment, axis.horizontal);
+            boolean horizontal = axis.horizontal;
+            int size = gl.getMeasurementIncludingMargin(c, horizontal);
+            Alignment alignment = gl.getAlignment(spec.alignment, horizontal);
             // todo test this works correctly when the returned value is UNDEFINED
-            int before = alignment.getAlignmentValue(c, size);
+            int before = getAlignmentValue(gl, c, size, alignment, horizontal);
             include(before, size - before);
         }
 
@@ -2614,8 +2632,8 @@
                 }
 
                 @Override
-                protected int getOffset(View c, Alignment alignment, int size) {
-                    return max(0, super.getOffset(c, alignment, size));
+                protected int getOffset(GridLayout gl, View c, Alignment a, int size, boolean hrz) {
+                    return max(0, super.getOffset(gl, c, a, size, hrz));
                 }
             };
         }
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 91e2e497..6c7ea67 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -105,11 +105,11 @@
         super(context);
         initImageView();
     }
-    
+
     public ImageView(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
-    
+
     public ImageView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
         initImageView();
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index b2321d9..992849d 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -112,8 +112,7 @@
     private static final int SELECTOR_ADJUSTMENT_DURATION_MILLIS = 800;
 
     /**
-     * The duration of scrolling to the next/previous value while snapping to
-     * a given position.
+     * The duration of scrolling while snapping to a given position.
      */
     private static final int SNAP_SCROLL_DURATION = 300;
 
@@ -680,6 +679,11 @@
         mAdjustScroller = new Scroller(getContext(), new DecelerateInterpolator(2.5f));
 
         updateInputTextView();
+
+        // If not explicitly specified this view is important for accessibility.
+        if (getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
+            setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+        }
     }
 
     @Override
diff --git a/core/java/android/widget/ShareActionProvider.java b/core/java/android/widget/ShareActionProvider.java
index 22e9ef1..080b87d 100644
--- a/core/java/android/widget/ShareActionProvider.java
+++ b/core/java/android/widget/ShareActionProvider.java
@@ -80,16 +80,22 @@
 
         /**
          * Called when a share target has been selected. The client can
-         * decide whether to handle the intent or rely on the default
-         * behavior which is launching it.
+         * decide whether to perform some action before the sharing is
+         * actually performed.
          * <p>
          * <strong>Note:</strong> Modifying the intent is not permitted and
          *     any changes to the latter will be ignored.
          * </p>
+         * <p>
+         * <strong>Note:</strong> You should <strong>not</strong> handle the
+         *     intent here. This callback aims to notify the client that a
+         *     sharing is being performed, so the client can update the UI
+         *     if necessary.
+         * </p>
          *
          * @param source The source of the notification.
          * @param intent The intent for launching the chosen share target.
-         * @return Whether the client has handled the intent.
+         * @return The return result is ignored. Always return false for consistency.
          */
         public boolean onShareTargetSelected(ShareActionProvider source, Intent intent);
     }
@@ -308,7 +314,7 @@
         @Override
         public boolean onChooseActivity(ActivityChooserModel host, Intent intent) {
             if (mOnShareTargetSelectedListener != null) {
-                return mOnShareTargetSelectedListener.onShareTargetSelected(
+                mOnShareTargetSelectedListener.onShareTargetSelected(
                         ShareActionProvider.this, intent);
             }
             return false;
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index c725b64..a13ee5a 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -24,6 +24,7 @@
 import android.text.method.WordIterator;
 import android.text.style.SpellCheckSpan;
 import android.text.style.SuggestionSpan;
+import android.util.Log;
 import android.view.textservice.SentenceSuggestionsInfo;
 import android.view.textservice.SpellCheckerSession;
 import android.view.textservice.SpellCheckerSession.SpellCheckerSessionListener;
@@ -43,6 +44,8 @@
  * @hide
  */
 public class SpellChecker implements SpellCheckerSessionListener {
+    private static final String TAG = SpellChecker.class.getSimpleName();
+    private static final boolean DBG = false;
 
     // No more than this number of words will be parsed on each iteration to ensure a minimum
     // lock of the UI thread
@@ -116,7 +119,7 @@
                     null /* Bundle not currently used by the textServicesManager */,
                     mCurrentLocale, this,
                     false /* means any available languages from current spell checker */);
-            mIsSentenceSpellCheckSupported = mSpellCheckerSession.isSentenceSpellCheckSupported();
+            mIsSentenceSpellCheckSupported = true;
         }
 
         // Restore SpellCheckSpans in pool
@@ -266,6 +269,12 @@
                         editable.subSequence(start, end).toString();
                 spellCheckSpan.setSpellCheckInProgress(true);
                 textInfos[textInfosCount++] = new TextInfo(word, mCookie, mIds[i]);
+                if (DBG) {
+                    Log.d(TAG, "create TextInfo: (" + i + "/" + mLength + ")" + word
+                            + ", cookie = " + mCookie + ", seq = "
+                            + mIds[i] + ", sel start = " + selectionStart + ", sel end = "
+                            + selectionEnd + ", start = " + start + ", end = " + end);
+                }
             }
         }
 
@@ -507,7 +516,20 @@
                 if (regionEnd <= spellCheckStart) {
                     return;
                 }
-                addSpellCheckSpan(editable, spellCheckStart, regionEnd);
+                final int selectionStart = Selection.getSelectionStart(editable);
+                final int selectionEnd = Selection.getSelectionEnd(editable);
+                if (DBG) {
+                    Log.d(TAG, "addSpellCheckSpan: "
+                            + editable.subSequence(spellCheckStart, regionEnd)
+                            + ", regionEnd = " + regionEnd + ", spellCheckStart = "
+                            + spellCheckStart + ", sel start = " + selectionStart + ", sel end ="
+                            + selectionEnd);
+                }
+                // Do not check this word if the user is currently editing it
+                if (spellCheckStart >= 0 && regionEnd > spellCheckStart
+                        && (selectionEnd < spellCheckStart || selectionStart > regionEnd)) {
+                    addSpellCheckSpan(editable, spellCheckStart, regionEnd);
+                }
             } else {
                 while (wordStart <= end) {
                     if (wordEnd >= start && wordEnd > wordStart) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 9867e47..37d9db7 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -1105,6 +1105,11 @@
         setLongClickable(longClickable);
 
         if (mEditor != null) mEditor.prepareCursorControllers();
+
+        // If not explicitly specified this view is important for accessibility.
+        if (getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
+            setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+        }
     }
 
     private void setTypefaceByIndex(int typefaceIndex, int styleIndex) {
@@ -7710,7 +7715,7 @@
         if (clip != null) {
             boolean didFirst = false;
             for (int i=0; i<clip.getItemCount(); i++) {
-                CharSequence paste = clip.getItemAt(i).coerceToText(getContext());
+                CharSequence paste = clip.getItemAt(i).coerceToStyledText(getContext());
                 if (paste != null) {
                     if (!didFirst) {
                         long minMax = prepareSpacesAroundPaste(min, max, paste);
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index bc88b62..18f7a91 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -251,6 +251,11 @@
 
         // set the content descriptions
         setContentDescriptions();
+
+        // If not explicitly specified this view is important for accessibility.
+        if (getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
+            setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+        }
     }
 
     @Override
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index f1dffa1..1ba6d43 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -51,6 +51,7 @@
 import android.view.ViewGroup;
 import android.view.Window;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.animation.AnimationUtils;
 import android.widget.SpinnerAdapter;
 
 import java.lang.ref.WeakReference;
@@ -596,19 +597,23 @@
         if (mCurWindowVisibility == View.VISIBLE && (mShowHideAnimationEnabled
                 || alwaysAnimate)) {
             mTopVisibilityView.setAlpha(0);
+            mTopVisibilityView.setTranslationY(-mTopVisibilityView.getHeight());
             AnimatorSet anim = new AnimatorSet();
             AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mTopVisibilityView, "alpha", 1));
+            b.with(ObjectAnimator.ofFloat(mTopVisibilityView, "translationY", 0));
             if (mContentView != null) {
                 b.with(ObjectAnimator.ofFloat(mContentView, "translationY",
                         -mTopVisibilityView.getHeight(), 0));
-                mTopVisibilityView.setTranslationY(-mTopVisibilityView.getHeight());
-                b.with(ObjectAnimator.ofFloat(mTopVisibilityView, "translationY", 0));
             }
             if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
                 mSplitView.setAlpha(0);
+                mSplitView.setTranslationY(mSplitView.getHeight());
                 mSplitView.setVisibility(View.VISIBLE);
                 b.with(ObjectAnimator.ofFloat(mSplitView, "alpha", 1));
+                b.with(ObjectAnimator.ofFloat(mSplitView, "translationY", 0));
             }
+            anim.setInterpolator(AnimationUtils.loadInterpolator(mContext,
+                    com.android.internal.R.interpolator.decelerate_quad));
             anim.addListener(mShowListener);
             mCurrentShowAnim = anim;
             anim.start();
@@ -638,16 +643,20 @@
             mContainerView.setTransitioning(true);
             AnimatorSet anim = new AnimatorSet();
             AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mTopVisibilityView, "alpha", 0));
+            b.with(ObjectAnimator.ofFloat(mTopVisibilityView, "translationY",
+                    -mTopVisibilityView.getHeight()));
             if (mContentView != null) {
                 b.with(ObjectAnimator.ofFloat(mContentView, "translationY",
                         0, -mTopVisibilityView.getHeight()));
-                b.with(ObjectAnimator.ofFloat(mTopVisibilityView, "translationY",
-                        -mTopVisibilityView.getHeight()));
             }
             if (mSplitView != null && mSplitView.getVisibility() == View.VISIBLE) {
                 mSplitView.setAlpha(1);
                 b.with(ObjectAnimator.ofFloat(mSplitView, "alpha", 0));
+                b.with(ObjectAnimator.ofFloat(mSplitView, "translationY",
+                        mSplitView.getHeight()));
             }
+            anim.setInterpolator(AnimationUtils.loadInterpolator(mContext,
+                    com.android.internal.R.interpolator.accelerate_quad));
             anim.addListener(mHideListener);
             mCurrentShowAnim = anim;
             anim.start();
diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java
index a0e125a..37567fd 100644
--- a/core/java/com/android/internal/app/PlatLogoActivity.java
+++ b/core/java/com/android/internal/app/PlatLogoActivity.java
@@ -29,9 +29,9 @@
 import android.widget.Toast;
 
 public class PlatLogoActivity extends Activity {
+    Vibrator mZzz;
     Toast mToast;
     ImageView mContent;
-    Vibrator mZzz = new Vibrator();
     int mCount;
     final Handler mHandler = new Handler();
 
@@ -63,7 +63,8 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        
+
+        mZzz = (Vibrator)getSystemService(VIBRATOR_SERVICE);
         mToast = Toast.makeText(this, "Android 4.0: Ice Cream Sandwich", Toast.LENGTH_SHORT);
 
         mContent = new ImageView(this);
diff --git a/core/java/com/android/internal/app/ShutdownThread.java b/core/java/com/android/internal/app/ShutdownThread.java
index 77d0c97..6a46929 100644
--- a/core/java/com/android/internal/app/ShutdownThread.java
+++ b/core/java/com/android/internal/app/ShutdownThread.java
@@ -37,6 +37,7 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.Vibrator;
+import android.os.SystemVibrator;
 import android.os.storage.IMountService;
 import android.os.storage.IMountShutdownObserver;
 
@@ -399,7 +400,7 @@
             }
         } else if (SHUTDOWN_VIBRATE_MS > 0) {
             // vibrate before shutting down
-            Vibrator vibrator = new Vibrator();
+            Vibrator vibrator = new SystemVibrator();
             try {
                 vibrator.vibrate(SHUTDOWN_VIBRATE_MS);
             } catch (Exception e) {
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index d1aa1ce..dbf6c8e 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -201,4 +201,40 @@
         }
         return array;
     }
+
+    public static int[] appendInt(int[] cur, int val) {
+        if (cur == null) {
+            return new int[] { val };
+        }
+        final int N = cur.length;
+        for (int i = 0; i < N; i++) {
+            if (cur[i] == val) {
+                return cur;
+            }
+        }
+        int[] ret = new int[N + 1];
+        System.arraycopy(cur, 0, ret, 0, N);
+        ret[N] = val;
+        return ret;
+    }
+
+    public static int[] removeInt(int[] cur, int val) {
+        if (cur == null) {
+            return null;
+        }
+        final int N = cur.length;
+        for (int i = 0; i < N; i++) {
+            if (cur[i] == val) {
+                int[] ret = new int[N - 1];
+                if (i > 0) {
+                    System.arraycopy(cur, 0, ret, 0, i);
+                }
+                if (i < (N - 1)) {
+                    System.arraycopy(cur, i + 1, ret, i, N - i - 1);
+                }
+                return ret;
+            }
+        }
+        return cur;
+    }
 }
diff --git a/core/java/com/android/internal/util/AsyncChannel.java b/core/java/com/android/internal/util/AsyncChannel.java
index 3973344..0c5d5ef 100644
--- a/core/java/com/android/internal/util/AsyncChannel.java
+++ b/core/java/com/android/internal/util/AsyncChannel.java
@@ -150,6 +150,24 @@
      */
     public static final int CMD_CHANNEL_DISCONNECTED = BASE + 4;
 
+    private static final int CMD_TO_STRING_COUNT = CMD_CHANNEL_DISCONNECTED + 1;
+    private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
+    static {
+        sCmdToString[CMD_CHANNEL_HALF_CONNECTED - BASE] = "CMD_CHANNEL_HALF_CONNECTED";
+        sCmdToString[CMD_CHANNEL_FULL_CONNECTION - BASE] = "CMD_CHANNEL_FULL_CONNECTION";
+        sCmdToString[CMD_CHANNEL_FULLY_CONNECTED - BASE] = "CMD_CHANNEL_FULLY_CONNECTED";
+        sCmdToString[CMD_CHANNEL_DISCONNECT - BASE] = "CMD_CHANNEL_DISCONNECT";
+        sCmdToString[CMD_CHANNEL_DISCONNECTED - BASE] = "CMD_CHANNEL_DISCONNECTED";
+    }
+    protected static String cmdToString(int cmd) {
+        cmd -= BASE;
+        if ((cmd >= 0) && (cmd < sCmdToString.length)) {
+            return sCmdToString[cmd];
+        } else {
+            return null;
+        }
+    }
+
     /** Successful status always 0, !0 is an unsuccessful status */
     public static final int STATUS_SUCCESSFUL = 0;
 
diff --git a/core/java/com/android/internal/util/IndentingPrintWriter.java b/core/java/com/android/internal/util/IndentingPrintWriter.java
index 3dd2284..699e9b3 100644
--- a/core/java/com/android/internal/util/IndentingPrintWriter.java
+++ b/core/java/com/android/internal/util/IndentingPrintWriter.java
@@ -46,6 +46,10 @@
         mCurrent = mBuilder.toString();
     }
 
+    public void printPair(String key, Object value) {
+        print(key + "=" + String.valueOf(value) + " ");
+    }
+
     @Override
     public void println() {
         super.println();
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index 07496a7..1391ac3 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -20,9 +20,13 @@
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Message;
+import android.text.TextUtils;
 import android.util.Log;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Calendar;
 import java.util.HashMap;
 import java.util.Vector;
 
@@ -444,9 +448,11 @@
      * The information maintained for a processed message.
      */
     public static class ProcessedMessageInfo {
-        private int what;
-        private State state;
-        private State orgState;
+        private long mTime;
+        private int mWhat;
+        private String mInfo;
+        private State mState;
+        private State mOrgState;
 
         /**
          * Constructor
@@ -455,8 +461,8 @@
          * @param orgState is the first state the received the message but
          * did not processes the message.
          */
-        ProcessedMessageInfo(Message message, State state, State orgState) {
-            update(message, state, orgState);
+        ProcessedMessageInfo(Message msg, String info, State state, State orgState) {
+            update(msg, info, state, orgState);
         }
 
         /**
@@ -465,31 +471,47 @@
          * @param orgState is the first state the received the message but
          * did not processes the message.
          */
-        public void update(Message message, State state, State orgState) {
-            this.what = message.what;
-            this.state = state;
-            this.orgState = orgState;
+        public void update(Message msg, String info, State state, State orgState) {
+            mTime = System.currentTimeMillis();
+            mWhat = msg.what;
+            mInfo = info;
+            mState = state;
+            mOrgState = orgState;
+        }
+
+        /**
+         * @return time stamp
+         */
+        public long getTime() {
+            return mTime;
+        }
+
+        /**
+         * @return msg.what
+         */
+        public long getWhat() {
+            return mWhat;
         }
 
         /**
          * @return the command that was executing
          */
-        public int getWhat() {
-            return what;
+        public String getInfo() {
+            return mInfo;
         }
 
         /**
          * @return the state that handled this message
          */
         public State getState() {
-            return state;
+            return mState;
         }
 
         /**
          * @return the original state that received the message.
          */
         public State getOriginalState() {
-            return orgState;
+            return mOrgState;
         }
 
         /**
@@ -498,26 +520,24 @@
         @Override
         public String toString() {
             StringBuilder sb = new StringBuilder();
-            sb.append("what=");
-            sb.append(what);
+            sb.append("time=");
+            Calendar c = Calendar.getInstance();
+            c.setTimeInMillis(mTime);
+            sb.append(String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c));
             sb.append(" state=");
-            sb.append(cn(state));
+            sb.append(mState == null ? "<null>" : mState.getName());
             sb.append(" orgState=");
-            sb.append(cn(orgState));
-            return sb.toString();
-        }
-
-        /**
-         * @return an objects class name
-         */
-        private String cn(Object n) {
-            if (n == null) {
-                return "null";
-            } else {
-                String name = n.getClass().getName();
-                int lastDollar = name.lastIndexOf('$');
-                return name.substring(lastDollar + 1);
+            sb.append(mOrgState == null ? "<null>" : mOrgState.getName());
+            sb.append(" what=");
+            sb.append(mWhat);
+            sb.append("(0x");
+            sb.append(Integer.toHexString(mWhat));
+            sb.append(")");
+            if ( ! TextUtils.isEmpty(mInfo)) {
+                sb.append(" ");
+                sb.append(mInfo);
             }
+            return sb.toString();
         }
     }
 
@@ -542,9 +562,9 @@
         private int mCount = 0;
 
         /**
-         * Constructor
+         * private constructor use add
          */
-        ProcessedMessages() {
+        private ProcessedMessages() {
         }
 
         /**
@@ -599,22 +619,23 @@
         /**
          * Add a processed message.
          *
-         * @param message
+         * @param msg
+         * @param messageInfo to be stored
          * @param state that handled the message
          * @param orgState is the first state the received the message but
          * did not processes the message.
          */
-        void add(Message message, State state, State orgState) {
+        void add(Message msg, String messageInfo, State state, State orgState) {
             mCount += 1;
             if (mMessages.size() < mMaxSize) {
-                mMessages.add(new ProcessedMessageInfo(message, state, orgState));
+                mMessages.add(new ProcessedMessageInfo(msg, messageInfo, state, orgState));
             } else {
                 ProcessedMessageInfo pmi = mMessages.get(mOldestIndex);
                 mOldestIndex += 1;
                 if (mOldestIndex >= mMaxSize) {
                     mOldestIndex = 0;
                 }
-                pmi.update(message, state, orgState);
+                pmi.update(msg, messageInfo, state, orgState);
             }
         }
     }
@@ -894,11 +915,14 @@
             /**
              * Record that we processed the message
              */
-            if (curStateInfo != null) {
-                State orgState = mStateStack[mStateStackTopIndex].state;
-                mProcessedMessages.add(msg, curStateInfo.state, orgState);
-            } else {
-                mProcessedMessages.add(msg, null, null);
+            if (mSm.recordProcessedMessage(msg)) {
+                if (curStateInfo != null) {
+                    State orgState = mStateStack[mStateStackTopIndex].state;
+                    mProcessedMessages.add(msg, mSm.getMessageInfo(msg), curStateInfo.state,
+                            orgState);
+                } else {
+                    mProcessedMessages.add(msg, mSm.getMessageInfo(msg), null, null);
+                }
             }
         }
 
@@ -1546,6 +1570,24 @@
     }
 
     /**
+     * @return true if msg should be saved in ProcessedMessage, default is true.
+     */
+    protected boolean recordProcessedMessage(Message msg) {
+        return true;
+    }
+
+    /**
+     * Return message info to be logged by ProcessedMessageInfo, default
+     * is an empty string. Override if additional information is desired.
+     *
+     * @param msg that was processed
+     * @return information to be logged as a String
+     */
+    protected String getMessageInfo(Message msg) {
+        return "";
+    }
+
+    /**
      * @return if debugging is enabled
      */
     public boolean isDbg() {
@@ -1577,4 +1619,21 @@
         /** Send the complete construction message */
         mSmHandler.completeConstruction();
     }
+
+    /**
+     * Dump the current state.
+     *
+     * @param fd
+     * @param pw
+     * @param args
+     */
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println(getName() + ":");
+        pw.println(" total messages=" + getProcessedMessagesCount());
+        for (int i=0; i < getProcessedMessagesSize(); i++) {
+            pw.printf(" msg[%d]: %s\n", i, getProcessedMessageInfo(i));
+            pw.flush();
+        }
+        pw.println("curState=" + getCurrentState().getName());
+    }
 }
diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java
index e00a853..6a09fe07 100644
--- a/core/java/com/android/internal/util/XmlUtils.java
+++ b/core/java/com/android/internal/util/XmlUtils.java
@@ -888,4 +888,19 @@
             ;
         }
     }
+
+    public static boolean nextElementWithin(XmlPullParser parser, int outerDepth)
+            throws IOException, XmlPullParserException {
+        for (;;) {
+            int type = parser.next();
+            if (type == XmlPullParser.END_DOCUMENT
+                    || (type == XmlPullParser.END_TAG && parser.getDepth() == outerDepth)) {
+                return false;
+            }
+            if (type == XmlPullParser.START_TAG
+                    && parser.getDepth() == outerDepth + 1) {
+                return true;
+            }
+        }
+    }
 }
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 8c05459..7a6f7d9 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -246,6 +246,10 @@
         mHomeLayout.setOnClickListener(mUpClickListener);
         mHomeLayout.setClickable(true);
         mHomeLayout.setFocusable(true);
+
+        if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
+            setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+        }
     }
 
     @Override
diff --git a/core/java/com/android/internal/widget/SizeAdaptiveLayout.java b/core/java/com/android/internal/widget/SizeAdaptiveLayout.java
new file mode 100644
index 0000000..adfd3dc
--- /dev/null
+++ b/core/java/com/android/internal/widget/SizeAdaptiveLayout.java
@@ -0,0 +1,405 @@
+/*
+ * 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.widget;
+
+import com.android.internal.R;
+
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewDebug;
+import android.view.ViewGroup;
+import android.widget.RemoteViews.RemoteView;
+
+/**
+ * A layout that switches between its children based on the requested layout height.
+ * Each child specifies its minimum and maximum valid height.  Results are undefined
+ * if children specify overlapping ranges.  A child may specify the maximum height
+ * as 'unbounded' to indicate that it is willing to be displayed arbitrarily tall.
+ *
+ * <p>
+ * See {@link SizeAdaptiveLayout.LayoutParams} for a full description of the
+ * layout parameters used by SizeAdaptiveLayout.
+ */
+@RemoteView
+public class SizeAdaptiveLayout extends ViewGroup {
+
+    private static final String TAG = "SizeAdaptiveLayout";
+    private static final boolean DEBUG = false;
+    private static final long CROSSFADE_TIME = 250;
+
+    // TypedArray indices
+    private static final int MIN_VALID_HEIGHT =
+            R.styleable.SizeAdaptiveLayout_Layout_layout_minHeight;
+    private static final int MAX_VALID_HEIGHT =
+            R.styleable.SizeAdaptiveLayout_Layout_layout_maxHeight;
+
+    // view state
+    private View mActiveChild;
+    private View mLastActive;
+
+    // animation state
+    private AnimatorSet mTransitionAnimation;
+    private AnimatorListener mAnimatorListener;
+    private ObjectAnimator mFadePanel;
+    private ObjectAnimator mFadeView;
+    private int mCanceledAnimationCount;
+    private View mEnteringView;
+    private View mLeavingView;
+    // View used to hide larger views under smaller ones to create a uniform crossfade
+    private View mModestyPanel;
+    private int mModestyPanelTop;
+
+    public SizeAdaptiveLayout(Context context) {
+        super(context);
+        initialize();
+    }
+
+    public SizeAdaptiveLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        initialize();
+    }
+
+    public SizeAdaptiveLayout(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        initialize();
+    }
+
+    private void initialize() {
+        mModestyPanel = new View(getContext());
+        // If the SizeAdaptiveLayout has a solid background, use it as a transition hint.
+        if (getBackground() instanceof ColorDrawable) {
+            mModestyPanel.setBackgroundDrawable(getBackground());
+        } else {
+            mModestyPanel.setBackgroundColor(Color.BLACK);
+        }
+        SizeAdaptiveLayout.LayoutParams layout =
+                new SizeAdaptiveLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                                                    ViewGroup.LayoutParams.MATCH_PARENT);
+        mModestyPanel.setLayoutParams(layout);
+        addView(mModestyPanel);
+        mFadePanel = ObjectAnimator.ofFloat(mModestyPanel, "alpha", 0f);
+        mFadeView = ObjectAnimator.ofFloat(null, "alpha", 0f);
+        mAnimatorListener = new BringToFrontOnEnd();
+        mTransitionAnimation = new AnimatorSet();
+        mTransitionAnimation.play(mFadeView).with(mFadePanel);
+        mTransitionAnimation.setDuration(CROSSFADE_TIME);
+        mTransitionAnimation.addListener(mAnimatorListener);
+    }
+
+    /**
+     * Visible for testing
+     * @hide
+     */
+    public Animator getTransitionAnimation() {
+        return mTransitionAnimation;
+    }
+
+    /**
+     * Visible for testing
+     * @hide
+     */
+    public View getModestyPanel() {
+        return mModestyPanel;
+    }
+
+    @Override
+    public void onAttachedToWindow() {
+        mLastActive = null;
+        // make sure all views start off invisible.
+        for (int i = 0; i < getChildCount(); i++) {
+            getChildAt(i).setVisibility(View.GONE);
+        }
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        if (DEBUG) Log.d(TAG, this + " measure spec: " +
+                         MeasureSpec.toString(heightMeasureSpec));
+        View model = selectActiveChild(heightMeasureSpec);
+        SizeAdaptiveLayout.LayoutParams lp =
+          (SizeAdaptiveLayout.LayoutParams) model.getLayoutParams();
+        if (DEBUG) Log.d(TAG, "active min: " + lp.minHeight + " max: " + lp.maxHeight);
+        measureChild(model, widthMeasureSpec, heightMeasureSpec);
+        int childHeight = model.getMeasuredHeight();
+        int childWidth = model.getMeasuredHeight();
+        int childState = combineMeasuredStates(0, model.getMeasuredState());
+        if (DEBUG) Log.d(TAG, "measured child at: " + childHeight);
+        int resolvedWidth = resolveSizeAndState(childWidth, widthMeasureSpec, childState);
+        int resolvedheight = resolveSizeAndState(childHeight, heightMeasureSpec, childState);
+        setMeasuredDimension(resolvedWidth, resolvedheight);
+        if (DEBUG) Log.d(TAG, "resolved to: " + resolvedheight);
+    }
+
+    //TODO extend to width and height
+    private View selectActiveChild(int heightMeasureSpec) {
+        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+
+        View unboundedView = null;
+        View tallestView = null;
+        int tallestViewSize = 0;
+        View smallestView = null;
+        int smallestViewSize = Integer.MAX_VALUE;
+        for (int i = 0; i < getChildCount(); i++) {
+            View child = getChildAt(i);
+            if (child != mModestyPanel) {
+                SizeAdaptiveLayout.LayoutParams lp =
+                    (SizeAdaptiveLayout.LayoutParams) child.getLayoutParams();
+                if (DEBUG) Log.d(TAG, "looking at " + i +
+                                 " with min: " + lp.minHeight +
+                                 " max: " +  lp.maxHeight);
+                if (lp.maxHeight == SizeAdaptiveLayout.LayoutParams.UNBOUNDED &&
+                    unboundedView == null) {
+                    unboundedView = child;
+                }
+                if (lp.maxHeight > tallestViewSize) {
+                    tallestViewSize = lp.maxHeight;
+                    tallestView = child;
+                }
+                if (lp.minHeight < smallestViewSize) {
+                    smallestViewSize = lp.minHeight;
+                    smallestView = child;
+                }
+                if (heightMode != MeasureSpec.UNSPECIFIED &&
+                    heightSize >= lp.minHeight && heightSize <= lp.maxHeight) {
+                    if (DEBUG) Log.d(TAG, "  found exact match, finishing early");
+                    return child;
+                }
+            }
+        }
+        if (unboundedView != null) {
+            tallestView = unboundedView;
+        }
+        if (heightMode == MeasureSpec.UNSPECIFIED) {
+            return tallestView;
+        }
+        if (heightSize > tallestViewSize) {
+            return tallestView;
+        }
+        return smallestView;
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        if (DEBUG) Log.d(TAG, this + " onlayout height: " + (bottom - top));
+        mLastActive = mActiveChild;
+        int measureSpec = View.MeasureSpec.makeMeasureSpec(bottom - top,
+                                                           View.MeasureSpec.EXACTLY);
+        mActiveChild = selectActiveChild(measureSpec);
+        mActiveChild.setVisibility(View.VISIBLE);
+
+        if (mLastActive != mActiveChild && mLastActive != null) {
+            if (DEBUG) Log.d(TAG, this + " changed children from: " + mLastActive +
+                    " to: " + mActiveChild);
+
+            mEnteringView = mActiveChild;
+            mLeavingView = mLastActive;
+
+            mEnteringView.setAlpha(1f);
+
+            mModestyPanel.setAlpha(1f);
+            mModestyPanel.bringToFront();
+            mModestyPanelTop = mLeavingView.getHeight();
+            mModestyPanel.setVisibility(View.VISIBLE);
+            // TODO: mModestyPanel background should be compatible with mLeavingView
+
+            mLeavingView.bringToFront();
+
+            if (mTransitionAnimation.isRunning()) {
+                mTransitionAnimation.cancel();
+            }
+            mFadeView.setTarget(mLeavingView);
+            mFadeView.setFloatValues(0f);
+            mFadePanel.setFloatValues(0f);
+            mTransitionAnimation.setupStartValues();
+            mTransitionAnimation.start();
+        }
+        final int childWidth = mActiveChild.getMeasuredWidth();
+        final int childHeight = mActiveChild.getMeasuredHeight();
+        // TODO investigate setting LAYER_TYPE_HARDWARE on mLastActive
+        mActiveChild.layout(0, 0, 0 + childWidth, 0 + childHeight);
+
+        if (DEBUG) Log.d(TAG, "got modesty offset of " + mModestyPanelTop);
+        mModestyPanel.layout(0, mModestyPanelTop, 0 + childWidth, mModestyPanelTop + childHeight);
+    }
+
+    @Override
+    public LayoutParams generateLayoutParams(AttributeSet attrs) {
+        if (DEBUG) Log.d(TAG, "generate layout from attrs");
+        return new SizeAdaptiveLayout.LayoutParams(getContext(), attrs);
+    }
+
+    @Override
+    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+        if (DEBUG) Log.d(TAG, "generate default layout from viewgroup");
+        return new SizeAdaptiveLayout.LayoutParams(p);
+    }
+
+    @Override
+    protected LayoutParams generateDefaultLayoutParams() {
+        if (DEBUG) Log.d(TAG, "generate default layout from null");
+        return new SizeAdaptiveLayout.LayoutParams();
+    }
+
+    @Override
+    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+        return p instanceof SizeAdaptiveLayout.LayoutParams;
+    }
+
+    /**
+     * Per-child layout information associated with ViewSizeAdaptiveLayout.
+     *
+     * TODO extend to width and height
+     *
+     * @attr ref android.R.styleable#SizeAdaptiveLayout_Layout_layout_minHeight
+     * @attr ref android.R.styleable#SizeAdaptiveLayout_Layout_layout_maxHeight
+     */
+    public static class LayoutParams extends ViewGroup.LayoutParams {
+
+        /**
+         * Indicates the minimum valid height for the child.
+         */
+        @ViewDebug.ExportedProperty(category = "layout")
+        public int minHeight;
+
+        /**
+         * Indicates the maximum valid height for the child.
+         */
+        @ViewDebug.ExportedProperty(category = "layout")
+        public int maxHeight;
+
+        /**
+         * Constant value for maxHeight that indicates there is not maximum height.
+         */
+        public static final int UNBOUNDED = -1;
+
+        /**
+         * {@inheritDoc}
+         */
+        public LayoutParams(Context c, AttributeSet attrs) {
+            super(c, attrs);
+            if (DEBUG) {
+                Log.d(TAG, "construct layout from attrs");
+                for (int i = 0; i < attrs.getAttributeCount(); i++) {
+                    Log.d(TAG, " " + attrs.getAttributeName(i) + " = " +
+                          attrs.getAttributeValue(i));
+                }
+            }
+            TypedArray a =
+                    c.obtainStyledAttributes(attrs,
+                            R.styleable.SizeAdaptiveLayout_Layout);
+
+            minHeight = a.getDimensionPixelSize(MIN_VALID_HEIGHT, 0);
+            if (DEBUG) Log.d(TAG, "got minHeight of: " + minHeight);
+
+            try {
+                maxHeight = a.getLayoutDimension(MAX_VALID_HEIGHT, UNBOUNDED);
+                if (DEBUG) Log.d(TAG, "got maxHeight of: " + maxHeight);
+            } catch (Exception e) {
+                if (DEBUG) Log.d(TAG, "caught exception looking for maxValidHeight " + e);
+            }
+
+            a.recycle();
+        }
+
+        /**
+         * Creates a new set of layout parameters with the specified width, height
+         * and valid height bounds.
+         *
+         * @param width the width, either {@link #MATCH_PARENT},
+         *        {@link #WRAP_CONTENT} or a fixed size in pixels
+         * @param height the height, either {@link #MATCH_PARENT},
+         *        {@link #WRAP_CONTENT} or a fixed size in pixels
+         * @param minHeight the minimum height of this child
+         * @param maxHeight the maximum height of this child
+         *        or {@link #UNBOUNDED} if the child can grow forever
+         */
+        public LayoutParams(int width, int height, int minHeight, int maxHeight) {
+            super(width, height);
+            this.minHeight = minHeight;
+            this.maxHeight = maxHeight;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public LayoutParams(int width, int height) {
+            this(width, height, UNBOUNDED, UNBOUNDED);
+        }
+
+        /**
+         * Constructs a new LayoutParams with default values as defined in {@link LayoutParams}.
+         */
+        public LayoutParams() {
+            this(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public LayoutParams(ViewGroup.LayoutParams p) {
+            super(p);
+            minHeight = UNBOUNDED;
+            maxHeight = UNBOUNDED;
+        }
+
+        public String debug(String output) {
+            return output + "SizeAdaptiveLayout.LayoutParams={" +
+                    ", max=" + maxHeight +
+                    ", max=" + minHeight + "}";
+        }
+    }
+
+    class BringToFrontOnEnd implements AnimatorListener {
+        @Override
+            public void onAnimationEnd(Animator animation) {
+            if (mCanceledAnimationCount == 0) {
+                mLeavingView.setVisibility(View.GONE);
+                mModestyPanel.setVisibility(View.GONE);
+                mEnteringView.bringToFront();
+                mEnteringView = null;
+                mLeavingView = null;
+            } else {
+                mCanceledAnimationCount--;
+            }
+        }
+
+        @Override
+            public void onAnimationCancel(Animator animation) {
+            mCanceledAnimationCount++;
+        }
+
+        @Override
+            public void onAnimationRepeat(Animator animation) {
+            if (DEBUG) Log.d(TAG, "fade animation repeated: should never happen.");
+            assert(false);
+        }
+
+        @Override
+            public void onAnimationStart(Animator animation) {
+        }
+    }
+}
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index 244b166..c48b974 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -35,6 +35,7 @@
 
 static const char* const OutOfResourcesException =
     "android/graphics/SurfaceTexture$OutOfResourcesException";
+static const char* const IllegalStateException = "java/lang/IllegalStateException";
 const char* const kSurfaceTextureClassPathName = "android/graphics/SurfaceTexture";
 
 struct fields_t {
@@ -212,10 +213,16 @@
     surfaceTexture->setDefaultBufferSize(width, height);
 }
 
-static jint SurfaceTexture_updateTexImage(JNIEnv* env, jobject thiz)
+static void SurfaceTexture_updateTexImage(JNIEnv* env, jobject thiz)
 {
     sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
-    return surfaceTexture->updateTexImage();
+    status_t err = surfaceTexture->updateTexImage();
+    if (err == INVALID_OPERATION) {
+        jniThrowException(env, IllegalStateException, "Unable to update 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)
@@ -258,7 +265,7 @@
     {"nativeInit",                 "(ILjava/lang/Object;Z)V", (void*)SurfaceTexture_init },
     {"nativeFinalize",             "()V",   (void*)SurfaceTexture_finalize },
     {"nativeSetDefaultBufferSize", "(II)V", (void*)SurfaceTexture_setDefaultBufferSize },
-    {"nativeUpdateTexImage",       "()I",   (void*)SurfaceTexture_updateTexImage },
+    {"nativeUpdateTexImage",       "()V",   (void*)SurfaceTexture_updateTexImage },
     {"nativeDetachFromGLContext",  "()I",   (void*)SurfaceTexture_detachFromGLContext },
     {"nativeAttachToGLContext",    "(I)I",   (void*)SurfaceTexture_attachToGLContext },
     {"nativeGetTransformMatrix",   "([F)V", (void*)SurfaceTexture_getTransformMatrix },
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index 202abf6..9abfb3a 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -179,6 +179,6 @@
 
 int register_android_hardware_SensorManager(JNIEnv *env)
 {
-    return jniRegisterNativeMethods(env, "android/hardware/SensorManager",
+    return jniRegisterNativeMethods(env, "android/hardware/SystemSensorManager",
             gMethods, NELEM(gMethods));
 }
diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp
index 0ab659b..325fe26 100644
--- a/core/jni/android_net_TrafficStats.cpp
+++ b/core/jni/android_net_TrafficStats.cpp
@@ -31,6 +31,9 @@
 
 namespace android {
 
+static const uint64_t VALUE_UNKNOWN = -1;
+static const char* IFACE_STAT_ALL = "/proc/net/xt_qtaguid/iface_stat_all";
+
 enum Tx_Rx {
     TX,
     RX
@@ -42,6 +45,21 @@
     TCP_AND_UDP
 };
 
+// NOTE: keep these in sync with TrafficStats.java
+enum IfaceStatType {
+    RX_BYTES = 0,
+    RX_PACKETS = 1,
+    TX_BYTES = 2,
+    TX_PACKETS = 3
+};
+
+struct IfaceStat {
+    uint64_t rxBytes;
+    uint64_t rxPackets;
+    uint64_t txBytes;
+    uint64_t txPackets;
+};
+
 // Returns an ASCII decimal number read from the specified file, -1 on error.
 static jlong readNumber(char const* filename) {
     char buf[80];
@@ -63,130 +81,82 @@
     return atoll(buf);
 }
 
-static const char* mobile_iface_list[] = {
-    "rmnet0",
-    "rmnet1",
-    "rmnet2",
-    "rmnet3",
-    "cdma_rmnet4",
-    "ppp0",
-    0
-};
+static int parseIfaceStat(const char* iface, struct IfaceStat* stat) {
+    FILE *fp = fopen(IFACE_STAT_ALL, "r");
+    if (!fp) {
+        return errno;
+    }
 
-static jlong getAll(const char** iface_list, const char* what) {
+    char buffer[256];
+    char cur_iface[32];
+    int active;
+    uint64_t rxBytes, rxPackets, txBytes, txPackets, devRxBytes, devRxPackets, devTxBytes,
+            devTxPackets;
 
-    char filename[80];
-    int idx = 0;
-    bool supported = false;
-    jlong total = 0;
-    while (iface_list[idx] != 0) {
-
-        snprintf(filename, sizeof(filename), "/sys/class/net/%s/statistics/%s",
-                 iface_list[idx], what);
-        jlong number = readNumber(filename);
-        if (number >= 0) {
-            supported = true;
-            total += number;
+    while (fgets(buffer, 256, fp) != NULL) {
+        if (sscanf(buffer, "%31s %d %llu %llu %llu %llu %llu %llu %llu %llu", cur_iface, &active,
+                   &rxBytes, &rxPackets, &txBytes, &txPackets, &devRxBytes, &devRxPackets,
+                   &devTxBytes, &devTxPackets) != 10) {
+            continue;
         }
-        idx++;
-    }
-    if (supported) return total;
 
-    return -1;
-}
+        if (!iface || !strcmp(iface, cur_iface)) {
+            stat->rxBytes += rxBytes;
+            stat->rxPackets += rxPackets;
+            stat->txBytes += txBytes;
+            stat->txPackets += txPackets;
 
-// Returns the sum of numbers from the specified path under /sys/class/net/*,
-// -1 if no such file exists.
-static jlong readTotal(char const* suffix) {
-    char filename[PATH_MAX] = "/sys/class/net/";
-    DIR *dir = opendir(filename);
-    if (dir == NULL) {
-        ALOGE("Can't list %s: %s", filename, strerror(errno));
-        return -1;
-    }
-
-    int len = strlen(filename);
-    jlong total = -1;
-    while (struct dirent *entry = readdir(dir)) {
-        // Skip ., .., and localhost interfaces.
-        if (entry->d_name[0] != '.' && strncmp(entry->d_name, "lo", 2) != 0) {
-            strlcpy(filename + len, entry->d_name, sizeof(filename) - len);
-            strlcat(filename, suffix, sizeof(filename));
-            jlong num = readNumber(filename);
-            if (num >= 0) total = total < 0 ? num : total + num;
+            if (active) {
+                stat->rxBytes += devRxBytes;
+                stat->rxPackets += devRxPackets;
+                stat->txBytes += devTxBytes;
+                stat->txPackets += devTxPackets;
+            }
         }
     }
 
-    closedir(dir);
-    return total;
+    fclose(fp);
+    return 0;
 }
 
-// Mobile stats get accessed a lot more often than total stats.
-// Note the individual files can come and go at runtime, so we check
-// each file every time (rather than caching which ones exist).
+static uint64_t getIfaceStatType(const char* iface, IfaceStatType type) {
+    struct IfaceStat stat;
+    memset(&stat, 0, sizeof(IfaceStat));
 
-static jlong getMobileTxPackets(JNIEnv* env, jobject clazz) {
-    return getAll(mobile_iface_list, "tx_packets");
-}
-
-static jlong getMobileRxPackets(JNIEnv* env, jobject clazz) {
-    return getAll(mobile_iface_list, "rx_packets");
-}
-
-static jlong getMobileTxBytes(JNIEnv* env, jobject clazz) {
-    return getAll(mobile_iface_list, "tx_bytes");
-}
-
-static jlong getMobileRxBytes(JNIEnv* env, jobject clazz) {
-    return getAll(mobile_iface_list, "rx_bytes");
-}
-
-static jlong getData(JNIEnv* env, const char* what, jstring javaInterface) {
-    ScopedUtfChars interface(env, javaInterface);
-    if (interface.c_str() == NULL) {
-        return -1;
+    if (parseIfaceStat(iface, &stat)) {
+        return VALUE_UNKNOWN;
     }
 
-    char filename[80];
-    snprintf(filename, sizeof(filename), "/sys/class/net/%s/statistics/%s", interface.c_str(), what);
-    return readNumber(filename);
+    switch (type) {
+        case RX_BYTES:
+            return stat.rxBytes;
+        case RX_PACKETS:
+            return stat.rxPackets;
+        case TX_BYTES:
+            return stat.txBytes;
+        case TX_PACKETS:
+            return stat.txPackets;
+        default:
+            return VALUE_UNKNOWN;
+    }
 }
 
-static jlong getTxPackets(JNIEnv* env, jobject clazz, jstring interface) {
-    return getData(env, "tx_packets", interface);
+static jlong getTotalStat(JNIEnv* env, jclass clazz, jint type) {
+    return getIfaceStatType(NULL, (IfaceStatType) type);
 }
 
-static jlong getRxPackets(JNIEnv* env, jobject clazz, jstring interface) {
-    return getData(env, "rx_packets", interface);
+static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type) {
+    struct IfaceStat stat;
+    const char* ifaceChars = env->GetStringUTFChars(iface, NULL);
+    if (ifaceChars) {
+        uint64_t stat = getIfaceStatType(ifaceChars, (IfaceStatType) type);
+        env->ReleaseStringUTFChars(iface, ifaceChars);
+        return stat;
+    } else {
+        return VALUE_UNKNOWN;
+    }
 }
 
-static jlong getTxBytes(JNIEnv* env, jobject clazz, jstring interface) {
-    return getData(env, "tx_bytes", interface);
-}
-
-static jlong getRxBytes(JNIEnv* env, jobject clazz, jstring interface) {
-    return getData(env, "rx_bytes", interface);
-}
-
-
-// Total stats are read less often, so we're willing to put up
-// with listing the directory and concatenating filenames.
-
-static jlong getTotalTxPackets(JNIEnv* env, jobject clazz) {
-    return readTotal("/statistics/tx_packets");
-}
-
-static jlong getTotalRxPackets(JNIEnv* env, jobject clazz) {
-    return readTotal("/statistics/rx_packets");
-}
-
-static jlong getTotalTxBytes(JNIEnv* env, jobject clazz) {
-    return readTotal("/statistics/tx_bytes");
-}
-
-static jlong getTotalRxBytes(JNIEnv* env, jobject clazz) {
-    return readTotal("/statistics/rx_bytes");
-}
 
 // Per-UID stats require reading from a constructed filename.
 
@@ -323,18 +293,8 @@
 }
 
 static JNINativeMethod gMethods[] = {
-    {"getMobileTxPackets", "()J", (void*) getMobileTxPackets},
-    {"getMobileRxPackets", "()J", (void*) getMobileRxPackets},
-    {"getMobileTxBytes", "()J", (void*) getMobileTxBytes},
-    {"getMobileRxBytes", "()J", (void*) getMobileRxBytes},
-    {"getTxPackets", "(Ljava/lang/String;)J", (void*) getTxPackets},
-    {"getRxPackets", "(Ljava/lang/String;)J", (void*) getRxPackets},
-    {"getTxBytes", "(Ljava/lang/String;)J", (void*) getTxBytes},
-    {"getRxBytes", "(Ljava/lang/String;)J", (void*) getRxBytes},
-    {"getTotalTxPackets", "()J", (void*) getTotalTxPackets},
-    {"getTotalRxPackets", "()J", (void*) getTotalRxPackets},
-    {"getTotalTxBytes", "()J", (void*) getTotalTxBytes},
-    {"getTotalRxBytes", "()J", (void*) getTotalRxBytes},
+    {"nativeGetTotalStat", "(I)J", (void*) getTotalStat},
+    {"nativeGetIfaceStat", "(Ljava/lang/String;I)J", (void*) getIfaceStat},
 
     /* Per-UID Stats */
     {"getUidTxBytes", "(I)J", (void*) getUidTxBytes},
diff --git a/core/jni/android_view_InputDevice.cpp b/core/jni/android_view_InputDevice.cpp
index e8a3a3b..5cb172b 100644
--- a/core/jni/android_view_InputDevice.cpp
+++ b/core/jni/android_view_InputDevice.cpp
@@ -57,7 +57,7 @@
             gInputDeviceClassInfo.ctor, deviceInfo.getId(), deviceInfo.getGeneration(),
             nameObj.get(), descriptorObj.get(),
             deviceInfo.getSources(), deviceInfo.getKeyboardType(),
-            kcmObj.get()));
+            kcmObj.get(), deviceInfo.hasVibrator()));
 
     const Vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
     for (size_t i = 0; i < ranges.size(); i++) {
@@ -87,7 +87,7 @@
     gInputDeviceClassInfo.clazz = jclass(env->NewGlobalRef(gInputDeviceClassInfo.clazz));
 
     GET_METHOD_ID(gInputDeviceClassInfo.ctor, gInputDeviceClassInfo.clazz,
-            "<init>", "(IILjava/lang/String;Ljava/lang/String;IILandroid/view/KeyCharacterMap;)V");
+            "<init>", "(IILjava/lang/String;Ljava/lang/String;IILandroid/view/KeyCharacterMap;Z)V");
 
     GET_METHOD_ID(gInputDeviceClassInfo.addMotionRange, gInputDeviceClassInfo.clazz,
             "addMotionRange", "(IIFFFF)V");
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index ce2cdee..31b914a 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -198,7 +198,7 @@
     return surface;
 }
 
-static void setSurface(JNIEnv* env, jobject clazz, const sp<Surface>& surface)
+void setSurface(JNIEnv* env, jobject clazz, const sp<Surface>& surface)
 {
     Surface* const p = (Surface*)env->GetIntField(clazz, so.surface);
     if (surface.get()) {
diff --git a/core/res/res/anim/dock_bottom_enter.xml b/core/res/res/anim/dock_bottom_enter.xml
index 7a2e94b..74a021b 100644
--- a/core/res/res/anim/dock_bottom_enter.xml
+++ b/core/res/res/anim/dock_bottom_enter.xml
@@ -19,8 +19,6 @@
 <!-- Animation for when a dock window at the bottom of the screen is entering. -->
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:interpolator="@android:interpolator/decelerate_quad">
-    <translate android:fromYDelta="75%" android:toYDelta="0"
+    <translate android:fromYDelta="100%" android:toYDelta="0"
         android:duration="@android:integer/config_mediumAnimTime"/>
-    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
-        android:duration="@android:integer/config_mediumAnimTime" />
 </set>
diff --git a/core/res/res/anim/dock_bottom_exit.xml b/core/res/res/anim/dock_bottom_exit.xml
index c2fd15c..213b3d9 100644
--- a/core/res/res/anim/dock_bottom_exit.xml
+++ b/core/res/res/anim/dock_bottom_exit.xml
@@ -19,8 +19,6 @@
 <!-- Animation for when a dock window at the bottom of the screen is exiting. -->
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:interpolator="@android:interpolator/accelerate_quad">
-    <translate android:fromYDelta="0" android:toYDelta="75%"
+    <translate android:fromYDelta="0" android:toYDelta="100%"
         android:startOffset="100" android:duration="@android:integer/config_mediumAnimTime"/>
-    <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
-        android:startOffset="100" android:duration="@android:integer/config_mediumAnimTime" />
 </set>
diff --git a/core/res/res/anim/dock_left_enter.xml b/core/res/res/anim/dock_left_enter.xml
index b057f67..4fce35a 100644
--- a/core/res/res/anim/dock_left_enter.xml
+++ b/core/res/res/anim/dock_left_enter.xml
@@ -19,8 +19,6 @@
 <!-- Animation for when a dock window at the left of the screen is entering. -->
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:interpolator="@android:interpolator/decelerate_quad">
-    <translate android:fromXDelta="-75%" android:toXDelta="0"
+    <translate android:fromXDelta="-100%" android:toXDelta="0"
         android:duration="@android:integer/config_mediumAnimTime"/>
-    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
-        android:duration="@android:integer/config_mediumAnimTime" />
 </set>
diff --git a/core/res/res/anim/dock_left_exit.xml b/core/res/res/anim/dock_left_exit.xml
index 576b1aa..bce203d 100644
--- a/core/res/res/anim/dock_left_exit.xml
+++ b/core/res/res/anim/dock_left_exit.xml
@@ -19,8 +19,6 @@
 <!-- Animation for when a dock window at the right of the screen is exiting. -->
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:interpolator="@android:interpolator/accelerate_quad">
-    <translate android:fromXDelta="0" android:toXDelta="-75%"
+    <translate android:fromXDelta="0" android:toXDelta="-100%"
         android:startOffset="100" android:duration="@android:integer/config_mediumAnimTime"/>
-    <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
-        android:startOffset="100" android:duration="@android:integer/config_mediumAnimTime" />
 </set>
diff --git a/core/res/res/anim/dock_right_enter.xml b/core/res/res/anim/dock_right_enter.xml
index e1bd190..26b8ad6 100644
--- a/core/res/res/anim/dock_right_enter.xml
+++ b/core/res/res/anim/dock_right_enter.xml
@@ -19,8 +19,6 @@
 <!-- Animation for when a dock window at the right of the screen is entering. -->
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:interpolator="@android:interpolator/decelerate_quad">
-    <translate android:fromXDelta="75%" android:toXDelta="0"
+    <translate android:fromXDelta="100%" android:toXDelta="0"
         android:duration="@android:integer/config_mediumAnimTime"/>
-    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
-        android:duration="@android:integer/config_mediumAnimTime" />
 </set>
diff --git a/core/res/res/anim/dock_right_exit.xml b/core/res/res/anim/dock_right_exit.xml
index 6d778fa..6beda59 100644
--- a/core/res/res/anim/dock_right_exit.xml
+++ b/core/res/res/anim/dock_right_exit.xml
@@ -19,8 +19,6 @@
 <!-- Animation for when a dock window at the right of the screen is exiting. -->
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:interpolator="@android:interpolator/accelerate_quad">
-    <translate android:fromXDelta="0" android:toXDelta="75%"
+    <translate android:fromXDelta="0" android:toXDelta="100%"
         android:startOffset="100" android:duration="@android:integer/config_mediumAnimTime"/>
-    <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
-        android:startOffset="100" android:duration="@android:integer/config_mediumAnimTime" />
 </set>
diff --git a/core/res/res/anim/dock_top_enter.xml b/core/res/res/anim/dock_top_enter.xml
index f2e4cae..594b479 100644
--- a/core/res/res/anim/dock_top_enter.xml
+++ b/core/res/res/anim/dock_top_enter.xml
@@ -19,8 +19,6 @@
 <!-- Animation for when a dock window at the top of the screen is entering. -->
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:interpolator="@android:interpolator/decelerate_quad">
-    <translate android:fromYDelta="-75%" android:toYDelta="0"
+    <translate android:fromYDelta="-100%" android:toYDelta="0"
         android:duration="@android:integer/config_mediumAnimTime"/>
-    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
-        android:duration="@android:integer/config_mediumAnimTime" />
 </set>
diff --git a/core/res/res/anim/dock_top_exit.xml b/core/res/res/anim/dock_top_exit.xml
index 7373695..b9691f6 100644
--- a/core/res/res/anim/dock_top_exit.xml
+++ b/core/res/res/anim/dock_top_exit.xml
@@ -19,8 +19,6 @@
 <!-- Animation for when a dock window at the top of the screen is exiting. -->
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:interpolator="@android:interpolator/accelerate_quad">
-    <translate android:fromYDelta="0" android:toYDelta="-75%"
+    <translate android:fromYDelta="0" android:toYDelta="-100%"
         android:startOffset="100" android:duration="@android:integer/config_mediumAnimTime"/>
-    <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
-        android:startOffset="100" android:duration="@android:integer/config_mediumAnimTime" />
 </set>
diff --git a/core/res/res/anim/lock_screen_behind_enter.xml b/core/res/res/anim/lock_screen_behind_enter.xml
index 6b06456..78b7d29 100644
--- a/core/res/res/anim/lock_screen_behind_enter.xml
+++ b/core/res/res/anim/lock_screen_behind_enter.xml
@@ -20,8 +20,8 @@
 <set xmlns:android="http://schemas.android.com/apk/res/android"
     android:background="#ff000000" android:shareInterpolator="false">
     <scale
-        android:fromXScale="0.95" android:toXScale="1.0"
-        android:fromYScale="0.95" android:toYScale="1.0"
+        android:fromXScale="0.90" android:toXScale="1.0"
+        android:fromYScale="0.90" android:toYScale="1.0"
         android:pivotX="50%p" android:pivotY="50%p"
         android:fillEnabled="true" android:fillBefore="true"
         android:interpolator="@interpolator/decelerate_cubic"
@@ -30,7 +30,7 @@
     <alpha
         android:fromAlpha="0.0" android:toAlpha="1.0"
         android:fillEnabled="true" android:fillBefore="true"
-        android:interpolator="@interpolator/decelerate_quad"
+        android:interpolator="@interpolator/decelerate_quint"
         android:startOffset="@android:integer/config_shortAnimTime"
         android:duration="@android:integer/config_shortAnimTime"/>
 </set>
\ No newline at end of file
diff --git a/core/res/res/drawable-nodpi/view_accessibility_focused.9.png b/core/res/res/drawable-nodpi/view_accessibility_focused.9.png
new file mode 100644
index 0000000..f03f575
--- /dev/null
+++ b/core/res/res/drawable-nodpi/view_accessibility_focused.9.png
Binary files differ
diff --git a/core/res/res/raw/accessibility_gestures.bin b/core/res/res/raw/accessibility_gestures.bin
new file mode 100644
index 0000000..1f95e56
--- /dev/null
+++ b/core/res/res/raw/accessibility_gestures.bin
Binary files differ
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 9528a7a..d299436 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -286,10 +286,8 @@
     <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>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Laat die program toe om die muis of stuurpaneel se wyserspoed te eniger tyd te verander. Dit moet nooit vir normale programme nodig wees nie."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"verander sleutelborduitleg"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Laat die program toe om die uitleg van die sleutelbord te verander. Behoort nooit vir gewone programme nodig te wees nie."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"stuur Linux-seine na programme"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Laat die program toe om te versoek dat die voorsiende sein na alle aanhoudende prosesse gestuur word."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"laat program altyd loop"</string>
@@ -1009,11 +1007,17 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Voer die vereiste PIN in:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"Voeg karakter in"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Onbekend program"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Stuur SMS-boodskappe"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"\'n Groot aantal SMS-boodskappe word gestuur. Raak OK om voort te gaan, of Kanselleer om op te hou stuur."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Kanselleer"</string>
+    <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; stuur \'n groot aantal SMS-boodskappe. Wil jy hierdie program toelaat om voort te gaan om boodskappe te stuur?"</string>
+    <string name="sms_control_yes" msgid="3663725993855816807">"Laat toe"</string>
+    <string name="sms_control_no" msgid="625438561395534982">"Weier"</string>
+    <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Stuur SMS na kortkode?"</string>
+    <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Stuur \'n premium SMS?"</string>
+    <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; wil graag \'n SMS stuur aan &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;, wat lyk asof dit \'n SMS-kortkode is.&lt;p&gt;Die stuur van SMS\'e na sommige kortkodes kan veroorsaak dat jou selfoonrekening gedebiteer word vir premium dienste.&lt;p&gt;Wil jy hierdie program toelaat om die boodskap te stuur?"</string>
+    <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; wil graag \'n SMS stuur aan &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;, wat \'n betaalde SMS-kortkode is.&lt;p&gt;&lt;b&gt;As jy \'n boodskap na hierdie bestemming stuur, sal jou selfoonrekening gedebiteer word vir betaalde dienste.&lt;/b&gt;&lt;p&gt;Wil jy hierdie program toelaat om die boodskap te stuur?"</string>
+    <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Stuur boodskap"</string>
+    <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Moenie stuur nie"</string>
+    <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Gee kwaadwillige program aan"</string>
     <string name="sim_removed_title" msgid="6227712319223226185">"SIM-kaart verwyder"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"Die mobielnetwerk sal nie beskikbaar wees nie totdat jy weer begin met \'n geldige SIM-kaart."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Klaar"</string>
@@ -1063,10 +1067,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Raak om USB-ontfouting te deaktiveer."</string>
     <string name="select_input_method" msgid="4653387336791222978">"Kies invoermetode"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"Stel invoermetodes op"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"Fisiese sleutelbord"</string>
+    <string name="hardware" msgid="7517821086888990278">"Hardeware"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidate"</u></string>
@@ -1193,14 +1195,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Verminder dag"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Vermeerder jaar"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Verminder jaar"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"gekontroleer"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"nie gekontroleer nie"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"gekies"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"nie gekies nie"</string>
-    <string name="switch_on" msgid="551417728476977311">"aan"</string>
-    <string name="switch_off" msgid="7249798614327155088">"af"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"gedruk"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"nie gedruk nie"</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>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 747b12d..b2714dd 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -286,10 +286,8 @@
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"በማንኛውም ጊዜ  የማሳያውን መሽከርከር ለመለወጥ ለመተግበሪያው ይፈቅዳሉ፡፡ ለተለመዱ መተግበሪያዎች አያስፈልግም፡፡"</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"የጠቋሚ ፍጥነት ለውጥ"</string>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"መዳፊት ወይም ዱካ መከተያ ጠቋሚ ፍጥነትን በማንኛውም ጊዜ ለመለወጥ ለመተግበሪያው ይፈቅዳሉ፡፡ ለመደበኛ መተግበሪያዎች መቼም ቢሆን አያስፈልግም፡፡"</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"የቁልፍ ሰሌዳ አቀማመጥ ቀይር"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"መተግበሪያው የቁልፍ ሰሌዳ አቀማመጡን እንዲቀይር ይፈቅድለታል። ለመደበኛ መተግበሪያዎች መቼም ቢሆን ሊያስፈልግ አይገባም።"</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"ወደ መተግበሪያዎችን የLinux ምልክቶች ላክ"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"ለሁሉም ተከታታይ ሂደቶች ልከው የሚያቀርቧቸው ሲግናሎችን ለመጠየቅ ለመተግበሪያው ይፈቅዳሉ።"</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"ትግበራ ሁልጊዜ አሂድ ላይ አድርግ"</string>
@@ -1009,11 +1007,17 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"የሚፈለገውን ፒን ተይብ፦"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"ፒን፦"</string>
     <string name="select_character" msgid="3365550120617701745">"ቁምፊ አስገባ"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"ያልታወቀ መተግበሪያ"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"የSMS መልዕክቶች መበላክ ላይ"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"በጣም ብዙ የ SMS መልዕክቶቸ ተልከዋል።ለመቀጠል \"እሺ \" ፣ ወይም መላክ ለማቆም\"ተው \" ምረጥ።"</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"እሺ"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"ይቅር"</string>
+    <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ቁጥሩ ብዙ የሆኑ የኤስ.ኤም.ኤስ. መልዕቶችን እየላከ ነው። ይሄ መተግበሪያ መልዕክቶችን መላኩን እንዲቀጥል መፍቀድ ትፈልጋለህ?"</string>
+    <string name="sms_control_yes" msgid="3663725993855816807">"ፍቀድ"</string>
+    <string name="sms_control_no" msgid="625438561395534982">"ከልክል"</string>
+    <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"ኤስ.ኤም.ኤስ. ለአጭር ኮድ ይላክ?"</string>
+    <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"ከፍ ያለ ኤስ.ኤም.ኤስ. ይላክ?"</string>
+    <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; የጽሑፍ መልዕክት ለ&lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt; መላክ ይፈልጋል፣ ይሄ ደግሞ የኤስ.ኤም.ኤስ. አጭር ኮድ ሆኖ ተገኝቷል።&lt;p&gt;የጽሑፍ መልዕክቶች ለሆኑ አጭር ኮዶች መላክ የተንቀሳቃሽ መለያህ ከፍ ላሉ አገልግሎቶች ሊያስከፍለው ይችላል።&lt;p&gt;ይሄ መተግበሪያ መልዕክቱ እንዲልክ መፍቀድ ትፈልጋለህ?"</string>
+    <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; የጽሑፍ መልዕክት ለ&lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt; መላክ ይፈልጋል፣ ይሄ ደግሞ ከፍ ያለ የኤስ.ኤም.ኤስ. አጭር ኮድ ነው።&lt;p&gt;&lt;b&gt;መልዕክት ወደዚህ ቦታ መላክ የተንቀሳቃሽ መለያህ ከፍ ላሉ አገልግሎቶች ያስከፍለዋል።&lt;/b&gt;&lt;p&gt;ይሄ መተግበሪያ መልዕክቱ እንዲልክ መፍቀድ ትፈልጋለህ?"</string>
+    <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"መልዕክት ላክ"</string>
+    <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"አትላክ"</string>
+    <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"ተንኮል አዘል መተግበሪያ ሪፖርት አድርግ"</string>
     <string name="sim_removed_title" msgid="6227712319223226185">"SIM ካርድ ተወግዷል"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"በትክክል የገባ SIM ካርድ ድጋሚ እስኪያስጀምሩ የተንቀሳቃሽ ስልክ አውታረመረብ አይገኝም።"</string>
     <string name="sim_done_button" msgid="827949989369963775">"ተከናውኗል"</string>
@@ -1063,10 +1067,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"USB ማረሚያ ላለማንቃት ዳስስ።"</string>
     <string name="select_input_method" msgid="4653387336791222978">"የግቤት ስልት ምረጥ"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"የግቤት ስልቶችን አዘጋጅ"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"የሚዳሰስ የቁልፍ ሰሌዳ"</string>
+    <string name="hardware" msgid="7517821086888990278">"ሃርድዌር"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"ዕጩዎች"</u></string>
@@ -1193,14 +1195,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"ቀን ቀንስ"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"ዓመት ጨምር"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"ዓመት ቀንስ"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"ታይቷል"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"አልተፈተሸም"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"የተመረጠ"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"አልተመረጠም"</string>
-    <string name="switch_on" msgid="551417728476977311">"በ:"</string>
-    <string name="switch_off" msgid="7249798614327155088">"ውጪ"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"ተጭኗል"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"አልተጫነም።"</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>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index e95ea69..daef582 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -286,10 +286,8 @@
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"للسماح للتطبيق بتغيير تدوير الشاشة في أي وقت. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"تغيير سرعة المؤشر"</string>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"للسماح للتطبيق بتغيير سرعة مؤشر الماوس أو لوحة التتبع في أي وقت. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"تغيير تنسيق لوحة مفاتيح"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"للسماح للتطبيق بتغيير تنسيق لوحة المفاتيح. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"إرسال إشارات Linux للتطبيقات"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"للسماح للتطبيق بطلب إرسال الإشارة المزوّدة لجميع العمليات المستمرة."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"تشغيل التطبيق دائمًا"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"اكتب رقم التعريف الشخصي المطلوب:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"رقم التعريف الشخصي:"</string>
     <string name="select_character" msgid="3365550120617701745">"إدراج حرف"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"تطبيق غير معروف"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"إرسال رسائل قصيرة SMS"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"تم إرسال عدد كبير من الرسائل القصيرة SMS. المس \"موافق\" للمتابعة، أو \"إلغاء\" لإيقاف الإرسال."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"موافق"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"إلغاء"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"تمت إزالة بطاقة SIM"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"لن تكون شبكة الجوال متاحة حتى تتم إعادة التشغيل وإدخال بطاقة SIM صالحة."</string>
     <string name="sim_done_button" msgid="827949989369963775">"تم"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"المس لتعطيل تصحيح أخطاء USB."</string>
     <string name="select_input_method" msgid="4653387336791222978">"اختيار أسلوب الإدخال"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"إعداد أسلوب الإدخال"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"لوحة مفاتيح فعلية"</string>
+    <string name="hardware" msgid="7517821086888990278">"أجهزة"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789 أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"العناصر المرشحة"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"تقليل الأيام"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"زيادة الأعوام"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"تقليل الأعوام"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"تم التحديد"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"لم يتم التحديد"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"محدد"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"غير محدد"</string>
-    <string name="switch_on" msgid="551417728476977311">"تشغيل"</string>
-    <string name="switch_off" msgid="7249798614327155088">"إيقاف"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"مضغوط"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"غير مضغوط"</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>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index c78ecd9..c155537 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -286,10 +286,8 @@
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Дазваляе прыкладанням змяняць паварот экрана ў любы час. Не патрабуецца для звычайных прыкладанняў."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"змена хутк. перамяшч. ўказ."</string>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Дазваляе прыкладанням змяняць хуткасць курсору мышы або трэкпада ў любы час. Не патрабуецца для звычайных прыкладанняў."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"змяніць раскладку клавіятуры"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Дазваляе прыкладанню змяняць раскладку клавіятуры. Не патрабуецца для звычайных прыкладанняў."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"адправіць сігналы Linux да прыкладанняў"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Дазваляе прыкладанням запытваць адпраўку падаваемага сігнала для ўсiх пастаянных працэсаў."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"прымусіць прыкладанне працаваць заўсёды"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Увядзіце патрэбны PIN-код:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-код"</string>
     <string name="select_character" msgid="3365550120617701745">"Уставіць сімвал"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Невядомае прыкладанне"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Адпраўка SMS"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Адпраўляецца вялікая колькасць SMS-паведамленняў. Націсніце \"OK\", каб працягнуць, ці \"Адмена\", каб спыніць адпраўку."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"ОК"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Адмяніць"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"SIM-карта выдаленая"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"Мабільная сетка будзе недаступная да перазагрузкі з дзеючай SIM-картай."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Гатова"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Націсніце, каб адключыць адладку USB."</string>
     <string name="select_input_method" msgid="4653387336791222978">"Выберыце метад уводу"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"Наладзіць метады ўводу"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"Фізічная клавіятура"</string>
+    <string name="hardware" msgid="7517821086888990278">"Апар. ср."</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" АБВГДЕЁЖЗІЙКЛМНОПРСТУЎФХЦЧШ\'ЫЬЭЮЯ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"кандыдат."</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Паменшыць лічбу дня"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Павялічыць лічбу года"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Паменшыць лічбу года"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"пастаўлены"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"не пастаўлены"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"абрана"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"не абрана"</string>
-    <string name="switch_on" msgid="551417728476977311">"укл."</string>
-    <string name="switch_off" msgid="7249798614327155088">"адключаны"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"націснутая"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"не націснутая"</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>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 8bcbec3..7860382 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1009,11 +1009,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Въведете задължителния ПИН:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"ПИН:"</string>
     <string name="select_character" msgid="3365550120617701745">"Вмъкване на знак"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Неизвестно приложение"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Изпращане на SMS съобщения"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Изпращат се голям брой SMS съобщения. Докоснете „OK“, за да продължите, или „Отказ“, за да спрете изпращането."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Отказ"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"SIM картата е премахната"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"Няма да имате достъп до мобилната мрежа, докато не рестартирате с поставена валидна SIM карта."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Готово"</string>
@@ -1193,14 +1209,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Намаляване на дните"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Увеличаване на годините"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Намаляване на годините"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"отметнато"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"не е отметнато"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"избрано"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"не е избрано"</string>
-    <string name="switch_on" msgid="551417728476977311">"включено"</string>
-    <string name="switch_off" msgid="7249798614327155088">"изключено"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"натиснато"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"не е натиснато"</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>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index fdae718..e266a85 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -286,10 +286,8 @@
     <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>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Permet que l\'aplicació canviï la velocitat del punter del ratolí o del ratolí tàctil en qualsevol moment. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"canvia la disposició del teclat"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Permet que l\'aplicació canviï la disposició del teclat. En principi mai no serà necessari per a les aplicacions normals."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"envia senyals Linux a les aplicacions"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Permet que l\'aplicació sol·liciti que el senyal subministrat s\'enviï a tots els processos persistents."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"fes que l\'aplicació s\'executi sempre"</string>
@@ -1009,11 +1007,17 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Introdueix el PIN sol·licitat:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"Insereix un caràcter"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Aplicació desconeguda"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"S\'estan enviant missatges SMS"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"S\'estan enviant molts missatges SMS. Toca D\'acord per continuar o Cancel·la per aturar l\'enviament."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"D\'acord"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Cancel·la"</string>
+    <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; està enviant molts missatges SMS. Vols permetre que aquesta aplicació continuï enviant missatges?"</string>
+    <string name="sms_control_yes" msgid="3663725993855816807">"Permet"</string>
+    <string name="sms_control_no" msgid="625438561395534982">"Denega"</string>
+    <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Vols enviar SMS a codi curt?"</string>
+    <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Vols enviar el SMS prèmium?"</string>
+    <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; vol enviar un missatge de text a &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;, que sembla que és un codi SMS curt.&lt;p&gt;Si envies missatges de text a codis curts, pot ser que es carreguin serveis prèmium al teu compte mòbil.&lt;p&gt;Vols permetre que aquesta aplicació enviï el missatge?"</string>
+    <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; vol enviar un missatge de text a &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;, que és un codi curt SMS prèmium.&lt;p&gt;&lt;b&gt;Si envies un missatge a aquesta destinació, es carregaran els serveis prèmium al teu compte mòbil.&lt;/b&gt;&lt;p&gt;Vols permetre que aquesta aplicació enviï el missatge?"</string>
+    <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Envia el missatge"</string>
+    <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"No enviïs"</string>
+    <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Informa d\'una aplic. maliciosa"</string>
     <string name="sim_removed_title" msgid="6227712319223226185">"Extracció de la targeta SIM"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"La xarxa de telefonia mòbil no estarà disponible fins que no reiniciïs amb una targeta SIM vàlida inserida."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Fet"</string>
@@ -1063,10 +1067,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Toca-ho per desactivar la depuració USB."</string>
     <string name="select_input_method" msgid="4653387336791222978">"Selecció de mètodes d\'introducció"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"Configura els mètodes d\'entrada"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"Teclat físic"</string>
+    <string name="hardware" msgid="7517821086888990278">"Maquinari"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
@@ -1193,14 +1195,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Fes disminuir el dia"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Fes augmentar l\'any"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Fes disminuir l\'any"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"marcat"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"no marcat"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"seleccionat"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"no seleccionat"</string>
-    <string name="switch_on" msgid="551417728476977311">"activat"</string>
-    <string name="switch_off" msgid="7249798614327155088">"desactivat"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"premut"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"no premut"</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>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 98b5771..33f91e8 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1009,11 +1009,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Zadejte požadovaný kód PIN:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"Vkládání znaků"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Neznámá aplikace"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Odesílání zpráv SMS"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Odesíláte velký počet zpráv SMS. Dotkněte se možnosti OK, chcete-li pokračovat, nebo možnosti Zrušit, chcete-li odesílání ukončit."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Zrušit"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"Karta SIM odebrána"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"Mobilní síť bude dostupná až poté, co vložíte platnou kartu SIM a restartujete zařízení."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Hotovo"</string>
@@ -1193,14 +1209,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Ubrat den"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Přidat rok"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Ubrat rok"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"zaškrtnuto"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"nezaškrtnuto"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"Vybráno"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"Nevybráno"</string>
-    <string name="switch_on" msgid="551417728476977311">"zapnuto"</string>
-    <string name="switch_off" msgid="7249798614327155088">"vypnuto"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"stisknuto"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"nestisknuto"</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>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index a3c7474..c5b0e17 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -286,10 +286,8 @@
     <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>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Tillader, at appen til enhver tid kan ændre musemarkørens hastighed. Bør aldrig være nødvendigt for normale apps."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"skift tastaturlayout"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Tillader, at appen må ændre tastaturlayoutet. Bør aldrig være nødvendig for normale apps."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"sende Linux-signaler til apps"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Tillader, at appen kan anmode om, at det leverede signal sendes til alle vedholdende processer."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"sørge for, at appen altid kører"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Skriv den påkrævede pinkode:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Pinkode:"</string>
     <string name="select_character" msgid="3365550120617701745">"Indsæt tegn"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Ukendt app"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Sender sms-beskeder"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Der sendes et stort antal sms-beskeder. Vælg \"OK\" for at fortsætte eller \"Annuller\" for at stoppe afsendelsen."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Annuller"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"SIM-kort blev fjernet"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"Det mobile netværk er utilgængeligt, indtil du genstarter med et gyldigt SIM-kort."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Udfør"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Tryk for at deaktivere USB-fejlretning."</string>
     <string name="select_input_method" msgid="4653387336791222978">"Vælg inputmetode"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"Konfigurer inputmetoder"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"Fysisk tastatur"</string>
+    <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidater"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Tidligere dag"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Senere år"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Tidligere år"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"markeret"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"ikke markeret"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"udvalgt"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"ikke valgt"</string>
-    <string name="switch_on" msgid="551417728476977311">"tændt"</string>
-    <string name="switch_off" msgid="7249798614327155088">"slukket"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"trykket på"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"ikke trykket på"</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>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index ae88920..5a24cb3 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -286,10 +286,8 @@
     <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>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Ermöglicht der App, jederzeit die Geschwindigkeit des Maus- bzw. Touchpad-Zeigers zu ändern. Sollte nie für normale Apps benötigt werden."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"Tastaturlayout ändern"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Ermöglicht der App, das Tastaturlayout zu ändern. Sollte für normale Apps nie benötigt werden."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"Linux-Signale an Apps senden"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Ermöglicht der App, das Senden des gelieferten Signals an alle andauernden Prozesse zu fordern"</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"App permanent ausführen"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Geben Sie die erforderliche PIN ein:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"Zeichen einfügen"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Unbekannte App"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Kurznachrichten werden gesendet"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Es wird eine große Anzahl an SMS versendet. Tippen Sie zum Fortfahren auf \"OK\" oder tippen Sie auf \"Abbrechen\", um den Sendevorgang zu beenden."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Abbrechen"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"SIM-Karte entfernt"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"Das Mobilfunknetz ist erst wieder verfügbar, wenn Sie einen Neustart mit einer gültigen SIM-Karte durchführen."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Fertig"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Zum Deaktivieren von USB-Debugging tippen"</string>
     <string name="select_input_method" msgid="4653387336791222978">"Eingabemethode wählen"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"Eingabemethoden einrichten"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"Physische Tastatur"</string>
+    <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"Kandidaten"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Tag verringern"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Jahr verlängern"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Jahr verringern"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"Aktiviert"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"Nicht aktiviert"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"Ausgewählt"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"Nicht ausgewählt"</string>
-    <string name="switch_on" msgid="551417728476977311">"An"</string>
-    <string name="switch_off" msgid="7249798614327155088">"Aus"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"Gedrückt"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"Nicht gedrückt"</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>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index ce49a84..7c951cc 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -286,10 +286,8 @@
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Επιτρέπει στην εφαρμογή την αλλαγή της περιστροφής της οθόνης ανά πάσα στιγμή. Δεν απαιτείται για συνήθεις εφαρμογές."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"αλλαγή ταχύτητας δείκτη"</string>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Επιτρέπει στην εφαρμογή την αλλαγή της ταχύτητας του δείκτη του ποντικιού ή της επιφάνειας αφής ανά πάσα στιγμή. Δεν πρέπει να χρησιμοποιείται από συνήθεις εφαρμογές."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"αλλαγή διάταξης πληκτρολογίου"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Επιτρέπει στην εφαρμογή την αλλαγή της διάταξης πληκτρολογίου. Δεν απαιτείται για συνήθεις εφαρμογές."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"αποστολή σημάτων Linux σε εφαρμογές"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Επιτρέπει στην εφαρμογή την αποστολή αιτήματος για την αποστολή του παρεχόμενου σήματος σε όλες τις υπάρχουσες διαδικασίες."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"να εκτελείται συνεχώς η εφαρμογή"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Πληκτρολογήστε τον απαιτούμενο κωδικό PIN:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"Εισαγωγή χαρακτήρα"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Άγνωστη εφαρμογή"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Αποστολή μηνυμάτων SMS"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Αποστέλλεται μεγάλος αριθμός μηνυμάτων SMS. Αγγίξτε το στοιχείο \"OK\" για συνέχεια, ή το στοιχείο \"Ακύρωση\" για διακοπή της αποστολής."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Ακύρωση"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"Η κάρτα SIM αφαιρέθηκε"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"Το δίκτυο κινητής τηλεφωνίας δεν θα είναι διαθέσιμο μέχρι να κάνετε επανεκκίνηση αφού τοποθετήσετε μια έγκυρη κάρτα SIM."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Τέλος"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Αγγίξτε για απενεργοποίηση του εντοπισμού σφαλμάτων USB."</string>
     <string name="select_input_method" msgid="4653387336791222978">"Επιλογή μεθόδου εισόδου"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"Ρύθμιση μεθόδων εισαγωγής"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"Φυσικό πληκτρολόγιο"</string>
+    <string name="hardware" msgid="7517821086888990278">"Υλικό"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"υποψήφιοι"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Μείωση ημέρας"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Αύξηση έτους"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Μείωση έτους"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"ελέγχθηκε"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"δεν επιλέχθηκε"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"επιλεγμένο"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"δεν έχει επιλεγεί"</string>
-    <string name="switch_on" msgid="551417728476977311">"ενεργοποίηση"</string>
-    <string name="switch_off" msgid="7249798614327155088">"απενεργοποιημένη"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"πατήθηκε"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"δεν πατήθηκε"</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>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 38b69fe..208e96a 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -286,10 +286,8 @@
     <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>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Allows the app to change the mouse or touch pad pointer speed at any time. Should never be needed for normal apps."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"change keyboard layout"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Allows the app to change the keyboard layout. Should never be needed for normal apps."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"send Linux signals to apps"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Allows the app to request that the supplied signal be sent to all persistent processes."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"make app always run"</string>
@@ -1009,11 +1007,17 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Type the required PIN:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"Insert character"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Unknown app"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Sending SMS messages"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"A large number of SMS messages are being sent. Touch OK to continue or Cancel to stop sending."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Cancel"</string>
+    <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; is sending a large number of SMS messages. Do you want to allow this app to continue sending messages?"</string>
+    <string name="sms_control_yes" msgid="3663725993855816807">"Allow"</string>
+    <string name="sms_control_no" msgid="625438561395534982">"Deny"</string>
+    <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Send SMS to short code?"</string>
+    <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Send premium SMS?"</string>
+    <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; would like to send a text message to &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;, which appears to be an SMS short code.&lt;p&gt;Sending text messages to some short codes may cause your mobile account to be billed for premium services.&lt;p&gt;do you want to allow this app to send the message?"</string>
+    <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; would like to send a text message to &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;, which is a premium SMS short code.&lt;p&gt;&lt;b&gt;Sending a message to this destination will cause your mobile account to be billed for premium services.&lt;/b&gt;&lt;p&gt;Do you want to allow this app to send the message?"</string>
+    <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Send message"</string>
+    <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Don\'t send"</string>
+    <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Report malicious app"</string>
     <string name="sim_removed_title" msgid="6227712319223226185">"SIM card removed"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"The mobile network will be unavailable until you restart with a valid SIM card inserted."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Done"</string>
@@ -1063,10 +1067,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Touch to disable USB debugging."</string>
     <string name="select_input_method" msgid="4653387336791222978">"Choose input method"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"Set up input methods"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"Physical keyboard"</string>
+    <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidates"</u></string>
@@ -1193,14 +1195,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Decrease day"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Increase year"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Decrease year"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"ticked"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"not ticked"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"selected"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"not selected"</string>
-    <string name="switch_on" msgid="551417728476977311">"on"</string>
-    <string name="switch_off" msgid="7249798614327155088">"off"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"pressed"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"not pressed"</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>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index d400734..6f1ee53 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -286,10 +286,8 @@
     <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>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Permite que la aplicación cambie la velocidad del puntero del mouse o el trackpad en cualquier momento. Las aplicaciones normales no deben utilizar este permiso."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"Cambiar el diseño del teclado"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Permite que la aplicación cambie el diseño del teclado. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"enviar señales de Linux a las aplicaciones"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Permite que la aplicación solicite que la señal suministrada se envíe a todos los procesos persistentes."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"hacer que la aplicación se ejecute siempre"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Escribe el PIN solicitado:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"Insertar caracteres"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Aplicación desconocida"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Enviando mensajes SMS"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Se está enviando una gran cantidad de mensajes SMS. Toca \"Aceptar\" para continuar o \"Cancelar\" para detener el envío."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"Aceptar"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Cancelar"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"Tarjeta SIM eliminada"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"La red para celulares no estará disponible hasta que reinicies, luego de insertar una tarjeta SIM válida."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Finalizado"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Toca para desactivar la depuración de USB."</string>
     <string name="select_input_method" msgid="4653387336791222978">"Selecciona el método de introducción"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"Configurar métodos de introducción"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"Teclado físico"</string>
+    <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Reducir día"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Aumentar año"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Reducir año"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"marcado"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"no marcado"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"seleccionado"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"No se ha seleccionado."</string>
-    <string name="switch_on" msgid="551417728476977311">"Activado"</string>
-    <string name="switch_off" msgid="7249798614327155088">"Desactivado"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"presionado"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"sin presionar"</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>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 6852184..95e1152 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -286,10 +286,8 @@
     <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>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Permite que la aplicación modifique la velocidad del puntero del ratón o del trackpad en cualquier momento. Las aplicaciones normales no deberían necesitar este permiso."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"cambiar el diseño del teclado"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Permite que la aplicación cambie el diseño del teclado. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"enviar señales Linux a aplicaciones"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Permite que la aplicación solicite que la señal suministrada se envíe a todos los procesos persistentes."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"hacer que la aplicación se ejecute siempre"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Escribe el PIN solicitado:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"Insertar carácter"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Aplicación desconocida"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Enviando mensajes SMS..."</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Se va a enviar un número elevado de mensajes SMS. Selecciona Aceptar para continuar o Cancelar para detener el envío."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"Aceptar"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Cancelar"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"Tarjeta SIM eliminada"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"La red móvil no estará disponible hasta que reinicies el dispositivo con una tarjeta SIM válida."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Listo"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Tocar para inhabilitar la depuración USB"</string>
     <string name="select_input_method" msgid="4653387336791222978">"Seleccionar método de introducción"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"Ajustar métodos de introducción"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"Teclado físico"</string>
+    <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Reducir días"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Aumentar año"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Reducir año"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"seleccionado"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"no seleccionado"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"seleccionado"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"no seleccionado"</string>
-    <string name="switch_on" msgid="551417728476977311">"activado"</string>
-    <string name="switch_off" msgid="7249798614327155088">"desactivado"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"pulsado"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"sin pulsar"</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>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 737ab21..a72691f 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -286,10 +286,8 @@
     <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>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Võimaldab rakendusel muuta igal ajal hiire- või puutepadjakursori kiirust. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"klaviatuuri paigutuse muutmine"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Lubab rakendusel muuta klaviatuuri paigutust. Tavarakenduste puhul ei peaks kunagi vaja olema."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"Linuxi signaalide saatmine rakendustele"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Võimaldab rakendusel taotleda edastatud signaali saatmist kõigile püsiprotsessidele."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"Rakenduste pidev töös hoidmine"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Sisestage nõutav PIN-kood:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-kood:"</string>
     <string name="select_character" msgid="3365550120617701745">"Sisesta tähemärk"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Tundmatu rakendus"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS-sõnumite saatmine"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Saadetakse suur hulk SMS-sõnumid. Saatmise jätkamiseks valige OK, lõpetamiseks Tühista."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Tühista"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"SIM-kaart eemaldatud"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"Mobiilsidevõrk ei ole saadaval, kuni sisestate kehtiva SIM-kaardi ja taaskäivitate seadme."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Valmis"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Puudutage USB-silumise keelamiseks."</string>
     <string name="select_input_method" msgid="4653387336791222978">"Valige sisestusmeetod"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"Seadista sisestusmeetodid"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"Füüsiline klaviatuur"</string>
+    <string name="hardware" msgid="7517821086888990278">"Riistvara"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidaadid"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Päeva vähendamine"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Aasta suurendamine"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Aasta vähendamine"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"märgitud"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"pole märgitud"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"valitud"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"pole valitud"</string>
-    <string name="switch_on" msgid="551417728476977311">"sees"</string>
-    <string name="switch_off" msgid="7249798614327155088">"väljas"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"vajutatud"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"pole vajutatud"</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>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 80b273b..d33fe74 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -286,10 +286,8 @@
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"به برنامه اجازه می‎دهد تا چرخش صفحه را هر وقت بخواهد تغییر دهد. برای برنامه‎های عادی نیاز نیست."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"تغییر سرعت اشاره گر"</string>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"به برنامه اجازه می‎دهد تا سرعت ماوس و پد کنترل را هر وقت خواست تغییر دهد. برای برنامه‎های عادی نیاز نیست."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"تغییر چیدمان صفحه کلید"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"به برنامه اجازه می‌دهد تا چیدمان صفحه کلید را تغییر دهد. این کار هیچ گاه برای برنامه‌های عادی نیاز نیست."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"ارسال سیگنالهای Linux به برنامه‎ها"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"به برنامه اجازه می‎دهد تا درخواست کند سیگنال ارائه شده به همه مراحل دائم ارسال شود."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"همیشه برنامه اجرا شود"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"پین لازم را تایپ کنید:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"پین:"</string>
     <string name="select_character" msgid="3365550120617701745">"درج نویسه"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"برنامه ناشناخته"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"ارسال پیامک ها"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"تعداد زیادی پیام کوتاه ارسال شده است. برای ادامه، \"تأیید\" را لمس کرده و برای توقف ارسال، \"لغو\" را لمس کنید."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"تأیید"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"لغو"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"سیم کارت برداشته شد"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"تا وقتی که با یک سیم‌کارت معتبر راه‌اندازی مجدد نکنید شبکه تلفن همراه غیر قابل‌ دسترس خواهد بود."</string>
     <string name="sim_done_button" msgid="827949989369963775">"انجام شد"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"غیرفعال کردن اشکال زدایی USB را لمس کنید."</string>
     <string name="select_input_method" msgid="4653387336791222978">"انتخاب روش ورودی"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"تنظیم روش‌های ورودی"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"صفحه کلید فیزیکی"</string>
+    <string name="hardware" msgid="7517821086888990278">"سخت‌افزار"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"داوطلبین"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"کاهش روز"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"افزایش سال"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"کاهش سال"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"علامت زده"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"بدون علامت"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"انتخاب شد"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"انتخاب نشده"</string>
-    <string name="switch_on" msgid="551417728476977311">"روشن"</string>
-    <string name="switch_off" msgid="7249798614327155088">"خاموش"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"فشرده شد"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"فشرده نشد"</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>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index f011ec3..f03e1af 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -286,10 +286,8 @@
     <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>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Antaa sovelluksen muuttaa hiiren tai kosketuslevyn osoittimen nopeutta milloin tahansa. Ei tavallisten sovellusten käyttöön."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"vaihda näppäimistön asettelua"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Antaa sovelluksen muuttaa näppäimistön asettelua. Ei tavallisten sovellusten käyttöön."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"Linux-signaalien lähettäminen sovelluksille"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Antaa sovelluksen pyytää, että tarjottu signaali lähetetään kaikille käynnissä oleville prosesseille."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"sovelluksen asettaminen aina käynnissä olevaksi"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Kirjoita pyydetty PIN-koodi:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-koodi:"</string>
     <string name="select_character" msgid="3365550120617701745">"Lisää merkki"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Tuntematon sovellus"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Tekstiviestien lähettäminen"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Olet lähettämässä suurta määrää tekstiviestejä. Jatka koskettamalla OK tai peruuta lähetys valitsemalla Peruuta."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Peruuta"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"SIM-kortti poistettu"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"Mobiiliverkko ei ole käytettävissä, ennen kuin käynnistät uudelleen kelvollisella laitteeseen kytketyllä SIM-kortilla."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Valmis"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Poista USB-vianetsintä käytöstä koskettamalla tätä."</string>
     <string name="select_input_method" msgid="4653387336791222978">"Valitse syöttötapa"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"Määritä syöttötavat"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"Fyysinen näppäimistö"</string>
+    <string name="hardware" msgid="7517821086888990278">"Laitteisto"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidaatit"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Vähennä päivien määrää."</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Lisää vuosien määrää."</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Vähennä vuosien määrää."</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"valittu"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"ei valittu"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"valittu"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"ei valittu"</string>
-    <string name="switch_on" msgid="551417728476977311">"käytössä"</string>
-    <string name="switch_off" msgid="7249798614327155088">"pois käytöstä"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"painettu"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"ei painettu"</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>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 7c78654..72ac5f4 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -286,10 +286,8 @@
     <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>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Permet à l\'application de modifier à tout moment la vitesse du pointeur de la souris ou du pavé tactile. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"changer disposition clavier"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Permet à l\'application de changer la disposition du clavier. Les applications standards ne devraient pas nécessiter cette autorisation."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"envoyer des signaux Linux aux applications"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Permet à l\'application de demander que le signal fourni soit envoyé à tous les processus persistants."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"exécuter l\'application en continu"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Saisissez le code PIN requis :"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Code PIN :"</string>
     <string name="select_character" msgid="3365550120617701745">"Insérer un caractère"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Application inconnue"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Envoi de messages SMS"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Vous êtes sur le point d\'envoyer un grand nombre de SMS. Appuyez sur \"OK\" pour continuer ou sur \"Annuler\" pour interrompre l\'envoi."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Annuler"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"Carte SIM retirée"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"Le réseau mobile ne sera pas disponible avant le redémarrage avec une carte SIM valide insérée."</string>
     <string name="sim_done_button" msgid="827949989369963775">"OK"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Appuyez pour désactiver le débogage USB."</string>
     <string name="select_input_method" msgid="4653387336791222978">"Sélectionnez le mode de saisie"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"Configurer les modes de saisie"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"Clavier physique"</string>
+    <string name="hardware" msgid="7517821086888990278">"Matériel"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Jour précédent"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Année suivante"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Année précédente"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"coché"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"non coché"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"sélectionné"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"non sélectionné"</string>
-    <string name="switch_on" msgid="551417728476977311">"activé"</string>
-    <string name="switch_off" msgid="7249798614327155088">"désactivé"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"sélectionné"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"non sélectionné"</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>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 1ee3d03..e94e286 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -286,10 +286,8 @@
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"एप्‍लिकेशन को किसी भी समय स्‍क्रीन का रोटेशन बदलने देता है. सामान्‍य एप्‍लिकेशन के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"सूचक गति बदलें"</string>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"एप्लिकेशन को माउस या ट्रैकपैड सूचक गति को किसी भी समय बदलने देता है. सामान्‍य एप्‍लिकेशन के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"कीबोर्ड लेआउट बदलें"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"एप्‍लिकेशन को कीबोर्ड लेआउट बदलने देता है. सामान्‍य एप्‍लिकेशन के लिए कभी आवश्‍यक नहीं है."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"एप्लिकेशन को Linux सिग्नल भेजें"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"एप्‍लिकेशन को यह अनुरोध करने देता है कि दिया गया सिग्नल सभी जारी प्रक्रियाओं को भेजा जाए."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"एप्‍लिकेशन को हमेशा चलने वाला बनाएं"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"आवश्‍यक पिन लिखें:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"पिन:"</string>
     <string name="select_character" msgid="3365550120617701745">"वर्ण सम्‍मिलित करें"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"अज्ञात एप्‍लिकेशन"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS संदेश भेज रहा है"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"बड़ी संख्‍या में SMS संदेश भेजे जा रहे हैं. जारी रखने के लिए ठीक स्‍पर्श करें, या भेजना बंद करने के लिए रद्द करें स्‍पर्श करें."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"ठीक"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"रद्द करें"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"सिमकार्ड निकाला गया"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"मान्‍य सि‍म कार्ड डालकर पुन: प्रारंभ करने तक मोबाइल नेटवर्क अनुपलब्‍ध रहेगा."</string>
     <string name="sim_done_button" msgid="827949989369963775">"पूर्ण"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"USB डीबग करना अक्षम करने के लिए स्‍पर्श करें."</string>
     <string name="select_input_method" msgid="4653387336791222978">"इनपुट पद्धति चुनें"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"इनपुट पद्धतियां सेट करें"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"भौतिक कीबोर्ड"</string>
+    <string name="hardware" msgid="7517821086888990278">"हार्डवेयर"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"उम्‍मीदवार"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"दिन कम करें"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"वर्ष बढ़ाएं"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"वर्ष कम करें"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"चेक किया गया"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"चेक नहीं किया गया"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"चयनित"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"चयनित नहीं"</string>
-    <string name="switch_on" msgid="551417728476977311">"चालू"</string>
-    <string name="switch_off" msgid="7249798614327155088">"बंद"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"दबाया गया"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"दबाया नहीं गया."</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>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 0023310..412bc61 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1009,11 +1009,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Upišite potreban PIN:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"Umetni znak"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Nepoznata aplikacija"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Slanje SMS poruka"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Šalje se velika količina SMS poruka. Dodirnite \"U redu\" za nastavak ili \"Odustani\" za prekid slanja."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"U redu"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Odustani"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"SIM kartica uklonjena"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"Mobilna mreža bit će nedostupna do ponovnog pokretanja s umetnutom važećom SIM karticom."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Gotovo"</string>
@@ -1193,14 +1209,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Smanjenje dana"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Povećanje godine"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Smanjenje godine"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"označeno"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"nije označeno"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"odabran"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"nije odabrano"</string>
-    <string name="switch_on" msgid="551417728476977311">"uključeno"</string>
-    <string name="switch_off" msgid="7249798614327155088">"isključeno"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"pritisnut"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"nije pritisnut"</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>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 4ae52d5..c8f039f 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -286,10 +286,8 @@
     <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>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Lehetővé teszi az alkalmazás számára, hogy bármikor módosítsa az egér vagy az érintőpad mutatójának sebességét. Normál alkalmazásoknak soha nem lehet rá szükségük."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"billentyűzetkiosztás módosítása"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Lehetővé teszi az alkalmazás számára, hogy módosítsa a billentyűzetkiosztást. Normál alkalmazásoknak alapesetben nem lehet szükségük rá."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"Linux-jelek küldése az alkalmazásoknak"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Lehetővé teszi az alkalmazás számára, hogy a megadott jelet elküldje az összes állandó folyamatnak."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"az alkalmazás állandó futtatása"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Adja meg a szükséges PIN kódot:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN kód:"</string>
     <string name="select_character" msgid="3365550120617701745">"Karakter beszúrása"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Ismeretlen alkalmazás"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS-ek küldése"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Nagy számú SMS-t kíván elküldeni. A folytatáshoz érintse meg az \"OK\", a küldés leállításához a \"Mégse\" lehetőséget."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Mégse"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"SIM-kártya eltávolítva"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"A mobilhálózat nem lesz elérhető, amíg újra nem indítja egy érvényes SIM kártya behelyezése után."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Kész"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Érintse meg az USB hibakeresés kikapcsolásához."</string>
     <string name="select_input_method" msgid="4653387336791222978">"Beviteli mód kiválasztása"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"Beviteli módok beállítása"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"Fizikai billentyűzet"</string>
+    <string name="hardware" msgid="7517821086888990278">"Hardver"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"jelöltek"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Dátum értékének csökkentése"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Év értékének növelése"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Év értékének csökkentése"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"bejelölve"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"nincs bejelölve"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"bejelölve"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"nincs kiválasztva"</string>
-    <string name="switch_on" msgid="551417728476977311">"be"</string>
-    <string name="switch_off" msgid="7249798614327155088">"kikapcsolva"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"megnyomva"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"nincs megnyomva"</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>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index bd6294b..03dac8a 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -109,7 +109,7 @@
     <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Tidak diteruskan"</string>
     <string name="fcComplete" msgid="3118848230966886575">"Kode fitur selesai."</string>
     <string name="fcError" msgid="3327560126588500777">"Masalah sambungan atau kode fitur tidak valid."</string>
-    <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
+    <string name="httpErrorOk" msgid="1191919378083472204">"Oke"</string>
     <string name="httpError" msgid="7956392511146698522">"Terjadi kesalahan jaringan."</string>
     <string name="httpErrorLookup" msgid="4711687456111963163">"Tidak dapat menemukan URL."</string>
     <string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"Skema autentikasi situs tidak didukung."</string>
@@ -744,7 +744,7 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Mulai ulang"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Laman pada \"<xliff:g id="TITLE">%s</xliff:g>\" menyatakan:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Beranjak dari laman ini?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Sentuh OK untuk melanjutkan atau Batal untuk tetap pada laman ini."</string>
+    <string name="js_dialog_before_unload" msgid="730366588032430474">"Beranjak dari laman ini?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Sentuh Oke untuk melanjutkan atau Batal untuk tetap pada 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>
@@ -892,7 +892,7 @@
     <string name="VideoView_error_title" msgid="3534509135438353077">"Masalah video"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Video ini tidak valid untuk pengaliran ke perangkat ini."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Tidak dapat memutar video ini."</string>
-    <string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
+    <string name="VideoView_error_button" msgid="2822238215100679592">"Oke"</string>
     <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="noon" msgid="7245353528818587908">"tengah hari"</string>
     <string name="Noon" msgid="3342127745230013127">"Tengah hari"</string>
@@ -916,9 +916,9 @@
     <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Ruang penyimpanan tinggal sedikit"</string>
     <string name="low_internal_storage_view_text" product="tablet" msgid="4231085657068852042">"Ruang penyimpanan tablet semakin sedikit."</string>
     <string name="low_internal_storage_view_text" product="default" msgid="635106544616378836">"Ruang penyimpanan ponsel tersisa sedikit."</string>
-    <string name="ok" msgid="5970060430562524910">"OK"</string>
+    <string name="ok" msgid="5970060430562524910">"Oke"</string>
     <string name="cancel" msgid="6442560571259935130">"Batal"</string>
-    <string name="yes" msgid="5362982303337969312">"OK"</string>
+    <string name="yes" msgid="5362982303337969312">"Oke"</string>
     <string name="no" msgid="5141531044935541497">"Batal"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Perhatian"</string>
     <string name="loading" msgid="7933681260296021180">"Memuat..."</string>
@@ -938,7 +938,7 @@
     <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_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="force_close" msgid="8346072094521265605">"OK"</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>
@@ -1009,11 +1009,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Ketik PIN yang diminta:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"Sisipkan huruf"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Apl tak dikenal"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Mengirim pesan SMS"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Pesan SMS dalam jumlah besar sedang dikirimkan. Sentuh OK untuk melanjutkan, atau Batal untuk menghentikan pengiriman."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Batal"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"Kartu SIM dihapus"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"Jaringan seluler tidak akan tersedia sampai Anda memulai lagi dengan memasukkan kartu SIM yang valid."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Selesai"</string>
@@ -1048,7 +1064,7 @@
     <string name="dlg_confirm_kill_storage_users_title" msgid="963039033470478697">"Hidupkan penyimpanan USB"</string>
     <string name="dlg_confirm_kill_storage_users_text" msgid="5100428757107469454">"Jika Anda menyalakan penyimpanan USB, beberapa apl yang Anda gunakan akan berhenti dan mungkin tidak dapat dibuka hingga penyimpanan USB dimatikan."</string>
     <string name="dlg_error_title" msgid="7323658469626514207">"Operasi USB gagal"</string>
-    <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
+    <string name="dlg_ok" msgid="7376953167039865701">"Oke"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Tersambung sebagai perangkat media"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Tersambung sebagai kamera"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Tersambung sebagai pemasang"</string>
@@ -1193,14 +1209,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Kurangi hari"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Tambah tahun"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Kurangi tahun"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"dicentang"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"tidak diperiksa"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"dipilih"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"tidak dipilih"</string>
-    <string name="switch_on" msgid="551417728476977311">"nyala"</string>
-    <string name="switch_off" msgid="7249798614327155088">"mati"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"ditekan"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"tidak ditekan"</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>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index ae52c62..e9e5924 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -286,10 +286,8 @@
     <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>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Consente all\'applicazione di modificare la velocità del puntatore del mouse o del trackpad in qualsiasi momento. Non dovrebbe mai essere necessaria per le applicazioni normali."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"modifica del layout tastiera"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Consente all\'applicazione di modificare il layout della tastiera. Non dovrebbe mai essere necessaria per le normali applicazioni."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"invio segnali Linux alle applicazioni"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Consente all\'applicazione di richiedere l\'invio del segnale fornito a tutti i processi persistenti."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"esecuzione permanente delle applicazioni"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Inserisci il PIN richiesto:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"Inserisci carattere"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Applicazione sconosciuta"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Invio SMS"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"È in corso l\'invio di numerosi SMS. Tocca \"OK\" per continuare oppure \"Annulla\" per interrompere l\'invio."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Annulla"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"Scheda SIM rimossa"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"La rete mobile non sarà disponibile finché non eseguirai il riavvio con una scheda SIM valida inserita."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Fine"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Tocca per disattivare il debug USB."</string>
     <string name="select_input_method" msgid="4653387336791222978">"Scegli il metodo di immissione"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"Configura metodi di immissione"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"Tastiera fisica"</string>
+    <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidati"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Riduci giorno"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Aumenta anno"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Riduci anno"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"selezionata"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"non selezionato"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"selezionato"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"non selezionato"</string>
-    <string name="switch_on" msgid="551417728476977311">"attivo"</string>
-    <string name="switch_off" msgid="7249798614327155088">"disattivo"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"premuto"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"non premuto"</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>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 613410f..731546c 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -286,10 +286,8 @@
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"מאפשר ליישום לשנות את הסיבוב של המסך בכל עת. הרשאה זו לעולם אינה נחוצה ליישומים רגילים."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"שינוי מהירות המצביע"</string>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"מאפשר ליישום לשנות את המהירות של מצביע העכבר או לוח המגע בכל עת. יישומים רגילים לא אמורים לעולם להזדקק להרשאה זו."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"שנה את פריסת המקלדת"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"מאפשר ליישום לשנות את פריסת המקלדת. הרשאה זו לעולם אינה אמורה להיות נחוצה עבור יישומים רגילים."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"שליחת אותות Linux ליישומים"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"מאפשר ליישום לבקש שהאות שנקלט יישלח לכל התהליכים המתמשכים."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"הגדרת היישום לפעול תמיד"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"הקלד את קוד ה-PIN הנדרש."</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"הוסף תו"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"יישום לא ידוע"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"שולח הודעות SMS"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"מתבצעת כעת שליחה של מספר גדול של הודעות SMS. גע באפשרות \'אישור\' כדי להמשיך, או \'ביטול\' כדי לעצור את השליחה."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"אישור"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"ביטול"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"כרטיס ה-SIM הוסר"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"הרשת הסלולרית לא תהיה זמינה עד שתפעיל מחדש לאחר הכנסת כרטיס SIM חוקי."</string>
     <string name="sim_done_button" msgid="827949989369963775">"סיום"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"גע כדי להשבית את ניקוי הבאגים בהתקן ה-USB."</string>
     <string name="select_input_method" msgid="4653387336791222978">"בחר שיטת הזנה"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"הגדר שיטות קלט"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"מקלדת פיזית"</string>
+    <string name="hardware" msgid="7517821086888990278">"חומרה"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"מועמדים"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"הפחת יום"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"הוסף שנה"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"הפחת שנה"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"מסומן"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"לא מסומן"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"נבחר"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"לא נבחר"</string>
-    <string name="switch_on" msgid="551417728476977311">"מופעל"</string>
-    <string name="switch_off" msgid="7249798614327155088">"כבוי"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"לחוץ"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"לא לחוץ"</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>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 5e5010d..e9d3558 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -286,10 +286,8 @@
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"いつでも画面の向きを変更することをアプリに許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"ポインタの速度の変更"</string>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"マウスまたはトラックパッドのポインタの速度をいつでも変更することをアプリに許可します。通常のアプリでは不要です。"</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"キーボードレイアウトの変更"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"キーボードレイアウトの変更をアプリに許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"アプリへのLinuxシグナルの送信"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"受信したシグナルをすべての継続プロセスに送信するようリクエストすることをアプリに許可します。"</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"アプリの常時実行"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"必要なPINを入力してください:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"文字を挿入"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"不明なアプリ"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMSメッセージの送信中"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"大量のSMSメッセージを送信しようとしています。[OK]で送信、[キャンセル]で中止します。"</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"キャンセル"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"SIMカードが取り外されました"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"有効なSIMカードを挿入して再起動するまでは、モバイルネットワークは利用できません。"</string>
     <string name="sim_done_button" msgid="827949989369963775">"完了"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"タップしてUSBデバッグを無効にします。"</string>
     <string name="select_input_method" msgid="4653387336791222978">"入力方法の選択"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"入力方法をセットアップ"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"物理キーボード"</string>
+    <string name="hardware" msgid="7517821086888990278">"ハードウェア"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"候補"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"1日戻します"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"1年進めます"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"1年戻します"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"ON"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"OFF"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"ON"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"選択されていません"</string>
-    <string name="switch_on" msgid="551417728476977311">"ON"</string>
-    <string name="switch_off" msgid="7249798614327155088">"OFF"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"ON"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"OFF"</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>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 5556aae..02ab306 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -286,10 +286,8 @@
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"앱이 언제든지 화면 회전을 변경할 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"포인터 속도 변경"</string>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"앱이 언제든지 마우스 또는 트랙패드 포인터의 속도를 변경할 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"키보드 레이아웃 변경"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"앱이 키보드 레이아웃을 변경할 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"앱에 Linux 시그널 보내기"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"제공된 시그널을 모든 영구 프로세스로 전송하는 것을 앱이 요청할 수 있도록 허용합니다."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"앱이 항상 실행되도록 설정"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"필수 PIN 입력:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"문자 삽입"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"알 수 없는 앱"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS 메시지를 보내는 중"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"SMS 메시지를 대량 전송 중입니다. 계속하려면 \'확인\'을 터치하고 전송을 중지하려면 \'취소\'를 터치하세요."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"확인"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"취소"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"SIM 카드 제거됨"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"유효한 SIM 카드를 삽입하여 다시 시작할 때까지 모바일 네트워크를 사용할 수 없습니다."</string>
     <string name="sim_done_button" msgid="827949989369963775">"완료"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"USB 디버깅을 사용하지 않으려면 터치하세요."</string>
     <string name="select_input_method" msgid="4653387336791222978">"입력 방법 선택"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"입력 방법 설정"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"물리적 키보드"</string>
+    <string name="hardware" msgid="7517821086888990278">"하드웨어"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"가능한 원인"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"\'일\'을 줄입니다."</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"\'연도\'를 늘립니다."</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"\'연도\'를 줄입니다."</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"확인"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"선택 안함"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"선택됨"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"선택 안함"</string>
-    <string name="switch_on" msgid="551417728476977311">"켜짐"</string>
-    <string name="switch_off" msgid="7249798614327155088">"꺼짐"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"누름"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"누르지 않음"</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>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 9e82e8c..3d389d8 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -286,10 +286,8 @@
     <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>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Leidžiama programai keisti pelės ar sensorinio pulto žymiklio greitį. Įprastoms programoms to neturėtų prireikti."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"keisti klaviatūros išdėstymą"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Leidžiama programai pakeisti klaviatūros išdėstymą. Įprastoms programoms to neturėtų prireikti."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"siųsti „Linux“ signalus programoms"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Leidžiama programai pateikti užklausą, kad teikiamas signalas būtų siunčiamas visiems nuolatiniams procesams."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"nustatyti, kad programa būtų visada vykdoma"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Įveskite reikiamą PIN kodą:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN kodas:"</string>
     <string name="select_character" msgid="3365550120617701745">"Įterpti simbolį"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Nežinoma programa"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS pranešimų siuntimas"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Siunčiama daug SMS pranešimų. Palieskite „Gerai“, jei norite tęsti, arba „Atšaukti“, jei norite sustabdyti siuntimą."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"Gerai"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Atšaukti"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"SIM kortelė pašalinta"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"Mobilusis tinklas bus nepasiekiamas, kol nepaleisite iš naujo įdėję tinkamą SIM kortelę."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Atlikta"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Palieskite, kad neleistumėte USB derinimo."</string>
     <string name="select_input_method" msgid="4653387336791222978">"Pasirinkite įvesties metodą"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"Nustatyti įvesties metodus"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"Fizinė klaviatūra"</string>
+    <string name="hardware" msgid="7517821086888990278">"Apar. įr."</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidatai"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Sumažinti dienų skaičių"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Padidinti metų skaičių"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Sumažinti metų skaičių"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"pažymėtas"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"nepatikrinta"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"pasirinkta"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"nepasirinkta"</string>
-    <string name="switch_on" msgid="551417728476977311">"įjungta"</string>
-    <string name="switch_off" msgid="7249798614327155088">"išjungta"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"paspausta"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"nepaspausta"</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>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index ae451e0..05d0dbe 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -286,10 +286,8 @@
     <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>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Ļauj lietotnei jebkurā laikā mainīt peles vai skārienpaliktņa rādītāja ātrumu. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"Tastatūras izkārtojuma maiņa"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Ļauj lietotnei mainīt tastatūras izkārtojumu. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"sūtīt Linux signālus lietotnēm"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Ļauj lietotnei pieprasīt, lai piegādātais signāls tiktu sūtīts visiem pastāvīgajiem procesiem."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"likt lietotnei vienmēr darboties"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Ierakstiet pieprasīto PIN:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"Ievietojiet rakstzīmi"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Nezināma lietotne"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Īsziņu sūtīšana"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Tiek sūtīts daudz īsziņu. Pieskarieties Labi, lai turpinātu, vai Atcelt, lai apturētu sūtīšanu."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"Labi"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Atcelt"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"SIM karte ir izņemta."</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"Mobilais tīkls nebūs pieejams līdz brīdim, kad restartēsiet ierīci ar ievietotu derīgu SIM karti."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Gatavs"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Pieskarieties, lai atspējotu USB atkļūdošanu."</string>
     <string name="select_input_method" msgid="4653387336791222978">"Ievades metodes izvēle"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"Iestatīt ievades metodes"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"Fiziskā tastatūra"</string>
+    <string name="hardware" msgid="7517821086888990278">"Aparatūra"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidāti"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Norādīt agrāku dienu"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Norādīt vēlāku gadu"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Norādīt agrāku gadu"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"atzīmēta"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"nav atzīmēta"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"atlasīta"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"nav atlasīta"</string>
-    <string name="switch_on" msgid="551417728476977311">"ieslēgts"</string>
-    <string name="switch_off" msgid="7249798614327155088">"izslēgts"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"nospiesta"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"nav nospiesta"</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>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index ead175b..f0f5630 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -286,10 +286,8 @@
     <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>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Membenarkan apl untuk menukar kelajuan penunjuk tetikus atau pad jejak pada bila-bila masa. Tidak sekali-kali diperlukan untuk apl biasa."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"tukar susun atur papan kekunci"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Membenarkan apl menukar susun atur papan kekunci. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"hantar isyarat Linux kepada apl"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Membenarkan apl meminta isyarat yang dibekalkan dihantar kepada semua proses yang berterusan."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"buatkan apl sentiasa berjalan"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Taipkan PIN yang diperlukan:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"Masukkan aksara"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Apl tidak diketahui"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Menghantar mesej SMS"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Sejumlah besar mesej SMS sedang dihantar. Sentuh \"OK\" untuk meneruskan atau \"Batal\" untuk menghentikan penghantaran."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Batal"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"Kad SIM dikeluarkan"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"Rangkaian mudah alih tidak akan tersedia sehingga anda mula semula dengan kad SIM yang sah dimasukkan."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Selesai"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Sentuh untuk melumpuhkan penyahpepijatan USB."</string>
     <string name="select_input_method" msgid="4653387336791222978">"Pilih kaedah input"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"Sediakan kaedah input"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"Papan kekunci fizikal"</string>
+    <string name="hardware" msgid="7517821086888990278">"Perkakasan"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"calon"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Kurangkan hari"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Tingkatkan tahun"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Kurangkan tahun"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"ditandakan"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"tidak ditandakan"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"dipilih"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"tidak dipilih"</string>
-    <string name="switch_on" msgid="551417728476977311">"hidup"</string>
-    <string name="switch_off" msgid="7249798614327155088">"mati"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"ditekan."</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"tidak ditekan"</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>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index bbd846f..6609d29 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1009,11 +1009,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Skriv inn påkrevd PIN-kode:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"Sett inn tegn"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Ukjent app"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Sender SMS-meldinger"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Et stort antall SMS-meldinger sendes. Trykk på OK for å fortsette, eller trykk på Avbryt for å avbryte sendingen."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Avbryt"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"SIM-kort er fjernet"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"Det mobile nettverket forblir utilgjengelig inntil du starter på nytt med et gyldig SIM-kort."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Fullført"</string>
@@ -1193,14 +1209,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Reduser dager"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Øk år"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Reduser år"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"valgt"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"ikke valgt"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"valgt"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"ikke valgt"</string>
-    <string name="switch_on" msgid="551417728476977311">"på"</string>
-    <string name="switch_off" msgid="7249798614327155088">"av"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"trykket"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"ikke trykket"</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>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 8440d62..1c8809a 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -286,10 +286,8 @@
     <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>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Hiermee kan de app de snelheid van de muis- of trackpadaanwijzer op elk moment wijzigen. Nooit vereist voor normale apps."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"toetsenbordindeling wijzigen"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Hiermee kan de app de toetsenbordindeling wijzigen. Nooit vereist voor normale apps."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"Linux-signalen verzenden naar apps"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Hiermee kan de app ervoor zorgen dat het geleverde signaal wordt verzonden naar alle persistente processen."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"app altijd laten uitvoeren"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Voer de gewenste pincode in:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Pincode"</string>
     <string name="select_character" msgid="3365550120617701745">"Teken invoegen"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Onbekende app"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS-berichten verzenden"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Er wordt een groot aantal sms\'jes verzonden. Raak \'OK\' aan om door te gaan of \'Annuleren\' om de verzending te stoppen."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Annuleren"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"Simkaart verwijderd"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"Het mobiele netwerk is niet beschikbaar totdat u het apparaat opnieuw start met een geldige simkaart."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Gereed"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Raak deze optie aan om USB-foutopsporing uit te schakelen."</string>
     <string name="select_input_method" msgid="4653387336791222978">"Invoermethode selecteren"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"Invoermethoden instellen"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"Fysiek toetsenbord"</string>
+    <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidaten"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Lagere waarde voor dag"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Hogere waarde voor jaar"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Lagere waarde voor jaar"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"aangevinkt"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"niet aangevinkt"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"geselecteerd"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"niet geselecteerd"</string>
-    <string name="switch_on" msgid="551417728476977311">"aan"</string>
-    <string name="switch_off" msgid="7249798614327155088">"uit"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"ingedrukt"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"niet ingedrukt"</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>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index ee1e6a3..83b7aba 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -286,10 +286,8 @@
     <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>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Pozwala aplikacji zmienić szybkość wskaźnika myszy lub touchpada w dowolnym momencie. Nieprzeznaczone dla zwykłych aplikacji."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"zmiana układu klawiatury"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Zezwala aplikacji na zmianę układu klawiatury. Nieprzeznaczone dla zwykłych aplikacji."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"wysyłanie sygnałów systemu Linux do aplikacji"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Pozwala aplikacji na żądanie, aby dostarczony sygnał został wysłany do wszystkich trwałych procesów."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"sprawianie, że aplikacja jest cały czas uruchomiona"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Wpisz wymagany kod PIN:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Kod PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"Wstaw znak"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Nieznana aplikacja"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Wysyłanie wiadomości SMS"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Wysyłana jest duża liczba wiadomości SMS. Dotknij OK, aby kontynuować, lub Anuluj, aby zatrzymać wysyłanie."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Anuluj"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"Karta SIM wyjęta"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"Sieć komórkowa będzie niedostępna do chwili ponownego uruchomienia urządzenia z użyciem ważnej karty SIM."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Gotowe"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Dotknij, aby wyłączyć debugowanie USB."</string>
     <string name="select_input_method" msgid="4653387336791222978">"Wybierz metodę wprowadzania"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"Konfiguruj metody wprowadzania"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"Klawiatura fizyczna"</string>
+    <string name="hardware" msgid="7517821086888990278">"Sprzęt"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCĆDEĘFGHIJKLŁMNŃOÓPQRSŚTUVWXYZŹŻ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandydaci"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Zmień dzień na wcześniejszy"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Zmień rok na późniejszy"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Zmień rok na wcześniejszy"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"zaznaczono"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"nie zaznaczono"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"wybrano"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"nie wybrano"</string>
-    <string name="switch_on" msgid="551417728476977311">"włączono"</string>
-    <string name="switch_off" msgid="7249798614327155088">"wyłączono"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"naciśnięto"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"nie naciśnięto"</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>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 393ba17..8f2f78f 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -286,10 +286,8 @@
     <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>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Permite à aplicação mudar em qualquer altura a velocidade do ponteiro do rato ou do trackpad. Nunca deverá ser necessário para aplicações normais."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"alterar o esquema de teclado"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Permite que a aplicação altere o esquema de teclado. Nunca deverá ser necessário para aplicações normais."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"enviar sinais Linux para aplicações"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Permite à aplicação pedir que o sinal fornecido seja enviado a todos os processos persistentes."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"fazer com que a aplicação seja sempre executada"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Introduza o PIN solicitado:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"Introduzir carácter"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Aplicação desconhecida"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"A enviar mensagens SMS"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Está a ser enviado um grande número de mensagens SMS. Toque em “OK” para continuar ou “Cancelar” para parar o envio."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Cancelar"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"Cartão SIM removido"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"A rede de telemóvel estará indisponível até que reinicie o aparelho com um cartão SIM válido inserido."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Concluído"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Toque para desativar a depuração USB."</string>
     <string name="select_input_method" msgid="4653387336791222978">"Escolher o método de entrada"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"Configurar métodos de introdução"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"Teclado físico"</string>
+    <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Diminuir dia"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Aumentar ano"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Diminuir ano"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"marcado"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"desmarcado"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"selecionado"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"não selecionado"</string>
-    <string name="switch_on" msgid="551417728476977311">"ativado"</string>
-    <string name="switch_off" msgid="7249798614327155088">"desativado"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"premido"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"não premido"</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>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index bb145f7..4d770b5 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -286,10 +286,8 @@
     <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>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Permite que o aplicativo altere a velocidade do cursos do mouse ou trackpad a qualquer momento. Nunca deve ser necessário para aplicativos normais."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"alterar layout do teclado"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Permite que o aplicativo altere o layout do teclado. Não será necessário para aplicativos normais."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"enviar sinais para aplicativos Linux"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Permite que o aplicativo solicite o envio do sinal fornecido a todos os processos persistentes."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"sempre executar o aplicativo"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Digite o PIN obrigatório:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"Inserir caractere"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Aplicativo desconhecido"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Enviando mensagens SMS"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Muitas mensagens SMS estão sendo enviadas. Selecione \"OK\" para continuar ou \"Cancelar\" para interromper o envio."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Cancelar"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"Cartão SIM removido"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"A rede móvel ficará indisponível até que você reinicie com um cartão SIM válido inserido."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Concluído"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Toque para desativar a depuração do USB."</string>
     <string name="select_input_method" msgid="4653387336791222978">"Selecione o método de entrada"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"Configurar métodos de entrada"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"Teclado físico"</string>
+    <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Diminuir dia"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Aumentar ano"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Diminuir ano"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"verificado"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"não selecionado"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"selecionado"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"Não selecionado"</string>
-    <string name="switch_on" msgid="551417728476977311">"ativado"</string>
-    <string name="switch_off" msgid="7249798614327155088">"desativado"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"pressionado"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"não pressionado"</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>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index 8b0718f..6f066de 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -1489,13 +1489,27 @@
     <!-- no translation found for wifi_p2p_show_pin_message (8530563323880921094) -->
     <skip />
     <string name="select_character" msgid="3365550120617701745">"Inserir in caracter"</string>
-    <!-- no translation found for sms_control_default_app_name (3058577482636640465) -->
-    <skip />
     <string name="sms_control_title" msgid="7296612781128917719">"Trametter messadis SMS"</string>
-    <!-- no translation found for sms_control_message (4073755190243093924) -->
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
     <skip />
-    <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Interrumper"</string>
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <!-- no translation found for sim_removed_title (6227712319223226185) -->
     <skip />
     <!-- no translation found for sim_removed_message (2333164559970958645) -->
@@ -1788,22 +1802,6 @@
     <skip />
     <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
     <skip />
-    <!-- no translation found for checkbox_checked (7222044992652711167) -->
-    <skip />
-    <!-- no translation found for checkbox_not_checked (5174639551134444056) -->
-    <skip />
-    <!-- no translation found for radiobutton_selected (8603599808486581511) -->
-    <skip />
-    <!-- no translation found for radiobutton_not_selected (2908760184307722393) -->
-    <skip />
-    <!-- no translation found for switch_on (551417728476977311) -->
-    <skip />
-    <!-- no translation found for switch_off (7249798614327155088) -->
-    <skip />
-    <!-- no translation found for togglebutton_pressed (4180411746647422233) -->
-    <skip />
-    <!-- no translation found for togglebutton_not_pressed (4495147725636134425) -->
-    <skip />
     <!-- no translation found for keyboardview_keycode_alt (4856868820040051939) -->
     <skip />
     <!-- no translation found for keyboardview_keycode_cancel (1203984017245783244) -->
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index d93d8d1..3772861 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1009,11 +1009,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Introduceţi codul PIN necesar:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Cod PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"Introduceţi caracterul"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Aplicaţie necunoscută"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Se trimit mesaje SMS"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"În acest moment se trimit multe mesaje SMS. Atingeţi „OK” pentru a continua sau „Anulaţi” pentru a opri trimiterea."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Anulaţi"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"Card SIM eliminat"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"Reţeaua mobilă va fi indisponibilă până când reporniţi cu o cartelă SIM validă introdusă."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Terminat"</string>
@@ -1193,14 +1209,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Reduceţi valoarea pentru zi"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Creşteţi valoarea pentru an"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Reduceţi valoarea pentru an"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"bifată"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"nebifată"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"selectat"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"neselectat"</string>
-    <string name="switch_on" msgid="551417728476977311">"activat"</string>
-    <string name="switch_off" msgid="7249798614327155088">"dezactivat"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"apăsat"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"neapăsat"</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>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 2743763..b967620 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -286,10 +286,8 @@
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Приложение сможет менять ориентацию экрана. Это разрешение не используется обычными приложениями."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"изменять скорость указателя"</string>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Приложение сможет в любой момент изменить скорость движения указателя мыши или сенсорной панели. Это разрешение не используется обычными приложениями."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"менять раскладку автоматически"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Разрешить автоматическую смену раскладки клавиатуры (используется лишь в некоторых приложениях)."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"отправка сигналов Linux приложениям"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Приложение сможет запрашивать передачу полученного сигнала всем постоянным процессам."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"постоянная работа приложения"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Введите PIN-код:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-код:"</string>
     <string name="select_character" msgid="3365550120617701745">"Введите символ"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Неизвестное приложение"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Отправка SMS-сообщений"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Отправляется большое количество SMS-сообщений. Нажмите \"ОК\", чтобы продолжить отправку, или \"Отмена\", чтобы прекратить ее."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"ОК"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Отмена"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"SIM-карта удалена"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"Пока вы не вставите действующую SIM-карту, мобильная сеть будет недоступна."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Готово"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Нажмите, чтобы отключить отладку по USB."</string>
     <string name="select_input_method" msgid="4653387336791222978">"Выберите способ ввода"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"Настройка способов ввода"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"Физическая клавиатура"</string>
+    <string name="hardware" msgid="7517821086888990278">"Аппаратура"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"варианты"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"На день назад"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"На год вперед"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"На год назад"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"установлено"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"не установлено"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"выбрано"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"не выбрано"</string>
-    <string name="switch_on" msgid="551417728476977311">"Включено"</string>
-    <string name="switch_off" msgid="7249798614327155088">"Выкл."</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"нажато"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"не нажато"</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>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 49d04c3..1bf7a17 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -286,10 +286,8 @@
     <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>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Umožňuje aplikácii kedykoľvek zmeniť rýchlosť kurzora myši alebo touchpadu. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"zmeniť rozloženie klávesnice"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Umožňuje aplikácii zmeniť rozloženie klávesnice. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"odoslať aplikáciám signály systému Linux"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Umožňuje aplikácii vyžiadať odoslanie poskytnutého signálu všetkým trvalým procesom."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"nastaviť, aby bola aplikácia neustále spustená"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Zadajte požadovaný kód PIN:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"Vkladanie znakov"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Neznáma aplikácia"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Odosielanie správ SMS"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Odosiela sa veľký počet správ SMS. Ak chcete pokračovať, dotknite sa tlačidla OK. Ak chcete odosielanie ukončiť, dotknite sa tlačidla Zrušiť."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Zrušiť"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"Karta SIM bola odobraná"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"Mobilná sieť nebude k dispozícii, kým nevložíte platnú kartu SIM a zariadenie nereštartujete."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Hotovo"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Dotknutím zakážete ladenie USB."</string>
     <string name="select_input_method" msgid="4653387336791222978">"Zvoliť metódu vstupu"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"Nastavenie metód vstupu"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"Fyzická klávesnica"</string>
+    <string name="hardware" msgid="7517821086888990278">"Hardvér"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁÄBCČDĎDZDŽEÉFGHCHIÍJKLĽMNŇOÓÔPRŔSŠTŤUÚVWXYÝZŽ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidáti"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Ubrať deň"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Pridať rok"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Ubrať rok"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"začiarknuté"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"nezačiarknuté"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"vybratý"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"nie je vybraté"</string>
-    <string name="switch_on" msgid="551417728476977311">"zapnuté"</string>
-    <string name="switch_off" msgid="7249798614327155088">"vypnuté"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"stlačené"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"nestlačené"</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>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 55f3593..152d1c1 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -286,10 +286,8 @@
     <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>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Programu omogoča spreminjanje hitrosti kazalca miške ali sledilne ploščice. Tega ni treba nikoli uporabiti za navadne programe."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"spreminjanje postavitve tipkovnice"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Aplikaciji omogoča, da kadar koli spremeni postavitev tipkovnice. Običajne aplikacije tega ne potrebujejo."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"pošiljanje signalov Linuxa programom"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Programu omogoča, da zahteva, da je posredovani signal poslan vsem trajnim procesom."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"neprekinjeno izvajanje programov"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Vnesite zahtevano kodo PIN:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"Vstavljanje znaka"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Neznan program"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Pošiljanje sporočil SMS"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"V pošiljanju je veliko sporočil SMS. Če želite nadaljevati, izberite »V redu«. Če želite pošiljanje ustaviti, izberite »Prekliči«."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"V redu"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Prekliči"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"Kartica SIM odstranjena"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"Mobilno omrežje ne bo na voljo, dokler naprave vnovič ne zaženete z veljavno kartico SIM."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Dokončano"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Dotaknite se, če želite onemogočiti iskanje in odpravljanje napak prek vrat USB."</string>
     <string name="select_input_method" msgid="4653387336791222978">"Izberite način vnosa"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"Nastavi načine vnosa"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"Fizična tipkovnica"</string>
+    <string name="hardware" msgid="7517821086888990278">"Strojna oprema"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Zmanjšanje vrednosti za dan"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Povečanje vrednosti za leto"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Zmanjšanje vrednosti za leto"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"potrjeno"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"ni odkljukano"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"izbrano"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"ni izbrano"</string>
-    <string name="switch_on" msgid="551417728476977311">"vklopljeno"</string>
-    <string name="switch_off" msgid="7249798614327155088">"izklopljeno"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"vklopljen"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"izklopljen"</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>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index de03bec..9e63b31 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1009,11 +1009,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Унесите потребни PIN:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"Уметање знака"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Непозната апликација"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Слање SMS порука"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Шаље се велики број SMS порука. Додирните Потврди да бисте наставили или Откажи да бисте зауставили слање."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"Потврди"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Откажи"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"SIM картица је уклоњена"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"Мобилна мрежа неће бити доступна док не покренете систем поново уз уметање важеће SIM картице."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Готово"</string>
@@ -1193,14 +1209,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Смањивање дана"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Повећавање године"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Смањивање године"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"изабрано"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"није потврђено"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"изабрано"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"није изабрано"</string>
-    <string name="switch_on" msgid="551417728476977311">"укључено"</string>
-    <string name="switch_off" msgid="7249798614327155088">"искључено"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"притиснуто"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"није притиснуто"</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>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 7448ff8..3db9ec7 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -286,10 +286,8 @@
     <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>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Tillåter att appen när som helst ändrar hastigheten för musens eller styrplattans markör. Ska inte behövas för vanliga appar."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"ändra tangentbordslayout"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Tillåter att appen ändrar tangentbordets layout. Ska inte behövas för vanliga appar."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"skicka Linux-signaler till appar"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Tillåter att appen begär att den angivna signalen skickas till alla beständiga processer."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"se till att appen alltid körs"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Ange den obligatoriska PIN-koden:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-kod:"</string>
     <string name="select_character" msgid="3365550120617701745">"Infoga tecken"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Okänd app"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Skickar SMS"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Flera SMS skickas. Tryck på OK om du vill fortsätta eller på Avbryt om du vill avsluta sändningen."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Avbryt"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"SIM-kortet togs bort"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"Det mobila nätverket kommer inte att vara tillgängligt förrän du startar om med ett giltigt SIM-kort."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Klar"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Tryck om du vill inaktivera USB-felsökning."</string>
     <string name="select_input_method" msgid="4653387336791222978">"Välj inmatningsmetod"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"Konfigurera inmatningsmetoder"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"Fysiskt tangentbord"</string>
+    <string name="hardware" msgid="7517821086888990278">"Maskinvara"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidater"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Minska dagar"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Öka år"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Minska år"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"markerat"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"inte markerat"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"markerade"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"ej vald"</string>
-    <string name="switch_on" msgid="551417728476977311">"på"</string>
-    <string name="switch_off" msgid="7249798614327155088">"av"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"intryckt"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"inte intryckt"</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>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index ab6c82f..20bc2c6 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -286,10 +286,8 @@
     <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>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Inaruhusu programu kubadilisha kasi ya kielekezi cha kipanya au pedi ya kufuatilia wakati wowote. Kamwe haitahitajika kwa programu za kawaida."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"badilisha mpangilio wa kibodi"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Inaruhusu programu kubadilisha mpangilio wa kibodi. Haipaswi kamwe kuhitajika kwa rogramu za kawaida."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"Tuma ishara za Linux kwa programu"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Inaruhusu programu kuomba ishara iliyotolewa kutumwa kwa michakato inyoendelea."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"Fanya programu kuendeshwa kila mara"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Charaza PIN inayohitajika:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"Ingiza kibambo"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Programu isiyojulikana"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Inatuma ujumbe wa SMS"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Idadi kubwa ya jumbe za SMS inatumwa. Gusa SAWA kuendelea, au Ghairi kuwacha kutuma."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"Sawa"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Ghairi"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"Kadi ya SIM 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>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Gusa ili kulemaza utatuaji wa USB."</string>
     <string name="select_input_method" msgid="4653387336791222978">"Chagua njia ya ingizo"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"Weka mbinu za ingizo"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"Kibodi halisi"</string>
+    <string name="hardware" msgid="7517821086888990278">"Maunzi"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"wagombeaji"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Punguza siku"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Ongeza mwaka"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Punguza mwaka"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"imeangaliwa"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"haijakaguliwa"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"Iliyochaguliwa"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"Haijachaguliwa"</string>
-    <string name="switch_on" msgid="551417728476977311">"Washa"</string>
-    <string name="switch_off" msgid="7249798614327155088">"zima"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"iliyobonyezwa"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"Haijabonyezwa"</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>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 7007522..0884fb7 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1009,11 +1009,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"พิมพ์ PIN ที่ต้องการ:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"ใส่อักขระ"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"แอปพลิเคชันที่ไม่รู้จัก"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"กำลังส่งข้อความ SMS"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"กำลังส่งข้อความ SMS จำนวนมาก แตะ \"ตกลง\" เพื่อทำงานต่อหรือ \"ยกเลิก\" เพื่อหยุดส่ง"</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"ตกลง"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"ยกเลิก"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"นำซิมการ์ดออกแล้ว"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"เครือข่ายมือถือจะไม่สามารถใช้งานได้จนกว่าคุณจะรีสตาร์ทโดยใส่ซิมการ์ดที่ถูกต้องแล้ว"</string>
     <string name="sim_done_button" msgid="827949989369963775">"เสร็จสิ้น"</string>
@@ -1193,14 +1209,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"ลดวัน"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"เพิ่มปี"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"ลดปี"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"เลือกไว้"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"ไม่ได้ตรวจสอบ"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"เลือกแล้ว"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"ไม่ได้เลือก"</string>
-    <string name="switch_on" msgid="551417728476977311">"เปิด"</string>
-    <string name="switch_off" msgid="7249798614327155088">"ปิด"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"กดแล้ว"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"ไม่ได้กด"</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>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 31ad6c8..26f7d5e 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -286,10 +286,8 @@
     <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>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Pinapayagan ang app na baguhin ang bilis ng mouse o trackpad pointer anumang oras. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"baguhin ang layout ng keyboard"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Pinapayagan ang app na baguhin ang layout ng keyboard. Hindi kailanman dapat na kailanganin para sa mga normal na app."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"magpadala ng mga signal ng Linux sa apps"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Pinapayagan ang app na hilinging maipadala ang ibinigay na signal sa lahat ng nagpapatuloy na proseso."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"palaging patakbuhin ang app"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"I-type ang kinakailangang PIN:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"Magpasok ng character"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Hindi kilalang app"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Nagpapadala ng mga SMS na mensahe"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Ipinapadala ang malaking bilang ng mga mensaheng SMS. Pindutin ang OK upang magpatuloy, o Kanselahin upang ihinto ang pagpapadala."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Kanselahin"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"Naalis ang SIM card"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"Hindi magiging available ang mobile network hanggang mag-restart ka gamit ang isang may-bisang SIM card"</string>
     <string name="sim_done_button" msgid="827949989369963775">"Tapos na"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Pindutin upang huwag paganahin ang pag-debug ng USB."</string>
     <string name="select_input_method" msgid="4653387336791222978">"Pumili ng pamamaraan ng pag-input"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"I-set up paraan ng pag-input"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"Aktwal na keyboard"</string>
+    <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"mga kandidato"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Bawasan ang araw"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Dagdagdan ang taon"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Bawasan ang taon"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"nilagyan ng check"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"hindi nilagyan ng check"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"pinili"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"Hindi pinili"</string>
-    <string name="switch_on" msgid="551417728476977311">"naka-on"</string>
-    <string name="switch_off" msgid="7249798614327155088">"naka-off"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"pinindot"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"hindi pinindot"</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>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 959d8bd..8abf38d 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -286,10 +286,8 @@
     <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>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Uygulamaya, istediği zaman fare veya izleme yüzeyi işaretçi hızını değiştirme izni verir. Normal uygulamalar için gerekli değildir."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"klavye düzenini değiştir"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Uygulamaya klavye düzenini değiştirme izni verir. Normal uygulamalar için hiçbir zaman gerekmez."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"uygulamalara Linux sinyalleri gönder"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Uygulamaya, sağlanan sinyalin tüm kalıcı işlemlere gönderilmesini isteme izni verir."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"uygulamayı her zaman çalıştır"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Gerekli PIN\'i yazın:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"Karakter ekle"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Bilinmeyen uygulama"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS mesajları gönderiliyor"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Çok sayıda SMS mesajı gönderiliyor. Devam etmek için Tamam\'a, göndermeyi durdurmak için İptal\'e dokunun."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"Tamam"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"İptal"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"SIM kart çıkarıldı"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"Geçerli bir SIM kart yerleştirilmiş olarak yeniden başlatana kadar mobil ağ kullanılamayacak."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Tamamlandı"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"USB hata ayıklama özelliğini devre dışı bırakmak için dokunun."</string>
     <string name="select_input_method" msgid="4653387336791222978">"Giriş yöntemini seçin"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"Giriş yöntemlerini ayarla"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"Fiziksel klavye"</string>
+    <string name="hardware" msgid="7517821086888990278">"Donanım"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"adaylar"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Günü azalt"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Yılı artır"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Yılı azalt"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"işaretli"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"işaretlenmedi"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"seçili"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"seçili değil"</string>
-    <string name="switch_on" msgid="551417728476977311">"açık"</string>
-    <string name="switch_off" msgid="7249798614327155088">"kapalı"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"basıldı"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"basılmadı"</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>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index f9d372e..5504176 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1009,11 +1009,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Введіть потрібний PIN-код:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-код:"</string>
     <string name="select_character" msgid="3365550120617701745">"Вставл-ня символу"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Невідома програма"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Надсил. SMS повідомлень"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Надсилається велика кількість SMS повідомлень. Торкніться \"OK\", щоб продовжити, або \"Скасувати\", щоб припинити надсилання."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Скасувати"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"SIM-карту вилучено"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"Мобільна мережа буде недоступна, поки ви не здійсните перезапуск, вставивши дійсну SIM-карту."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Готово"</string>
@@ -1193,14 +1209,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"На день назад"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"На рік уперед"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"На рік назад"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"перевірено"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"не перевірено"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"вибрано"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"не вибрано"</string>
-    <string name="switch_on" msgid="551417728476977311">"увімк."</string>
-    <string name="switch_off" msgid="7249798614327155088">"вимкн."</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"натиснуто"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"не натиснуто"</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>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index dde1ad4..96e97f6 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -286,10 +286,8 @@
     <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>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Cho phép ứng dụng thay đổi tốc độ của chuột hoặc con trỏ trên ô di chuột bất kỳ lúc nào. Không cần thiết cho các ứng dụng thông thường."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"thay đổi bố cục bàn phím"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Cho phép các ứng dụng thay đổi bố cục bàn phím. Không bao giờ cần thiết cho các ứng dụng bình thường."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"gửi tín hiệu Linux đến ứng dụng"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Cho phép ứng dụng yêu cầu tín hiệu đã cung cấp được gửi đến tất cả các quá trình liên tục."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"đặt ứng dụng luôn chạy"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Nhập PIN bắt buộc:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Mã PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"Chèn ký tự"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Ứng dụng không xác định"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Đang gửi tin nhắn SMS"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Một lượng lớn các tin nhắn SMS đang được gửi. Chạm OK để tiếp tục hoặc Hủy để ngừng gửi."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Hủy"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"Đã xóa thẻ SIM"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"Mạng di động sẽ không khả dụng cho đến khi bạn khởi động lại với thẻ SIM hợp lệ được lắp."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Xong"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Chạm để vô hiệu hóa gỡ lỗi USB."</string>
     <string name="select_input_method" msgid="4653387336791222978">"Chọn phương thức nhập"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"Thiết lập phương thức nhập"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"Bàn phím thực"</string>
+    <string name="hardware" msgid="7517821086888990278">"Phần cứng"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"ứng viên"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Giảm ngày"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Tăng năm"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Giảm năm"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"đã kiểm tra"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"chưa chọn"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"đã chọn"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"chưa được chọn"</string>
-    <string name="switch_on" msgid="551417728476977311">"bật"</string>
-    <string name="switch_off" msgid="7249798614327155088">"tắt"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"đã bấm"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"chưa được bấm"</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>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 0c338bb..08a15e4 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -286,10 +286,8 @@
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"允许应用随时更改屏幕的旋转状态。普通应用绝不需要此权限。"</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"更改指针速度"</string>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"允许应用随时更改鼠标或触控板指针速度。普通应用绝不需要此权限。"</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"更改键盘布局"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"允许应用更改键盘布局。普通应用绝不需要此权限。"</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"向应用发送 Linux 信号"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"允许应用请求将提供的信号发送给所有持续的进程。"</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"让应用始终运行"</string>
@@ -1009,11 +1007,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"键入所需的 PIN:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"插入字符"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"未知应用"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"正在发送短信"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"正在发送大量短信。触摸“确定”继续,或触摸“取消”停止发送。"</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"确定"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"取消"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"已移除 SIM 卡"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"移动网络不可用。请插入有效的 SIM 卡并重新启动。"</string>
     <string name="sim_done_button" msgid="827949989369963775">"完成"</string>
@@ -1063,10 +1077,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"触摸以停用 USB 调试。"</string>
     <string name="select_input_method" msgid="4653387336791222978">"选择输入法"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"设置输入法"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"物理键盘"</string>
+    <string name="hardware" msgid="7517821086888990278">"硬件"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"候选"</u></string>
@@ -1193,14 +1205,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"减小日期值"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"增大年份值"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"减小年份值"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"已选中"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"未选中"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"已选择"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"未选择"</string>
-    <string name="switch_on" msgid="551417728476977311">"已打开"</string>
-    <string name="switch_off" msgid="7249798614327155088">"已关闭"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"已按下"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"未按下"</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>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index c36b1b5..0468534 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1009,11 +1009,27 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"請輸入必要的 PIN:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"插入字元"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"不明的應用程式"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"傳送 SMS 簡訊"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"即將傳送大量的 SMS 簡訊。輕觸 [確定] 可繼續傳送,或輕觸 [取消] 停止傳送。"</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"確定"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"取消"</string>
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+    <skip />
     <string name="sim_removed_title" msgid="6227712319223226185">"SIM 卡已移除"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"您必須先插入有效的 SIM 卡再重新啟動手機,才能使用行動網路。"</string>
     <string name="sim_done_button" msgid="827949989369963775">"完成"</string>
@@ -1193,14 +1209,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"減少日數"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"增加年數"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"減少年數"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"已勾選"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"尚未勾選"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"已選取"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"未選取"</string>
-    <string name="switch_on" msgid="551417728476977311">"開啟"</string>
-    <string name="switch_off" msgid="7249798614327155088">"關閉"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"已按下"</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"未按下"</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>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 3b3b1e1..c910d4a 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -286,10 +286,8 @@
     <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>
     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Ivumela insiza ukuthi iguqule ijubane legundane noma lendawo yokukhomba ngomunwe. Akufanele kudingakele izinsiza ezijwayelekile."</string>
-    <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
-    <skip />
-    <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
-    <skip />
+    <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"shintsha isendlalelo sekhibhodi"</string>
+    <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Ivumela uhlelo lokusebenza ukushintsha isendlalelo sekhibhodi. Kufanele ingadingi izinhlelo zokusebenzia ezivamile."</string>
     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"Thumela imifanekiso ye-Linu ezinsizeni"</string>
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Ivumela insiza ukuthi icele ukuthi isiginali ethunyelwe idluliselwe kuzo zonke izinqubeko ezisalelayo."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"yenza insiza ukuthi ihlale isebenza"</string>
@@ -1009,11 +1007,17 @@
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Faka i-PIN edingekayo:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
     <string name="select_character" msgid="3365550120617701745">"Faka uhlamvu"</string>
-    <string name="sms_control_default_app_name" msgid="3058577482636640465">"insiza engaziwa"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Ithumela imiyalezo ye-SMS"</string>
-    <string name="sms_control_message" msgid="4073755190243093924">"Inani eliphezulu lwama-SMS liyathunyelwa. Khetha \"KULUNGILE\" ukuqhubeka, noma \"Khansela\" ukumisa ukuthumela."</string>
-    <string name="sms_control_yes" msgid="2532062172402615953">"KULUNGILE"</string>
-    <string name="sms_control_no" msgid="1715320703137199869">"Khansela"</string>
+    <string name="sms_control_message" msgid="3867899169651496433">"I-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ithumela inombolo enkulu yemilayezo ye-SMS. Ufuna ukuvumela lolu hlelo lokusebenza ukuqhubeka ukuthumela imilayezo?"</string>
+    <string name="sms_control_yes" msgid="3663725993855816807">"Vumela"</string>
+    <string name="sms_control_no" msgid="625438561395534982">"Nqaba"</string>
+    <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Thumela ikhodi efushane?"</string>
+    <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Ukuthumela i-SMS ye-premium?"</string>
+    <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"I-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ithanda ukuthumela umlayezo wombhalo ku-&lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;, okubonakala sengathi ikhodi ye-SMS efushane.&lt;p&gt;Ukuthumela umlayezo wombhalo kungabangela i-akhawunti yeselula yakho ukuthi ikhokheliswe amasevisi e-premium.&lt;p&gt;Ufuna ukuvumela uhlelo lokusebenza ukuthumela umlayezo?"</string>
+    <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"I-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ithanda ukuthumela umlayezo wombhalo ku-&lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;, okuyikhodi efushane ye-SMS ye-premium.&lt;p&gt;&lt;b&gt;Ukuthumela umlayezo kule ndawo kuzobangela i-akhawunti yeselula yakho ukuthi ikhokheliswe amasevisi e-premium.&lt;/b&gt;&lt;p&gt;Ufuna ukuvumela lolu hlelo lokusebenza ukuthumela umlayezo?"</string>
+    <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Thumela umlayezo?"</string>
+    <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Ungathumeli"</string>
+    <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Bika uhlelo lokusebenza olungalungile"</string>
     <string name="sim_removed_title" msgid="6227712319223226185">"Ikhadi le-SIM likhishiwe"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"Inethiwekhi yeselula ngeke itholakale kuwena kuze kube uqala kabusha ufake ikhadi le-SIM elifanele."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Kwenziwe"</string>
@@ -1063,10 +1067,8 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Thinta ukwenza ukuthi ukudibhaga kwe-USB kungasebenzi."</string>
     <string name="select_input_method" msgid="4653387336791222978">"Khetha indlela yokufaka"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"Izilungiselelo zezindlela zokufakwayo"</string>
-    <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
-    <skip />
-    <!-- no translation found for hardware (7517821086888990278) -->
-    <skip />
+    <string name="use_physical_keyboard" msgid="6203112478095117625">"Ukwakheka kwekhibhodi"</string>
+    <string name="hardware" msgid="7517821086888990278">"I-Hardware"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"abahlanganyeli"</u></string>
@@ -1193,14 +1195,6 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Yehlisa usuku"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Khulisa unyaka"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Yehlisa unyaka"</string>
-    <string name="checkbox_checked" msgid="7222044992652711167">"kuhloliwe"</string>
-    <string name="checkbox_not_checked" msgid="5174639551134444056">"akuhloliwe"</string>
-    <string name="radiobutton_selected" msgid="8603599808486581511">"Okukhethiwe"</string>
-    <string name="radiobutton_not_selected" msgid="2908760184307722393">"akukhethiwe"</string>
-    <string name="switch_on" msgid="551417728476977311">"vuliwe"</string>
-    <string name="switch_off" msgid="7249798614327155088">"valiwe"</string>
-    <string name="togglebutton_pressed" msgid="4180411746647422233">"kucindezelwe."</string>
-    <string name="togglebutton_not_pressed" msgid="4495147725636134425">"akucindezelwe."</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>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index aabe407..6f489d4 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -835,6 +835,10 @@
 
         <!-- Reference to the Pointer style -->
         <attr name="pointerStyle" format="reference" />
+
+        <!-- The drawable for accessibility focused views. -->
+        <attr name="accessibilityFocusedDrawable" format="reference" />
+
     </declare-styleable>
 
     <!-- **************************************************************** -->
@@ -2123,6 +2127,20 @@
                 layoutDirection is LTR, and ALIGN_LEFT otherwise -->
             <enum name="viewEnd" value="6" />
         </attr>
+
+        <!-- Controls how 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. Note: While not recommended, an accessibility service may
+             decide to ignore this attribute and operate on all views in the view tree. -->
+        <attr name="importantForAccessibility" format="integer">
+            <!-- The system determines whether the view is important for accessibility (recommended). -->
+            <enum name="auto" value="0" />
+            <!-- The view is important for accessibility. -->
+            <enum name="yes" value="1" />
+            <!-- The view is not important for accessibility. -->
+            <enum name="no" value="2" />
+        </attr>
+
     </declare-styleable>
 
     <!-- Attributes that can be used with a {@link android.view.ViewGroup} or any
@@ -2349,8 +2367,6 @@
         <!-- Component name of an activity that allows the user to modify
              the settings for this service. -->
         <attr name="settingsActivity"/>
-        <!-- Set true when the spell checker supports sentence level spell checking. -->
-        <attr name="supportsSentenceSpellCheck" format="boolean" />
     </declare-styleable>
 
     <!-- This is the subtype of the spell checker. Subtype can describe locales (e.g. en_US, fr_FR...) -->
@@ -2445,6 +2461,8 @@
         <attr name="accessibilityFlags">
             <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#DEFAULT} -->
             <flag name="flagDefault" value="0x00000001" />
+            <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#INCLUDE_NOT_IMPORTANT_VIEWS} -->
+            <flag name="flagIncludeNotImportantViews" value="0x00000002" />
         </attr>
         <!-- Component name of an activity that allows the user to modify
              the settings for this service. This setting cannot be changed at runtime. -->
@@ -4317,6 +4335,7 @@
          <li>"state_hovered"
          <li>"state_drag_can_accept"
          <li>"state_drag_hovered"
+         <li>"state_accessibility_focused"
          </ul>  -->
     <declare-styleable name="DrawableStates">
         <!-- State value for {@link android.graphics.drawable.StateListDrawable StateListDrawable},
@@ -4377,6 +4396,9 @@
              indicating that a drag operation (for which the Drawable's view is a valid recipient)
              is currently positioned over the Drawable. -->
         <attr name="state_drag_hovered" format="boolean" />
+        <!-- State for {@link android.graphics.drawable.StateListDrawable StateListDrawable}
+             indicating that a View has accessibility focus. -->
+        <attr name="state_accessibility_focused" format="boolean" />
     </declare-styleable>
     <declare-styleable name="ViewDrawableStates">
         <attr name="state_pressed" />
@@ -5358,6 +5380,21 @@
     </declare-styleable>
 
     <!-- =============================== -->
+    <!-- SizeAdaptiveLayout class attributes -->
+    <!-- =============================== -->
+    <eat-comment />
+    <declare-styleable name="SizeAdaptiveLayout_Layout">
+      <!-- The maximum valid height for this item. -->
+      <attr name="layout_maxHeight" format="dimension">
+        <!-- Indicates that the view may be resized arbitrarily large. -->
+        <enum name="unbounded" value="-1" />
+      </attr>
+      <!-- The minimum valid height for this item. -->
+      <attr name="layout_minHeight" format="dimension" />
+    </declare-styleable>
+    <declare-styleable name="SizeAdaptiveLayout" />
+
+    <!-- =============================== -->
     <!-- LockPatternView class attributes -->
     <!-- =============================== -->
     <eat-comment />
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 0bed2fb..6266726 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -231,6 +231,7 @@
   <java-symbol type="attr" name="windowFixedWidthMinor" />
   <java-symbol type="attr" name="windowFixedHeightMajor" />
   <java-symbol type="attr" name="windowFixedHeightMinor" />
+  <java-symbol type="attr" name="accessibilityFocusedDrawable"/>
 
   <java-symbol type="bool" name="action_bar_embed_tabs" />
   <java-symbol type="bool" name="action_bar_expanded_action_views_exclusive" />
@@ -1109,6 +1110,7 @@
   <java-symbol type="xml" name="time_zones_by_country" />
   <java-symbol type="xml" name="sms_short_codes" />
 
+  <java-symbol type="raw" name="accessibility_gestures" />
   <java-symbol type="raw" name="incognito_mode_start_page" />
   <java-symbol type="raw" name="loaderror" />
   <java-symbol type="raw" name="nodomain" />
@@ -3589,7 +3591,9 @@
   <public type="attr" name="layout_marginEnd"/>
   <public type="attr" name="kcm"/>
 
+
   <public type="attr" name="parentActivityName" />
 
-  <public type="attr" name="supportsSentenceSpellCheck" />
+  <public type="attr" name="importantForAccessibility"/>
+
 </resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 7e06e24..71738ad 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -366,6 +366,9 @@
 
         <!-- Pointer style -->
         <item name="pointerStyle">@android:style/Pointer</item>
+
+        <!-- Accessibility focused drawable. -->
+        <item name="accessibilityFocusedDrawable">@android:drawable/view_accessibility_focused</item>
     </style>
 
     <!-- Variant of {@link #Theme} with no title bar -->
diff --git a/core/tests/coretests/apks/install/Android.mk b/core/tests/coretests/apks/install/Android.mk
new file mode 100644
index 0000000..b38dc20
--- /dev/null
+++ b/core/tests/coretests/apks/install/Android.mk
@@ -0,0 +1,8 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := install
+
+include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install/AndroidManifest.xml b/core/tests/coretests/apks/install/AndroidManifest.xml
new file mode 100644
index 0000000..60f1ba0
--- /dev/null
+++ b/core/tests/coretests/apks/install/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?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.frameworks.coretests.install_loc">
+
+    <application android:hasCode="false">
+    </application>
+</manifest>
diff --git a/core/tests/coretests/apks/install/res/values/strings.xml b/core/tests/coretests/apks/install/res/values/strings.xml
new file mode 100644
index 0000000..3b8b3b1
--- /dev/null
+++ b/core/tests/coretests/apks/install/res/values/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Just need this dummy file to have something to build. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string name="dummy">dummy</string>
+</resources>
diff --git a/core/tests/coretests/res/drawable/abe.jpg b/core/tests/coretests/res/drawable/abe.jpg
new file mode 100644
index 0000000..1f978a9
--- /dev/null
+++ b/core/tests/coretests/res/drawable/abe.jpg
Binary files differ
diff --git a/core/tests/coretests/res/drawable/gettysburg.png b/core/tests/coretests/res/drawable/gettysburg.png
new file mode 100644
index 0000000..7a2d596
--- /dev/null
+++ b/core/tests/coretests/res/drawable/gettysburg.png
Binary files differ
diff --git a/core/tests/coretests/res/layout/size_adaptive.xml b/core/tests/coretests/res/layout/size_adaptive.xml
new file mode 100644
index 0000000..03d0574
--- /dev/null
+++ b/core/tests/coretests/res/layout/size_adaptive.xml
@@ -0,0 +1,40 @@
+<?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.
+-->
+<com.android.internal.widget.SizeAdaptiveLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
+    android:id="@+id/multi1"
+    android:layout_width="match_parent"
+    android:layout_height="64dp" >
+
+    <include
+        android:id="@+id/one_u"
+        layout="@layout/size_adaptive_one_u"
+        android:layout_width="fill_parent"
+        android:layout_height="64dp"
+        internal:layout_minHeight="64dp"
+        internal:layout_maxHeight="64dp"
+        />
+
+    <include
+        android:id="@+id/four_u"
+        layout="@layout/size_adaptive_four_u"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        internal:layout_minHeight="65dp"
+        internal:layout_maxHeight="unbounded"/>
+
+</com.android.internal.widget.SizeAdaptiveLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_color.xml b/core/tests/coretests/res/layout/size_adaptive_color.xml
new file mode 100644
index 0000000..cdb7a59
--- /dev/null
+++ b/core/tests/coretests/res/layout/size_adaptive_color.xml
@@ -0,0 +1,41 @@
+<?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.
+-->
+<com.android.internal.widget.SizeAdaptiveLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
+    android:background="#ffffff"
+    android:id="@+id/multi1"
+    android:layout_width="match_parent"
+    android:layout_height="64dp" >
+
+    <include
+        android:id="@+id/one_u"
+        layout="@layout/size_adaptive_one_u"
+        android:layout_width="fill_parent"
+        android:layout_height="64dp"
+        internal:layout_minHeight="64dp"
+        internal:layout_maxHeight="64dp"
+        />
+
+    <include
+        android:id="@+id/four_u"
+        layout="@layout/size_adaptive_four_u"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        internal:layout_minHeight="65dp"
+        internal:layout_maxHeight="unbounded"/>
+
+</com.android.internal.widget.SizeAdaptiveLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_four_u.xml b/core/tests/coretests/res/layout/size_adaptive_four_u.xml
new file mode 100644
index 0000000..232b921
--- /dev/null
+++ b/core/tests/coretests/res/layout/size_adaptive_four_u.xml
@@ -0,0 +1,68 @@
+<?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.
+-->
+<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/gridLayout4"
+    android:layout_width="match_parent"
+    android:layout_height="256dp"
+    android:background="#000000"
+    android:columnCount="2"
+    android:padding="1dp" >
+
+    <ImageView
+        android:id="@+id/actor"
+        android:layout_width="62dp"
+        android:layout_height="62dp"
+        android:layout_row="0"
+        android:layout_column="0"
+        android:layout_rowSpan="2"
+        android:contentDescription="@string/actor"
+        android:src="@drawable/abe" />
+
+    <TextView
+        android:layout_width="0dp"
+        android:id="@+id/name"
+        android:layout_row="0"
+        android:layout_column="1"
+        android:layout_gravity="fill_horizontal"
+        android:padding="3dp"
+        android:text="@string/actor"
+        android:textColor="#ffffff"
+        android:textStyle="bold" />
+
+    <ImageView
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_row="1"
+        android:layout_column="1"
+        android:layout_gravity="fill_horizontal"
+        android:padding="5dp"
+        android:adjustViewBounds="true"
+        android:background="#555555"
+        android:scaleType="centerCrop"
+        android:src="@drawable/gettysburg"
+        android:contentDescription="@string/caption" />
+
+    <TextView
+        android:layout_width="0dp"
+        android:id="@+id/note"
+        android:layout_row="2"
+        android:layout_column="1"
+        android:layout_gravity="fill_horizontal"
+        android:padding="3dp"
+        android:singleLine="true"
+        android:text="@string/first"
+        android:textColor="#ffffff" />
+</GridLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_four_u_text.xml b/core/tests/coretests/res/layout/size_adaptive_four_u_text.xml
new file mode 100644
index 0000000..93a10de
--- /dev/null
+++ b/core/tests/coretests/res/layout/size_adaptive_four_u_text.xml
@@ -0,0 +1,59 @@
+<?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.
+-->
+<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/gridLayout4"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="#000000"
+    android:columnCount="2"
+    android:padding="1dp"
+    android:orientation="horizontal" >
+
+    <ImageView
+        android:id="@+id/actor"
+        android:layout_width="62dp"
+        android:layout_height="62dp"
+        android:layout_row="0"
+        android:layout_column="0"
+        android:layout_rowSpan="2"
+        android:contentDescription="@string/actor"
+        android:src="@drawable/abe" />
+
+    <TextView
+        android:layout_width="0dp"
+        android:id="@+id/name"
+        android:layout_row="0"
+        android:layout_column="1"
+        android:layout_gravity="fill_horizontal"
+        android:padding="3dp"
+        android:text="@string/actor"
+        android:textColor="#ffffff"
+        android:textStyle="bold" />
+
+    <TextView
+        android:id="@+id/note"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_column="1"
+        android:layout_gravity="fill_horizontal"
+        android:layout_marginTop="5dp"
+        android:layout_row="1"
+        android:padding="3dp"
+        android:singleLine="false"
+        android:text="@string/first"
+        android:textColor="#ffffff" />
+
+    </GridLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_gappy.xml b/core/tests/coretests/res/layout/size_adaptive_gappy.xml
new file mode 100644
index 0000000..d5e3b41
--- /dev/null
+++ b/core/tests/coretests/res/layout/size_adaptive_gappy.xml
@@ -0,0 +1,40 @@
+<?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.
+-->
+<com.android.internal.widget.SizeAdaptiveLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
+    android:id="@+id/multi_with_gap"
+    android:layout_width="match_parent"
+    android:layout_height="64dp" >
+
+    <include
+        android:id="@+id/one_u"
+        layout="@layout/size_adaptive_one_u"
+        android:layout_width="fill_parent"
+        android:layout_height="64dp"
+        internal:layout_minHeight="64dp"
+        internal:layout_maxHeight="64dp"
+        />
+
+    <include
+        android:id="@+id/four_u"
+        layout="@layout/size_adaptive_four_u"
+        android:layout_width="fill_parent"
+        android:layout_height="256dp"
+        internal:layout_minHeight="128dp"
+        internal:layout_maxHeight="unbounded"/>
+
+</com.android.internal.widget.SizeAdaptiveLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_large_only.xml b/core/tests/coretests/res/layout/size_adaptive_large_only.xml
new file mode 100644
index 0000000..cf58265
--- /dev/null
+++ b/core/tests/coretests/res/layout/size_adaptive_large_only.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+<com.android.internal.widget.SizeAdaptiveLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
+    android:id="@+id/large_only_multi"
+    android:layout_width="match_parent"
+    android:layout_height="64dp" >
+
+    <include
+        android:id="@+id/four_u"
+        layout="@layout/size_adaptive_four_u"
+        android:layout_width="fill_parent"
+        android:layout_height="256dp"
+        internal:layout_minHeight="65dp"
+        internal:layout_maxHeight="unbounded"/>
+
+</com.android.internal.widget.SizeAdaptiveLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_one_u.xml b/core/tests/coretests/res/layout/size_adaptive_one_u.xml
new file mode 100644
index 0000000..b6fe4a0
--- /dev/null
+++ b/core/tests/coretests/res/layout/size_adaptive_one_u.xml
@@ -0,0 +1,66 @@
+<?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.
+-->
+<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/gridLayout1"
+    android:layout_width="match_parent"
+    android:layout_height="64dp"
+    android:background="#000000"
+    android:columnCount="3"
+    android:padding="1dp"
+    android:rowCount="2" >
+
+    <ImageView
+        android:id="@+id/actor"
+        android:layout_width="62dp"
+        android:layout_height="62dp"
+        android:layout_column="0"
+        android:layout_row="0"
+        android:layout_rowSpan="2"
+        android:contentDescription="@string/actor"
+        android:src="@drawable/abe" />
+
+    <TextView
+        android:id="@+id/name"
+        android:layout_gravity="fill"
+        android:padding="3dp"
+        android:text="@string/actor"
+        android:textColor="#ffffff"
+        android:textStyle="bold" />
+
+    <ImageView
+        android:layout_width="62dp"
+        android:layout_height="62dp"
+        android:layout_gravity="fill_vertical"
+        android:layout_rowSpan="2"
+        android:adjustViewBounds="true"
+        android:background="#555555"
+        android:padding="2dp"
+        android:scaleType="fitXY"
+        android:src="@drawable/gettysburg"
+        android:contentDescription="@string/caption" />
+
+    <TextView
+        android:id="@+id/note"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:layout_gravity="fill"
+        android:layout_marginTop="5dp"
+        android:padding="3dp"
+        android:singleLine="true"
+        android:text="@string/first"
+        android:textColor="#ffffff" />
+
+</GridLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_one_u_text.xml b/core/tests/coretests/res/layout/size_adaptive_one_u_text.xml
new file mode 100644
index 0000000..df54eb6
--- /dev/null
+++ b/core/tests/coretests/res/layout/size_adaptive_one_u_text.xml
@@ -0,0 +1,54 @@
+<?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.
+-->
+<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/gridLayout1"
+    android:layout_width="match_parent"
+    android:layout_height="64dp"
+    android:background="#000000"
+    android:columnCount="2"
+    android:padding="1dp"
+    android:rowCount="2" >
+
+    <ImageView
+        android:id="@+id/actor"
+        android:layout_width="62dp"
+        android:layout_height="62dp"
+        android:layout_column="0"
+        android:layout_row="0"
+        android:layout_rowSpan="2"
+        android:contentDescription="@string/actor"
+        android:src="@drawable/abe" />
+
+    <TextView
+        android:id="@+id/name"
+        android:layout_gravity="fill"
+        android:padding="3dp"
+        android:text="@string/actor"
+        android:textColor="#ffffff"
+        android:textStyle="bold" />
+
+    <TextView
+        android:id="@+id/note"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:layout_gravity="fill"
+        android:layout_marginTop="5dp"
+        android:padding="3dp"
+        android:singleLine="true"
+        android:text="@string/first"
+        android:textColor="#ffffff" />
+
+</GridLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_overlapping.xml b/core/tests/coretests/res/layout/size_adaptive_overlapping.xml
new file mode 100644
index 0000000..4abe8b0
--- /dev/null
+++ b/core/tests/coretests/res/layout/size_adaptive_overlapping.xml
@@ -0,0 +1,40 @@
+<?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.
+-->
+<com.android.internal.widget.SizeAdaptiveLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
+    android:id="@+id/multi_with_overlap"
+    android:layout_width="match_parent"
+    android:layout_height="64dp" >
+
+    <include
+        android:id="@+id/one_u"
+        layout="@layout/size_adaptive_one_u"
+        android:layout_width="fill_parent"
+        android:layout_height="64dp"
+        internal:layout_minHeight="64dp"
+        internal:layout_maxHeight="64dp"
+        />
+
+    <include
+        android:id="@+id/four_u"
+        layout="@layout/size_adaptive_four_u"
+        android:layout_width="fill_parent"
+        android:layout_height="256dp"
+        internal:layout_minHeight="64dp"
+        internal:layout_maxHeight="256dp"/>
+
+</com.android.internal.widget.SizeAdaptiveLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_singleton.xml b/core/tests/coretests/res/layout/size_adaptive_singleton.xml
new file mode 100644
index 0000000..eba387f
--- /dev/null
+++ b/core/tests/coretests/res/layout/size_adaptive_singleton.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+<com.android.internal.widget.SizeAdaptiveLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="64dp" >
+
+    <include
+        android:id="@+id/one_u"
+        layout="@layout/size_adaptive_one_u_text"
+        android:layout_width="fill_parent"
+        android:layout_height="64dp"
+        internal:layout_minHeight="64dp"
+        internal:layout_maxHeight="64dp"
+        />
+
+</com.android.internal.widget.SizeAdaptiveLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_text.xml b/core/tests/coretests/res/layout/size_adaptive_text.xml
new file mode 100644
index 0000000..a9f0ba9
--- /dev/null
+++ b/core/tests/coretests/res/layout/size_adaptive_text.xml
@@ -0,0 +1,40 @@
+<?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.
+-->
+<com.android.internal.widget.SizeAdaptiveLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
+    android:id="@+id/multi1"
+    android:layout_width="match_parent"
+    android:layout_height="64dp" >
+
+    <include
+        android:id="@+id/one_u"
+        layout="@layout/size_adaptive_one_u_text"
+        android:layout_width="fill_parent"
+        android:layout_height="64dp"
+        internal:layout_minHeight="64dp"
+        internal:layout_maxHeight="64dp"
+        />
+
+    <include
+        android:id="@+id/four_u"
+        layout="@layout/size_adaptive_four_u_text"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        internal:layout_minHeight="65dp"
+        internal:layout_maxHeight="unbounded"/>
+
+</com.android.internal.widget.SizeAdaptiveLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_three_way.xml b/core/tests/coretests/res/layout/size_adaptive_three_way.xml
new file mode 100644
index 0000000..1eb5396
--- /dev/null
+++ b/core/tests/coretests/res/layout/size_adaptive_three_way.xml
@@ -0,0 +1,48 @@
+<?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.
+-->
+<com.android.internal.widget.SizeAdaptiveLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
+    android:id="@+id/three_way_multi"
+    android:layout_width="match_parent"
+    android:layout_height="64dp" >
+
+    <include
+        android:id="@+id/one_u"
+        layout="@layout/size_adaptive_one_u"
+        android:layout_width="fill_parent"
+        android:layout_height="64dp"
+        internal:layout_minHeight="64dp"
+        internal:layout_maxHeight="64dp"
+        />
+
+    <include
+        android:id="@+id/two_u"
+        layout="@layout/size_adaptive_four_u"
+        android:layout_width="fill_parent"
+        android:layout_height="128dp"
+        internal:layout_minHeight="65dp"
+        internal:layout_maxHeight="128dp"/>
+
+    <include
+        android:id="@+id/four_u"
+        layout="@layout/size_adaptive_four_u"
+        android:layout_width="fill_parent"
+        android:layout_height="256dp"
+        internal:layout_minHeight="129dp"
+        internal:layout_maxHeight="unbounded"/>
+
+</com.android.internal.widget.SizeAdaptiveLayout>
diff --git a/core/tests/coretests/res/raw/install b/core/tests/coretests/res/raw/install
deleted file mode 100644
index 06981f4..0000000
--- a/core/tests/coretests/res/raw/install
+++ /dev/null
Binary files differ
diff --git a/core/tests/coretests/res/values/strings.xml b/core/tests/coretests/res/values/strings.xml
index 71f3520..ce0d9a2 100644
--- a/core/tests/coretests/res/values/strings.xml
+++ b/core/tests/coretests/res/values/strings.xml
@@ -131,4 +131,8 @@
 
     <string name="textview_hebrew_text">&#x05DD;&#x05DE;ab?!</string>
 
+    <!-- SizeAdaptiveLayout -->
+    <string name="first">Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal.</string>
+    <string name="actor">Abe Lincoln</string>
+    <string name="caption">Lincoln adressing the crowd at Gettysburgh</string>
 </resources>
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 9575ced..580b4da 100755
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -170,11 +170,10 @@
         return ipm;
     }
 
-    public boolean invokeInstallPackage(Uri packageURI, int flags, GenericReceiver receiver) {
+    public void invokeInstallPackage(Uri packageURI, int flags, GenericReceiver receiver,
+            boolean shouldSucceed) {
         PackageInstallObserver observer = new PackageInstallObserver();
-        final boolean received = false;
         mContext.registerReceiver(receiver, receiver.filter);
-        final boolean DEBUG = true;
         try {
             // Wait on observer
             synchronized(observer) {
@@ -192,10 +191,24 @@
                     if(!observer.isDone()) {
                         fail("Timed out waiting for packageInstalled callback");
                     }
-                    if (observer.returnCode != PackageManager.INSTALL_SUCCEEDED) {
-                        Log.i(TAG, "Failed to install with error code = " + observer.returnCode);
-                        return false;
+
+                    if (shouldSucceed) {
+                        if (observer.returnCode != PackageManager.INSTALL_SUCCEEDED) {
+                            fail("Package installation should have succeeded, but got code "
+                                    + observer.returnCode);
+                        }
+                    } else {
+                        if (observer.returnCode == PackageManager.INSTALL_SUCCEEDED) {
+                            fail("Package installation should fail");
+                        }
+
+                        /*
+                         * We'll never expect get a notification since we
+                         * shouldn't succeed.
+                         */
+                        return;
                     }
+
                     // Verify we received the broadcast
                     waitTime = 0;
                     while((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
@@ -209,7 +222,6 @@
                     if(!receiver.isDone()) {
                         fail("Timed out waiting for PACKAGE_ADDED notification");
                     }
-                    return receiver.received;
                 }
             }
         } finally {
@@ -588,7 +600,7 @@
                 }
             } else {
                 InstallReceiver receiver = new InstallReceiver(pkg.packageName);
-                assertTrue(invokeInstallPackage(packageURI, flags, receiver));
+                invokeInstallPackage(packageURI, flags, receiver, true);
                 // Verify installed information
                 assertInstall(pkg, flags, expInstallLocation);
             }
@@ -705,13 +717,9 @@
             receiver = new InstallReceiver(ip.pkg.packageName);
         }
         try {
-            try {
-                assertEquals(invokeInstallPackage(ip.packageURI, flags, receiver), replace);
-                if (replace) {
-                    assertInstall(ip.pkg, flags, ip.pkg.installLocation);
-                }
-            } catch (Exception e) {
-                failStr("Failed with exception : " + e);
+            invokeInstallPackage(ip.packageURI, flags, receiver, replace);
+            if (replace) {
+                assertInstall(ip.pkg, flags, ip.pkg.installLocation);
             }
         } finally {
             cleanUpInstall(ip);
@@ -1244,7 +1252,7 @@
         GenericReceiver receiver = new ReplaceReceiver(ip.pkg.packageName);
         int replaceFlags = rFlags | PackageManager.INSTALL_REPLACE_EXISTING;
         try {
-            assertEquals(invokeInstallPackage(ip.packageURI, replaceFlags, receiver), true);
+            invokeInstallPackage(ip.packageURI, replaceFlags, receiver, true);
             assertInstall(ip.pkg, rFlags, ip.pkg.installLocation);
         } catch (Exception e) {
             failStr("Failed with exception : " + e);
@@ -1271,7 +1279,7 @@
         GenericReceiver receiver = new ReplaceReceiver(ip.pkg.packageName);
         int replaceFlags = rFlags | PackageManager.INSTALL_REPLACE_EXISTING;
         try {
-            assertEquals(invokeInstallPackage(ip.packageURI, replaceFlags, receiver), true);
+            invokeInstallPackage(ip.packageURI, replaceFlags, receiver, true);
             assertInstall(ip.pkg, iFlags, ip.pkg.installLocation);
         } catch (Exception e) {
             failStr("Failed with exception : " + e);
diff --git a/core/tests/coretests/src/android/widget/focus/ListOfButtonsTest.java b/core/tests/coretests/src/android/widget/focus/ListOfButtonsTest.java
index 3dba4e5..1968a32 100644
--- a/core/tests/coretests/src/android/widget/focus/ListOfButtonsTest.java
+++ b/core/tests/coretests/src/android/widget/focus/ListOfButtonsTest.java
@@ -19,7 +19,7 @@
 import android.widget.focus.ListOfButtons;
 import com.android.frameworks.coretests.R;
 
-import android.test.ActivityInstrumentationTestCase;
+import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.widget.ListAdapter;
 import android.widget.Button;
@@ -31,7 +31,7 @@
  * Tests that focus works as expected when navigating into and out of
  * a {@link ListView} that has buttons in it.
  */
-public class ListOfButtonsTest extends ActivityInstrumentationTestCase<ListOfButtons> {
+public class ListOfButtonsTest extends ActivityInstrumentationTestCase2<ListOfButtons> {
 
     private ListAdapter mListAdapter;
     private Button mButtonAtTop;
@@ -39,7 +39,7 @@
     private ListView mListView;
 
     public ListOfButtonsTest() {
-        super("com.android.frameworks.coretests", ListOfButtons.class);
+        super(ListOfButtons.class);
     }
 
     @Override
@@ -47,6 +47,7 @@
         super.setUp();
 
         ListOfButtons a = getActivity();
+        getInstrumentation().waitForIdleSync();
         mListAdapter = a.getListAdapter();
         mButtonAtTop = (Button) a.findViewById(R.id.button);
         mListView = a.getListView();
diff --git a/core/tests/coretests/src/com/android/internal/os/DebugTest.java b/core/tests/coretests/src/com/android/internal/os/DebugTest.java
new file mode 100644
index 0000000..88c7d1b
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/DebugTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.os;
+
+import android.os.Debug;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
+@SmallTest
+public class DebugTest extends TestCase {
+
+    private final static String EXPECTED_GET_CALLER =
+            "com\\.android\\.internal\\.os\\.DebugTest\\.testGetCaller:\\d\\d";
+    private final static String EXPECTED_GET_CALLERS =
+            "com\\.android\\.internal\\.os\\.DebugTest.callDepth3:\\d\\d " +
+            "com\\.android\\.internal\\.os\\.DebugTest.callDepth2:\\d\\d " +
+            "com\\.android\\.internal\\.os\\.DebugTest.callDepth1:\\d\\d ";
+
+    /**
+     * @return String consisting of the caller to this method.
+     */
+    private String callDepth0() {
+        return Debug.getCaller();
+    }
+
+    public void testGetCaller() {
+        assertTrue(callDepth0().matches(EXPECTED_GET_CALLER));
+    }
+
+    /**
+     * @return String consisting of the callers to this method.
+     */
+    private String callDepth4() {
+        return Debug.getCallers(3);
+    }
+
+    private String callDepth3() {
+        return callDepth4();
+    }
+
+    private String callDepth2() {
+        return callDepth3();
+    }
+
+    private String callDepth1() {
+        return callDepth2();
+    }
+
+    public void testGetCallers() {
+        assertTrue(callDepth1().matches(EXPECTED_GET_CALLERS));
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/widget/SizeAdaptiveLayoutTest.java b/core/tests/coretests/src/com/android/internal/widget/SizeAdaptiveLayoutTest.java
new file mode 100644
index 0000000..fc83e4a
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/widget/SizeAdaptiveLayoutTest.java
@@ -0,0 +1,446 @@
+/*
+ * 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.widget;
+
+import com.android.frameworks.coretests.R;
+
+import android.content.Context;
+import android.graphics.drawable.ColorDrawable;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import com.android.internal.widget.SizeAdaptiveLayout;
+
+
+public class SizeAdaptiveLayoutTest extends AndroidTestCase {
+
+    private LayoutInflater mInflater;
+    private int mOneU;
+    private int mFourU;
+    private SizeAdaptiveLayout mSizeAdaptiveLayout;
+    private View mSmallView;
+    private View mMediumView;
+    private View mLargeView;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // inflate the layout
+        final Context context = getContext();
+        mInflater = LayoutInflater.from(context);
+        mOneU = 64;
+        mFourU = 4 * mOneU;
+    }
+
+    private void inflate(int resource){
+        mSizeAdaptiveLayout = (SizeAdaptiveLayout) mInflater.inflate(resource, null);
+        mSizeAdaptiveLayout.onAttachedToWindow();
+
+        mSmallView = mSizeAdaptiveLayout.findViewById(R.id.one_u);
+        mMediumView = mSizeAdaptiveLayout.findViewById(R.id.two_u);
+        mLargeView = mSizeAdaptiveLayout.findViewById(R.id.four_u);
+    }
+
+    /**
+     * The name 'test preconditions' is a convention to signal that if this
+     * test doesn't pass, the test case was not set up properly and it might
+     * explain any and all failures in other tests.  This is not guaranteed
+     * to run before other tests, as junit uses reflection to find the tests.
+     */
+    @SmallTest
+    public void testPreconditions() {
+        assertNotNull(mInflater);
+
+        inflate(R.layout.size_adaptive);
+        assertNotNull(mSizeAdaptiveLayout);
+        assertNotNull(mSmallView);
+        assertNotNull(mLargeView);
+    }
+
+    @SmallTest
+    public void testOpenLarge() {
+        inflate(R.layout.size_adaptive);
+        SizeAdaptiveLayout.LayoutParams lp =
+          (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
+        int height = (int) lp.minHeight + 10;
+
+        measureAndLayout(height);
+
+        assertEquals("4U should be visible",
+                View.VISIBLE,
+                mLargeView.getVisibility());
+        assertEquals("1U should be gone",
+                View.GONE,
+                mSmallView.getVisibility());
+    }
+
+    @SmallTest
+    public void testOpenSmall() {
+        inflate(R.layout.size_adaptive);
+        SizeAdaptiveLayout.LayoutParams lp =
+          (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams();
+        int height = (int) lp.minHeight;
+
+        measureAndLayout(height);
+
+        assertEquals("1U should be visible",
+                View.VISIBLE,
+                mSmallView.getVisibility());
+        assertEquals("4U should be gone",
+                View.GONE,
+                mLargeView.getVisibility());
+    }
+
+    @SmallTest
+    public void testOpenTooSmall() {
+        inflate(R.layout.size_adaptive);
+        SizeAdaptiveLayout.LayoutParams lp =
+          (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams();
+        int height = (int) lp.minHeight - 10;
+
+        measureAndLayout(height);
+
+        assertEquals("1U should be visible",
+                View.VISIBLE,
+                mSmallView.getVisibility());
+        assertEquals("4U should be gone",
+                View.GONE,
+                mLargeView.getVisibility());
+    }
+
+    @SmallTest
+    public void testOpenTooBig() {
+        inflate(R.layout.size_adaptive);
+        SizeAdaptiveLayout.LayoutParams lp =
+          (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
+        lp.maxHeight = 500;
+        mLargeView.setLayoutParams(lp);
+        int height = (int) (lp.minHeight + 10);
+
+        measureAndLayout(height);
+
+        assertEquals("4U should be visible",
+                View.VISIBLE,
+                mLargeView.getVisibility());
+        assertEquals("1U should be gone",
+                View.GONE,
+                mSmallView.getVisibility());
+    }
+
+    @SmallTest
+    public void testOpenWrapContent() {
+        inflate(R.layout.size_adaptive_text);
+        SizeAdaptiveLayout.LayoutParams lp =
+          (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
+        int height = (int) lp.minHeight + 10;
+
+        // manually measure it, and lay it out
+        int measureSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST);
+        mSizeAdaptiveLayout.measure(500, measureSpec);
+        assertTrue("should not be forced to 4U",
+                mSizeAdaptiveLayout.getMeasuredHeight() < mFourU);
+    }
+
+    @SmallTest
+    public void testOpenOneUOnlySmall() {
+        inflate(R.layout.size_adaptive_singleton);
+        assertNull("largeView should be NULL in the singleton layout", mLargeView);
+
+        SizeAdaptiveLayout.LayoutParams lp =
+          (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams();
+        int height = (int) lp.minHeight - 10;
+
+        measureAndLayout(height);
+
+        assertEquals("1U should be visible",
+                View.VISIBLE,
+                mSmallView.getVisibility());
+    }
+
+    @SmallTest
+    public void testOpenOneUOnlyLarge() {
+        inflate(R.layout.size_adaptive_singleton);
+        assertNull("largeView should be NULL in the singleton layout", mLargeView);
+
+        SizeAdaptiveLayout.LayoutParams lp =
+          (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams();
+        int height = (int) lp.maxHeight + 10;
+
+        measureAndLayout(height);
+
+        assertEquals("1U should be visible",
+                View.VISIBLE,
+                mSmallView.getVisibility());
+    }
+
+    @SmallTest
+    public void testOpenOneUOnlyJustRight() {
+        inflate(R.layout.size_adaptive_singleton);
+        assertNull("largeView should be NULL in the singleton layout", mLargeView);
+
+        SizeAdaptiveLayout.LayoutParams lp =
+          (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams();
+        int height = (int) lp.minHeight;
+
+        measureAndLayout(height);
+
+        assertEquals("1U should be visible",
+                View.VISIBLE,
+                mSmallView.getVisibility());
+    }
+
+    @SmallTest
+    public void testOpenFourUOnlySmall() {
+        inflate(R.layout.size_adaptive_large_only);
+        assertNull("smallView should be NULL in the singleton layout", mSmallView);
+
+        SizeAdaptiveLayout.LayoutParams lp =
+          (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
+        int height = (int) lp.minHeight - 10;
+
+        measureAndLayout(height);
+
+        assertEquals("4U should be visible",
+                View.VISIBLE,
+                mLargeView.getVisibility());
+    }
+
+    @SmallTest
+    public void testOpenFourUOnlyLarge() {
+        inflate(R.layout.size_adaptive_large_only);
+        assertNull("smallView should be NULL in the singleton layout", mSmallView);
+
+        SizeAdaptiveLayout.LayoutParams lp =
+          (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
+        int height = (int) lp.maxHeight + 10;
+
+        measureAndLayout(height);
+
+        assertEquals("4U should be visible",
+                View.VISIBLE,
+                mLargeView.getVisibility());
+    }
+
+    @SmallTest
+    public void testOpenFourUOnlyJustRight() {
+        inflate(R.layout.size_adaptive_large_only);
+        assertNull("smallView should be NULL in the singleton layout", mSmallView);
+
+        SizeAdaptiveLayout.LayoutParams lp =
+          (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
+        int height = (int) lp.minHeight;
+
+        measureAndLayout(height);
+
+        assertEquals("4U should be visible",
+                View.VISIBLE,
+                mLargeView.getVisibility());
+    }
+
+    @SmallTest
+    public void testOpenIntoAGap() {
+        inflate(R.layout.size_adaptive_gappy);
+
+        SizeAdaptiveLayout.LayoutParams smallParams =
+          (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams();
+        SizeAdaptiveLayout.LayoutParams largeParams =
+          (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
+        assertTrue("gappy layout should have a gap",
+                smallParams.maxHeight + 10 < largeParams.minHeight);
+        int height = (int) smallParams.maxHeight + 10;
+
+        measureAndLayout(height);
+
+        assertTrue("one and only one view should be visible",
+                mLargeView.getVisibility() != mSmallView.getVisibility());
+        // behavior is undefined in this case.
+    }
+
+    @SmallTest
+    public void testOpenIntoAnOverlap() {
+        inflate(R.layout.size_adaptive_overlapping);
+
+        SizeAdaptiveLayout.LayoutParams smallParams =
+          (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams();
+        SizeAdaptiveLayout.LayoutParams largeParams =
+          (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
+        assertEquals("overlapping layout should overlap",
+                smallParams.minHeight,
+                largeParams.minHeight);
+        int height = (int) smallParams.maxHeight;
+
+        measureAndLayout(height);
+
+        assertTrue("one and only one view should be visible",
+                mLargeView.getVisibility() != mSmallView.getVisibility());
+        assertEquals("1U should get priority in an overlap because it is first",
+                View.VISIBLE,
+                mSmallView.getVisibility());
+    }
+
+    @SmallTest
+    public void testOpenThreeWayViewSmall() {
+        inflate(R.layout.size_adaptive_three_way);
+        assertNotNull("mMediumView should not be NULL in the three view layout", mMediumView);
+
+        SizeAdaptiveLayout.LayoutParams lp =
+          (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams();
+        int height = (int) lp.minHeight;
+
+        measureAndLayout(height);
+
+        assertEquals("1U should be visible",
+                View.VISIBLE,
+                mSmallView.getVisibility());
+        assertEquals("2U should be gone",
+                View.GONE,
+                mMediumView.getVisibility());
+        assertEquals("4U should be gone",
+                View.GONE,
+                mLargeView.getVisibility());
+    }
+
+    @SmallTest
+    public void testOpenThreeWayViewMedium() {
+        inflate(R.layout.size_adaptive_three_way);
+        assertNotNull("mMediumView should not be NULL in the three view layout", mMediumView);
+
+        SizeAdaptiveLayout.LayoutParams lp =
+          (SizeAdaptiveLayout.LayoutParams) mMediumView.getLayoutParams();
+        int height = (int) lp.minHeight;
+
+        measureAndLayout(height);
+
+        assertEquals("1U should be gone",
+                View.GONE,
+                mSmallView.getVisibility());
+        assertEquals("2U should be visible",
+                View.VISIBLE,
+                mMediumView.getVisibility());
+        assertEquals("4U should be gone",
+                View.GONE,
+                mLargeView.getVisibility());
+    }
+
+    @SmallTest
+    public void testOpenThreeWayViewLarge() {
+        inflate(R.layout.size_adaptive_three_way);
+        assertNotNull("mMediumView should not be NULL in the three view layout", mMediumView);
+
+        SizeAdaptiveLayout.LayoutParams lp =
+          (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
+        int height = (int) lp.minHeight;
+
+        measureAndLayout(height);
+
+        assertEquals("1U should be gone",
+                View.GONE,
+                mSmallView.getVisibility());
+        assertEquals("2U should be gone",
+                View.GONE,
+                mMediumView.getVisibility());
+        assertEquals("4U should be visible",
+                View.VISIBLE,
+                mLargeView.getVisibility());
+    }
+
+    @SmallTest
+    public void testResizeWithoutAnimation() {
+        inflate(R.layout.size_adaptive);
+
+        SizeAdaptiveLayout.LayoutParams largeParams =
+          (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
+        int startHeight = (int) largeParams.minHeight + 10;
+        int endHeight = (int) largeParams.minHeight + 10;
+
+        measureAndLayout(startHeight);
+
+        assertEquals("4U should be visible",
+                View.VISIBLE,
+                mLargeView.getVisibility());
+        assertFalse("There should be no animation on initial rendering.",
+                    mSizeAdaptiveLayout.getTransitionAnimation().isRunning());
+
+        measureAndLayout(endHeight);
+
+        assertEquals("4U should still be visible",
+                View.VISIBLE,
+                mLargeView.getVisibility());
+        assertFalse("There should be no animation on scale within a view.",
+                    mSizeAdaptiveLayout.getTransitionAnimation().isRunning());
+    }
+
+    @SmallTest
+    public void testResizeWithAnimation() {
+        inflate(R.layout.size_adaptive);
+
+        SizeAdaptiveLayout.LayoutParams smallParams =
+          (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams();
+        SizeAdaptiveLayout.LayoutParams largeParams =
+          (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
+        int startHeight = (int) largeParams.minHeight + 10;
+        int endHeight = (int) smallParams.maxHeight;
+
+        measureAndLayout(startHeight);
+
+        assertEquals("4U should be visible",
+                View.VISIBLE,
+                mLargeView.getVisibility());
+        assertFalse("There should be no animation on initial rendering.",
+                    mSizeAdaptiveLayout.getTransitionAnimation().isRunning());
+
+        measureAndLayout(endHeight);
+
+        assertEquals("1U should now be visible",
+                View.VISIBLE,
+                mSmallView.getVisibility());
+        assertTrue("There should be an animation on scale between views.",
+                   mSizeAdaptiveLayout.getTransitionAnimation().isRunning());
+    }
+
+    @SmallTest
+    public void testModestyPanelChangesColorWhite() {
+        inflate(R.layout.size_adaptive_color);
+        View panel = mSizeAdaptiveLayout.getModestyPanel();
+        assertTrue("ModestyPanel should have a ColorDrawable background",
+                   panel.getBackground() instanceof ColorDrawable);
+        ColorDrawable panelColor = (ColorDrawable) panel.getBackground();
+        ColorDrawable salColor = (ColorDrawable) mSizeAdaptiveLayout.getBackground();
+        assertEquals("ModestyPanel color should match the SizeAdaptiveLayout",
+                     panelColor.getColor(), salColor.getColor());
+    }
+
+    @SmallTest
+    public void testModestyPanelHasDefault() {
+        inflate(R.layout.size_adaptive);
+        View panel = mSizeAdaptiveLayout.getModestyPanel();
+        assertNull("SizeAdaptiveLayout should have no background for this test",
+                     mSizeAdaptiveLayout.getBackground());
+        assertTrue("ModestyPanel should have a ColorDrawable background",
+                   panel.getBackground() instanceof ColorDrawable);
+    }
+
+    private void measureAndLayout(int height) {
+        // manually measure it, and lay it out
+        int measureSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST);
+        mSizeAdaptiveLayout.measure(500, measureSpec);
+        mSizeAdaptiveLayout.layout(0, 0, 500, height);
+    }
+}
diff --git a/data/fonts/DroidNaskh-Regular-Shift.ttf b/data/fonts/DroidNaskh-Regular-Shift.ttf
index 0cb843d..bb9c70c 100644
--- a/data/fonts/DroidNaskh-Regular-Shift.ttf
+++ b/data/fonts/DroidNaskh-Regular-Shift.ttf
Binary files differ
diff --git a/data/sounds/AllAudio.mk b/data/sounds/AllAudio.mk
index 2e18a10..e403205 100644
--- a/data/sounds/AllAudio.mk
+++ b/data/sounds/AllAudio.mk
@@ -20,3 +20,5 @@
 $(call inherit-product, frameworks/base/data/sounds/AudioPackage4.mk)
 $(call inherit-product, frameworks/base/data/sounds/AudioPackage5.mk)
 $(call inherit-product, frameworks/base/data/sounds/AudioPackage6.mk)
+$(call inherit-product, frameworks/base/data/sounds/AudioPackage7.mk)
+$(call inherit-product, frameworks/base/data/sounds/AudioPackage7alt.mk)
diff --git a/docs/html/images/training/backward-compatible-ui-classes-eclair.png b/docs/html/images/training/backward-compatible-ui-classes-eclair.png
new file mode 100644
index 0000000..febba5b
--- /dev/null
+++ b/docs/html/images/training/backward-compatible-ui-classes-eclair.png
Binary files differ
diff --git a/docs/html/images/training/backward-compatible-ui-classes-honeycomb.png b/docs/html/images/training/backward-compatible-ui-classes-honeycomb.png
new file mode 100644
index 0000000..ba14252
--- /dev/null
+++ b/docs/html/images/training/backward-compatible-ui-classes-honeycomb.png
Binary files differ
diff --git a/docs/html/images/training/backward-compatible-ui-classes.png b/docs/html/images/training/backward-compatible-ui-classes.png
new file mode 100644
index 0000000..c5a3cd8
--- /dev/null
+++ b/docs/html/images/training/backward-compatible-ui-classes.png
Binary files differ
diff --git a/docs/html/images/training/backward-compatible-ui-gb.png b/docs/html/images/training/backward-compatible-ui-gb.png
new file mode 100644
index 0000000..621ee63
--- /dev/null
+++ b/docs/html/images/training/backward-compatible-ui-gb.png
Binary files differ
diff --git a/docs/html/images/training/backward-compatible-ui-ics.png b/docs/html/images/training/backward-compatible-ui-ics.png
new file mode 100644
index 0000000..6460554
--- /dev/null
+++ b/docs/html/images/training/backward-compatible-ui-ics.png
Binary files differ
diff --git a/docs/html/images/training/implementing-navigation-up.png b/docs/html/images/training/implementing-navigation-up.png
new file mode 100644
index 0000000..18f3779
--- /dev/null
+++ b/docs/html/images/training/implementing-navigation-up.png
Binary files differ
diff --git a/docs/html/resources/resources_toc.cs b/docs/html/resources/resources_toc.cs
index 5297c23..686bde3 100644
--- a/docs/html/resources/resources_toc.cs
+++ b/docs/html/resources/resources_toc.cs
@@ -227,7 +227,31 @@
           </li>
         </ul>
       </li>
-      
+
+      <li class="toggle-list">
+        <div><a href="<?cs var:toroot ?>training/backward-compatible-ui/index.html">
+            <span class="en">Creating Backward-Compatible UIs<span class="new">&nbsp;new!</span></span>
+          </a></div>
+        <ul>
+          <li><a href="<?cs var:toroot ?>training/backward-compatible-ui/abstracting.html">
+            <span class="en">Abstracting the New APIs</span>
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/backward-compatible-ui/new-implementation.html">
+            <span class="en">Proxying to the New APIs</span>
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/backward-compatible-ui/older-implementation.html">
+            <span class="en">Creating an Implementation with Older APIs</span>
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/backward-compatible-ui/using-component.html">
+            <span class="en">Using the Version-Aware Component</span>
+          </a>
+          </li>
+        </ul>
+      </li>
+
       <li class="toggle-list">
         <div><a href="<?cs var:toroot ?>training/enterprise/index.html">
             <span class="en">Developing for Enterprise</span>
@@ -278,7 +302,32 @@
           </a>
           </li>
         </ul>
-       </li>
+      </li>
+
+      <li class="toggle-list">
+        <div><a href="<?cs var:toroot ?>training/implementing-navigation/index.html">
+            <span class="en">Implementing Effective Navigation<span class="new">&nbsp;new!</span></span>
+          </a></div>
+        <ul>
+          <li><a href="<?cs var:toroot ?>training/implementing-navigation/lateral.html">
+            <span class="en">Implementing Lateral Navigation</span>
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/implementing-navigation/ancestral.html">
+            <span class="en">Implementing Ancestral Navigation</span>
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/implementing-navigation/temporal.html">
+            <span class="en">Implementing Temporal Navigation</span>
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/implementing-navigation/descendant.html">
+            <span class="en">Implementing Descendant Navigation</span>
+          </a>
+          </li>
+        </ul>
+      </li>
+
        <li class="toggle-list">
         <div><a href="<?cs var:toroot ?>training/tv/index.html">
            <span class="en">Designing for TV<span class="new">&nbsp;new!</span></span>
diff --git a/docs/html/shareables/training/EffectiveNavigation.zip b/docs/html/shareables/training/EffectiveNavigation.zip
new file mode 100644
index 0000000..f21af45
--- /dev/null
+++ b/docs/html/shareables/training/EffectiveNavigation.zip
Binary files differ
diff --git a/docs/html/shareables/training/LocationAware.zip b/docs/html/shareables/training/LocationAware.zip
index 46970cd..8ed97cb 100644
--- a/docs/html/shareables/training/LocationAware.zip
+++ b/docs/html/shareables/training/LocationAware.zip
Binary files differ
diff --git a/docs/html/shareables/training/TabCompat.zip b/docs/html/shareables/training/TabCompat.zip
new file mode 100644
index 0000000..b70b442
--- /dev/null
+++ b/docs/html/shareables/training/TabCompat.zip
Binary files differ
diff --git a/docs/html/training/backward-compatible-ui/abstracting.jd b/docs/html/training/backward-compatible-ui/abstracting.jd
new file mode 100644
index 0000000..1141b54
--- /dev/null
+++ b/docs/html/training/backward-compatible-ui/abstracting.jd
@@ -0,0 +1,111 @@
+page.title=Abstracting the New APIs
+parent.title=Creating Backward-Compatible UIs
+parent.link=index.html
+
+trainingnavtop=true
+next.title=Proxying to the New APIs
+next.link=new-implementation.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to:</h2>
+<ul>
+  <li><a href="#prepare-abstraction">Prepare for Abstraction</a></li>
+  <li><a href="#create-abstract-tab">Create an Abstract Tab Interface</a></li>
+  <li><a href="#abstract-actionbar-tab">Abstract ActionBar.Tab</a></li>
+  <li><a href="#abstract-actionbar-methods">Abstract ActionBar Tab Methods</a></li>
+</ul>
+
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a></li>
+  <li><a href="{@docRoot}guide/topics/ui/actionbar.html#Tabs">Action Bar Tabs</a></li>
+</ul>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+<a href="http://developer.android.com/shareables/training/TabCompat.zip"
+  class="button">Download the sample app</a>
+<p class="filename">TabCompat.zip</p>
+</div>
+
+</div>
+</div>
+
+<p>Suppose you want to use <a href="{@docRoot}guide/topics/ui/actionbar.html#Tabs">action bar tabs</a> as the primary form of top-level navigation in your application. Unfortunately, the {@link android.app.ActionBar} APIs are only available in Android 3.0 or later (API level 11+). Thus, if you want to distribute your application to devices running earlier versions of the platform, you need to provide an implementation that supports the newer API while providing a fallback mechanism that uses older APIs.</p>
+
+<p>In this class, you build a tabbed user interface (UI) component that uses abstract classes with version-specific implementations to provide backward-compatibility. This lesson describes how to create an abstraction layer for the new tab APIs as the first step toward building the tab component.</p>
+
+<h2 id="prepare-abstraction">Prepare for Abstraction</h2>
+
+<p><a href="http://en.wikipedia.org/wiki/Abstraction_(computer_science)">Abstraction</a> in the Java programming language involves the creation of one or more interfaces or abstract classes to hide implementation details. In the case of newer Android APIs, you can use abstraction to build version-aware components that use the current APIs on newer devices, and fallback to older, more compatible APIs on older devices.</p>
+
+<p>When using this approach, you first determine what newer classes you want to be able to use in a backward compatible way, then create abstract classes, based on the public interfaces of the newer classes. In defining the abstraction interfaces, you should mirror the newer API as much as possible. This maximizes forward-compatibility and makes it easier to drop the abstraction layer in the future when it is no longer necessary.</p>
+
+<p>After creating abstract classes for these new APIs, any number of implementations can be created and chosen at runtime. For the purposes of backward-compatibility, these implementations can vary by required API level. Thus, one implementation may use recently released APIs, while others can use older APIs.</p>
+
+<h2 id="create-abstract-tab">Create an Abstract Tab Interface</h2>
+
+<p>In order to create a backward-compatible version of tabs, you should first determine which features and specific APIs your application requires. In the case of top-level section tabs, suppose you have the following functional requirements:</p>
+
+<ol>
+<li>Tab indicators should show text and an icon.</li>
+<li>Tabs can be associated with a fragment instance.</li>
+<li>The activity should be able to listen for tab changes.</li>
+</ol>
+
+<p>Preparing these requirements in advance allows you to control the scope of your abstraction layer. This means that you can spend less time creating multiple implementations of your abstraction layer and begin using your new backward-compatible implementation sooner.</p>
+
+<p>The key APIs for tabs are in {@link android.app.ActionBar} and {@link android.app.ActionBar.Tab ActionBar.Tab}. These are the APIs to abstract in order to make your tabs version-aware. The requirements for this example project call for compatibility back to Eclair (API level 5) while taking advantage of the new tab features in Honeycomb (API Level 11). A diagram of the class structure to support these two implementations and their abstract base classes (or interfaces) is shown below.</p>
+
+<img src="{@docRoot}images/training/backward-compatible-ui-classes.png"
+  alt="Class diagram of abstract base classes and version-specific implementations." id="figure-classes">
+
+<p class="img-caption"><strong>Figure 1.</strong> Class diagram of abstract base classes and version-specific implementations.</p>
+
+<h2 id="abstract-actionbar-tab">Abstract ActionBar.Tab</h2>
+
+<p>Get started on building your tab abstraction layer by creating an abstract class representing a tab, that mirrors the {@link android.app.ActionBar.Tab ActionBar.Tab} interface:</p>
+
+<pre>
+public abstract class CompatTab {
+    ...
+    public abstract CompatTab setText(int resId);
+    public abstract CompatTab setIcon(int resId);
+    public abstract CompatTab setTabListener(
+            CompatTabListener callback);
+    public abstract CompatTab setFragment(Fragment fragment);
+
+    public abstract CharSequence getText();
+    public abstract Drawable getIcon();
+    public abstract CompatTabListener getCallback();
+    public abstract Fragment getFragment();
+    ...
+}
+</pre>
+
+<p>You can use an abstract class instead of an interface here to simplify the implementation of common features such as association of tab objects with activities (not shown in the code snippet).</p>
+
+<h2 id="abstract-actionbar-methods">Abstract ActionBar Tab Methods</h2>
+
+<p>Next, define an abstract class that allows you to create and add tabs to an activity, like {@link android.app.ActionBar#newTab ActionBar.newTab()} and {@link android.app.ActionBar#addTab ActionBar.addTab()}:</p>
+
+<pre>
+public abstract class TabHelper {
+    ...
+
+    public CompatTab newTab(String tag) {
+        // This method is implemented in a later lesson.
+    }
+
+    public abstract void addTab(CompatTab tab);
+
+    ...
+}
+</pre>
+
+<p>In the next lessons, you create implementations for <code>TabHelper</code> and <code>CompatTab</code> that work across both older and newer platform versions.</p>
diff --git a/docs/html/training/backward-compatible-ui/index.jd b/docs/html/training/backward-compatible-ui/index.jd
new file mode 100644
index 0000000..7e27e68
--- /dev/null
+++ b/docs/html/training/backward-compatible-ui/index.jd
@@ -0,0 +1,57 @@
+page.title=Creating Backward-Compatible UIs
+
+trainingnavtop=true
+startpage=true
+next.title=Abstracting the New Implementation
+next.link=abstracting.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>Dependencies and prerequisites</h2>
+
+<ul>
+  <li>API level 5</li>
+  <li><a href="{@docRoot}sdk/compatibility-library.html">The Android Support Package</a></li>
+</ul>
+
+<h2>You should also read</h2>
+
+<ul>
+  <li><a href="{@docRoot}resources/samples/ActionBarCompat/index.html">ActionBarCompat</a></li>
+  <li><a href="http://android-developers.blogspot.com/2010/07/how-to-have-your-cupcake-and-eat-it-too.html">How to have your (Cup)cake and eat it too</a></li>
+</ul>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+<a href="http://developer.android.com/shareables/training/TabCompat.zip"
+  class="button">Download the sample app</a>
+<p class="filename">TabCompat.zip</p>
+</div>
+
+</div>
+</div>
+
+<p>This class demonstrates how to use UI components and APIs available in newer versions of Android in a backward-compatible way, ensuring that your application still runs on previous versions of the platform.</p>
+
+<p>Throughout this class, the new <a href="{@docRoot}guide/topics/ui/actionbar.html#Tabs">Action Bar Tabs</a> feature introduced in Android 3.0 (API level 11) serves as the guiding example, but you can apply these techniques to other UI components and API features.</p>
+
+<h2 id="lessons">Lessons</h2>
+
+
+<dl>
+  <dt><strong><a href="abstracting.html">Abstracting the New APIs</a></strong></dt>
+    <dd>Determine which features and APIs your application needs. Learn how to define application-specific, intermediary Java interfaces that abstract the implementation of the UI component to your application.</dd>
+
+  <dt><strong><a href="new-implementation.html">Proxying to the New APIs</a></strong></dt>
+    <dd>Learn how to create an implementation of your interface that uses newer APIs.</dd>
+
+  <dt><strong><a href="older-implementation.html">Creating an Implementation with Older APIs</a></strong></dt>
+    <dd>Learn how to create a custom implementation of your interface that uses older APIs.</dd>
+
+  <dt><strong><a href="using-component.html">Using the Version-Aware Component</a></strong></dt>
+    <dd>Learn how to choose an implementation to use at runtime, and begin using the interface in your application.</dd>
+</dl>
diff --git a/docs/html/training/backward-compatible-ui/new-implementation.jd b/docs/html/training/backward-compatible-ui/new-implementation.jd
new file mode 100644
index 0000000..5b8b51c
--- /dev/null
+++ b/docs/html/training/backward-compatible-ui/new-implementation.jd
@@ -0,0 +1,113 @@
+page.title=Proxying to the New APIs
+parent.title=Creating Backward-Compatible UIs
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Abstracting the New APIs
+previous.link=abstracting.html
+next.title=Creating an Implementation with Older APIs
+next.link=older-implementation.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to:</h2>
+<ol>
+  <li><a href="#new-tabs">Implement Tabs Using New APIs</a></li>
+  <li><a href="#compattabhoneycomb">Implement CompatTabHoneycomb</a></li>
+  <li><a href="#tabhelperhoneycomb">Implement TabHelperHoneycomb</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a></li>
+  <li><a href="{@docRoot}guide/topics/ui/actionbar.html#Tabs">Action Bar Tabs</a></li>
+</ul>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+<a href="http://developer.android.com/shareables/training/TabCompat.zip"
+  class="button">Download the sample app</a>
+<p class="filename">TabCompat.zip</p>
+</div>
+
+</div>
+</div>
+
+<p>This lesson shows you how to subclass the <code>CompatTab</code> and <code>TabHelper</code> abstract classes and use new APIs. Your application can use this implementation on devices running a platform version that supports them.</p>
+
+<h2 id="new-tabs">Implement Tabs Using New APIs</h2>
+
+<p>The concrete classes for <code>CompatTab</code> and <code>TabHelper</code> that use newer APIs are a <em>proxy</em> implementation. Since the abstract classes defined in the previous lesson mirror the new APIs (class structure, method signatures, etc.), the concrete classes that use these newer APIs simply proxy method calls and their results.</p>
+
+<p>You can directly use newer APIs in these concrete classes&mdash;and not crash on earlier devices&mdash;because of lazy class loading. Classes are loaded and initialized on first access&mdash;instantiating the class or accessing one of its static fields or methods for the first time. Thus, as long as you don't instantiate the Honeycomb-specific implementations on pre-Honeycomb devices, the Dalvik VM won't throw any {@link java.lang.VerifyError} exceptions.</p>
+
+<p>A good naming convention for this implementation is to append the API level or platform version code name corresponding to the APIs required by the concrete classes. For example, the native tab implementation can be provided by <code>CompatTabHoneycomb</code> and <code>TabHelperHoneycomb</code> classes, since they rely on APIs available in Android 3.0 (API level 11) or later.</p>
+
+<img src="{@docRoot}images/training/backward-compatible-ui-classes-honeycomb.png"
+  alt="Class diagram for the Honeycomb implementation of tabs." id="figure-classes">
+
+<p class="img-caption"><strong>Figure 1.</strong> Class diagram for the Honeycomb implementation of tabs.</p>
+
+<h2 id="compattabhoneycomb">Implement CompatTabHoneycomb</h2>
+
+<p><code>CompatTabHoneycomb</code> is the implementation of the <code>CompatTab</code> abstract class that <code>TabHelperHoneycomb</code> uses to reference individual tabs. <code>CompatTabHoneycomb</code> simply proxies all method calls to its contained {@link android.app.ActionBar.Tab} object.</p>
+
+<p>Begin implementing <code>CompatTabHoneycomb</code> using the new {@link android.app.ActionBar.Tab ActionBar.Tab} APIs:</p>
+
+<pre>
+public class CompatTabHoneycomb extends CompatTab {
+    // The native tab object that this CompatTab acts as a proxy for.
+    ActionBar.Tab mTab;
+    ...
+
+    protected CompatTabHoneycomb(FragmentActivity activity, String tag) {
+        ...
+        // Proxy to new ActionBar.newTab API
+        mTab = activity.getActionBar().newTab();
+    }
+
+    public CompatTab setText(int resId) {
+        // Proxy to new ActionBar.Tab.setText API
+        mTab.setText(resId);
+        return this;
+    }
+
+    ...
+    // Do the same for other properties (icon, callback, etc.)
+}
+</pre>
+
+<h2 id="tabhelperhoneycomb">Implement TabHelperHoneycomb</h2>
+
+<p><code>TabHelperHoneycomb</code> is the implementation of the <code>TabHelper</code> abstract class that proxies method calls to an actual {@link android.app.ActionBar}, obtained from its contained {@link android.app.Activity}.</p>
+
+<p>Implement <code>TabHelperHoneycomb</code>, proxying method calls to the {@link android.app.ActionBar} API:</p>
+
+<pre>
+public class TabHelperHoneycomb extends TabHelper {
+    ActionBar mActionBar;
+    ...
+
+    protected void setUp() {
+        if (mActionBar == null) {
+            mActionBar = mActivity.getActionBar();
+            mActionBar.setNavigationMode(
+                    ActionBar.NAVIGATION_MODE_TABS);
+        }
+    }
+
+    public void addTab(CompatTab tab) {
+        ...
+        // Tab is a CompatTabHoneycomb instance, so its
+        // native tab object is an ActionBar.Tab.
+        mActionBar.addTab((ActionBar.Tab) tab.getTab());
+    }
+
+    // The other important method, newTab() is part of
+    // the base implementation.
+}
+</pre>
\ No newline at end of file
diff --git a/docs/html/training/backward-compatible-ui/older-implementation.jd b/docs/html/training/backward-compatible-ui/older-implementation.jd
new file mode 100644
index 0000000..5006123
--- /dev/null
+++ b/docs/html/training/backward-compatible-ui/older-implementation.jd
@@ -0,0 +1,126 @@
+page.title=Creating an Implementation with Older APIs
+parent.title=Creating Backward-Compatible UIs
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Proxying to the New APIs
+previous.link=new-implementation.html
+next.title=Using the Version-Aware Component
+next.link=using-component.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to:</h2>
+<ol>
+  <li><a href="#decide-substitute">Decide on a Substitute Solution</a></li>
+  <li><a href="#older-tabs">Implement Tabs Using Older APIs</a></li>
+</ol>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+<a href="http://developer.android.com/shareables/training/TabCompat.zip"
+  class="button">Download the sample app</a>
+<p class="filename">TabCompat.zip</p>
+</div>
+
+</div>
+</div>
+
+
+<p>This lesson discusses how to create an implementation that mirrors newer APIs yet supports older devices.</p>
+
+<h2 id="decide-substitute">Decide on a Substitute Solution</h2>
+
+<p>The most challenging task in using newer UI features in a backward-compatible way is deciding on and implementing an older (fallback) solution for older platform versions. In many cases, it's possible to fulfill the purpose of these newer UI components using older UI framework features. For example:</p>
+
+<ul>
+
+<li>
+<p>Action bars can be implemented using a horizontal {@link android.widget.LinearLayout} containing image buttons, either as custom title bars or as views in your activity layout. Overflow actions can be presented under the device <em>Menu</em> button.</p>
+</li>
+
+<li>
+<p>Action bar tabs can be implemented using a horizontal {@link android.widget.LinearLayout} containing buttons, or using the {@link android.widget.TabWidget} UI element.</p>
+</li>
+
+<li>
+<p>{@link android.widget.NumberPicker} and {@link android.widget.Switch} widgets can be implemented using {@link android.widget.Spinner} and {@link android.widget.ToggleButton} widgets, respectively.</p>
+</li>
+
+<li>
+<p>{@link android.widget.ListPopupWindow} and {@link android.widget.PopupMenu} widgets can be implemented using {@link android.widget.PopupWindow} widgets.</p>
+</li>
+
+</ul>
+
+<p>There generally isn't a one-size-fits-all solution for backporting newer UI components to older devices. Be mindful of the user experience: on older devices, users may not be familiar with newer design patterns and UI components. Give some thought as to how the same functionality can be delivered using familiar elements. In many cases this is less of a concern&mdash;if newer UI components are prominent in the application ecosystem (such as the action bar), or where the interaction model is extremely simple and intuitive (such as swipe views using a {@link android.support.v4.view.ViewPager}).</p>
+
+<h2 id="older-tabs">Implement Tabs Using Older APIs</h2>
+
+<p>To create an older implementation of action bar tabs, you can use a {@link android.widget.TabWidget} and {@link android.widget.TabHost} (although one can alternatively use horizontally laid-out {@link android.widget.Button} widgets). Implement this in classes called <code>TabHelperEclair</code> and <code>CompatTabEclair</code>, since this implementation uses APIs introduced no later than Android 2.0 (Eclair).</p>
+
+
+<img src="{@docRoot}images/training/backward-compatible-ui-classes-eclair.png"
+  alt="Class diagram for the Eclair implementation of tabs." id="figure-classes">
+
+<p class="img-caption"><strong>Figure 1.</strong> Class diagram for the Eclair implementation of tabs.</p>
+
+<p>The <code>CompatTabEclair</code> implementation stores tab properties such as the tab text and icon in instance variables, since there isn't an {@link android.app.ActionBar.Tab ActionBar.Tab} object available to handle this storage:</p>
+
+<pre>
+public class CompatTabEclair extends CompatTab {
+    // Store these properties in the instance,
+    // as there is no ActionBar.Tab object.
+    private CharSequence mText;
+    ...
+
+    public CompatTab setText(int resId) {
+        // Our older implementation simply stores this
+        // information in the object instance.
+        mText = mActivity.getResources().getText(resId);
+        return this;
+    }
+
+    ...
+    // Do the same for other properties (icon, callback, etc.)
+}
+</pre>
+
+<p>The <code>TabHelperEclair</code> implementation makes use of methods on the
+{@link android.widget.TabHost} widget for creating {@link android.widget.TabHost.TabSpec}
+objects and tab indicators:</p>
+
+<pre>
+public class TabHelperEclair extends TabHelper {
+    private TabHost mTabHost;
+    ...
+
+    protected void setUp() {
+        if (mTabHost == null) {
+            // Our activity layout for pre-Honeycomb devices
+            // must contain a TabHost.
+            mTabHost = (TabHost) mActivity.findViewById(
+                    android.R.id.tabhost);
+            mTabHost.setup();
+        }
+    }
+
+    public void addTab(CompatTab tab) {
+        ...
+        TabSpec spec = mTabHost
+                .newTabSpec(tag)
+                .setIndicator(tab.getText()); // And optional icon
+        ...
+        mTabHost.addTab(spec);
+    }
+
+    // The other important method, newTab() is part of
+    // the base implementation.
+}
+</pre>
+
+<p>You now have two implementations of <code>CompatTab</code> and <code>TabHelper</code>: one that works on devices running Android 3.0 or later and uses new APIs, and another that works on devices running Android 2.0 or later and uses older APIs. The next lesson discusses using these implementations in your application.</p>
diff --git a/docs/html/training/backward-compatible-ui/using-component.jd b/docs/html/training/backward-compatible-ui/using-component.jd
new file mode 100644
index 0000000..4bf7fa0
--- /dev/null
+++ b/docs/html/training/backward-compatible-ui/using-component.jd
@@ -0,0 +1,143 @@
+page.title=Using the Version-Aware Component
+parent.title=Creating Backward-Compatible UIs
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Creating an Implementation with Older APIs
+previous.link=older-implementation.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to:</h2>
+<ol>
+  <li><a href="#switching-logic">Add the Switching Logic</a></li>
+  <li><a href="#layout">Create a Version-Aware Activity Layout</a></li>
+  <li><a href="#use-tabhelper">Use TabHelper in Your Activity</a></li>
+</ol>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+<a href="http://developer.android.com/shareables/training/TabCompat.zip"
+  class="button">Download the sample app</a>
+<p class="filename">TabCompat.zip</p>
+</div>
+
+</div>
+</div>
+
+<p>Now that you have two implementations of <code>TabHelper</code> and <code>CompatTab</code>&mdash;one for Android 3.0 and later and one for earlier versions of the platform&mdash;it's time to do something with these implementations. This lesson discusses creating the logic for switching between these implementations, creating version-aware layouts, and finally using the backward-compatible UI component.</p>
+
+<h2 id="switching-logic">Add the Switching Logic</h2>
+
+<p>The <code>TabHelper</code> abstract class acts as a <a href="http://en.wikipedia.org/wiki/Factory_(software_concept)">factory</a> for creating version-appropriate <code>TabHelper</code> and <code>CompatTab</code> instances, based on the current device's platform version:</p>
+
+<pre>
+public abstract class TabHelper {
+    ...
+    // Usage is TabHelper.createInstance(activity)
+    public static TabHelper createInstance(FragmentActivity activity) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+            return new TabHelperHoneycomb(activity);
+        } else {
+            return new TabHelperEclair(activity);
+        }
+    }
+
+    // Usage is mTabHelper.newTab("tag")
+    public CompatTab newTab(String tag) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+            return new CompatTabHoneycomb(mActivity, tag);
+        } else {
+            return new CompatTabEclair(mActivity, tag);
+        }
+    }
+    ...
+}
+</pre>
+
+<h2 id="layout">Create a Version-Aware Activity Layout</h2>
+
+<p>The next step is to provide layouts for your activity that can support the two tab implementations. For the older implementation (<code>TabHelperEclair</code>), you need to ensure that your activity layout contains a {@link android.widget.TabWidget} and {@link android.widget.TabHost}, along with a container for tab contents:</p>
+
+<p><strong>res/layout/main.xml:</strong></p>
+
+<pre>
+&lt;!-- This layout is for API level 5-10 only. --&gt;
+&lt;TabHost xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/tabhost"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"&gt;
+
+    &lt;LinearLayout
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:padding="5dp"&gt;
+
+        &lt;TabWidget
+            android:id="@android:id/tabs"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" /&gt;
+
+        &lt;FrameLayout
+            android:id="@android:id/tabcontent"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="1" /&gt;
+
+    &lt;/LinearLayout&gt;
+&lt;/TabHost&gt;
+</pre>
+
+<p>For the <code>TabHelperHoneycomb</code> implementation, all you need is a {@link android.widget.FrameLayout} to contain the tab contents, since the tab indicators are provided by the {@link android.app.ActionBar}:</p>
+
+<p><strong>res/layout-v11/main.xml:</strong></p>
+
+<pre>
+&lt;FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/tabcontent"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent" /&gt;
+</pre>
+
+<p>At runtime, Android will decide which version of the <code>main.xml</code> layout to inflate depending on the platform version. This is the same logic shown in the previous section to determine which <code>TabHelper</code> implementation to use.</p>
+
+<h2 id="use-tabhelper">Use TabHelper in Your Activity</h2>
+
+<p>In your activity's {@link android.app.Activity#onCreate onCreate()} method, you can obtain a <code>TabHelper</code> object and add tabs with the following code:</p>
+
+<pre>
+{@literal @}Override
+public void onCreate(Bundle savedInstanceState) {
+    setContentView(R.layout.main);
+
+    TabHelper tabHelper = TabHelper.createInstance(this);
+    tabHelper.setUp();
+
+    CompatTab photosTab = tabHelper
+            .newTab("photos")
+            .setText(R.string.tab_photos);
+    tabHelper.addTab(photosTab);
+
+    CompatTab videosTab = tabHelper
+            .newTab("videos")
+            .setText(R.string.tab_videos);
+    tabHelper.addTab(videosTab);
+}
+</pre>
+
+<p>When running the application, this code inflates the correct activity layout and instantiates either a <code>TabHelperHoneycomb</code> or <code>TabHelperEclair</code> object. The concrete class that's actually used is opaque to the activity, since they share the common <code>TabHelper</code> interface.</p>
+
+<p>Below are two screenshots of this implementation running on an Android 2.3 and Android 4.0 device.</p>
+
+<img src="{@docRoot}images/training/backward-compatible-ui-gb.png"
+  alt="Example screenshot of tabs running on an Android 2.3 device (using TabHelperEclair)." width="200">
+
+<img src="{@docRoot}images/training/backward-compatible-ui-ics.png"
+  alt="Example screenshots of tabs running on an Android 4.0 device (using TabHelperHoneycomb)." width="200">
+
+<p class="img-caption"><strong>Figure 1.</strong> Example screenshots of backward-compatible tabs running on an Android 2.3 device (using <code>TabHelperEclair</code>) and an Android 4.0 device (using <code>TabHelperHoneycomb</code>).</p>
diff --git a/docs/html/training/implementing-navigation/ancestral.jd b/docs/html/training/implementing-navigation/ancestral.jd
new file mode 100644
index 0000000..495b45d
--- /dev/null
+++ b/docs/html/training/implementing-navigation/ancestral.jd
@@ -0,0 +1,124 @@
+page.title=Implementing Ancestral Navigation
+parent.title=Implementing Effective Navigation
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Implementing Lateral Navigation
+previous.link=lateral.html
+next.title=Implementing Temporal Navigation
+next.link=temporal.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to:</h2>
+<ol>
+  <li><a href="#up">Implement <em>Up</em> Navigation</a></li>
+  <li><a href="#app-home">Properly Handle the Application Home Screen</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}training/design-navigation/ancestral-temporal.html">Providing Ancestral and Temporal Navigation</a></li>
+  <li><a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back Stack</a></li>
+  <li><a href="{@docRoot}design/patterns/navigation.html">Android Design: Navigation</a></li>
+</ul>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+<a href="http://developer.android.com/shareables/training/EffectiveNavigation.zip"
+  class="button">Download the sample app</a>
+<p class="filename">EffectiveNavigation.zip</p>
+</div>
+
+</div>
+</div>
+
+
+<p><em>Ancestral navigation</em> is up the application's information hierarchy, where the top of the hierarchy (or root) is the application's home screen. This navigation concept is described in <a href="{@docRoot}training/design-navigation/ancestral-temporal.html">Designing Effective Navigation</a>. This lesson discusses how to provide ancestral navigation using the <em>Up</em> button in the action bar.</p>
+
+
+<h2 id="up">Implement <em>Up</em> Navigation</h2>
+
+<p>When implementing ancestral navigation, all screens in your application that aren't the home screen should offer a means of navigating to the immediate parent screen in the hierarchy via the <em>Up</em> button in the action bar.</p>
+
+
+<img src="{@docRoot}images/training/implementing-navigation-up.png"
+  alt="The Up button in the action bar." id="figure-up">
+
+<p class="img-caption"><strong>Figure 1.</strong> The <em>Up</em> button in the action bar.</p>
+
+<p>Regardless of how the current screen was reached, pressing this button should always take the user to the same screen in the hierarchy.</p>
+
+<p>To implement <em>Up</em>, enable it in the action bar in your activity's {@link android.app.Activity#onCreate onCreate()} method:</p>
+
+<pre>
+{@literal @}Override
+public void onCreate(Bundle savedInstanceState) {
+    ...
+    getActionBar().setDisplayHomeAsUpEnabled(true);
+    ...
+}
+</pre>
+
+<p>You should also handle <code>android.R.id.home</code> in {@link android.app.Activity#onOptionsItemSelected onOptionsItemSelected()}. This resource is the menu item ID for the <em>Home</em> (or <em>Up</em>) button. To ensure that a specific parent activity is shown, <em>DO NOT</em> simply call {@link android.app.Activity#finish finish()}. Instead, use an intent such as the one described below.</p>
+
+<pre>
+{@literal @}Override
+public boolean onOptionsItemSelected(MenuItem item) {
+    switch (item.getItemId()) {
+        case android.R.id.home:
+            // This is called when the Home (Up) button is pressed
+            // in the Action Bar.
+            Intent parentActivityIntent = new Intent(this, MyParentActivity.class);
+            parentActivityIntent.addFlags(
+                    Intent.FLAG_ACTIVITY_CLEAR_TOP |
+                    Intent.FLAG_ACTIVITY_NEW_TASK);
+            startActivity(parentActivityIntent);
+            finish();
+            return true;
+    }
+    return super.onOptionsItemSelected(item);
+}
+</pre>
+
+<p>When the current activity belongs to a task from a different application&mdash;for example if it was reached via an intent from another application&mdash;pressing <em>Up</em> should create a new task for the application with a synthesized back stack. This approach is described in <a href="{@docRoot}design/patterns/navigation.html">Android Design: Navigation</a> and the {@link android.support.v4.app.TaskStackBuilder} class reference.</p>
+
+<p>The {@link android.support.v4.app.NavUtils} and {@link android.support.v4.app.TaskStackBuilder} classes in the <a href="{@docRoot}sdk/compatibility-library.html">Android Support Package</a> provide helpers for implementing this behavior correctly. An example usage of these two helper classes is below:</p>
+
+<pre>
+{@literal @}Override
+public boolean onOptionsItemSelected(MenuItem item) {
+    switch (item.getItemId()) {
+        case android.R.id.home:
+            Intent upIntent = new Intent(this, MyParentActivity.class);
+            if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
+                // This activity is not part of the application's task, so create a new task
+                // with a synthesized back stack.
+                TaskStackBuilder.from(this)
+                        .addNextIntent(new Intent(this, MyGreatGrandParentActivity.class))
+                        .addNextIntent(new Intent(this, MyGrandParentActivity.class))
+                        .addNextIntent(upIntent)
+                        .startActivities();
+                finish();
+            } else {
+                // This activity is part of the application's task, so simply
+                // navigate up to the hierarchical parent activity.
+                NavUtils.navigateUpTo(this, upIntent);
+            }
+            return true;
+    }
+    return super.onOptionsItemSelected(item);
+}
+</pre>
+
+<h2 id="app-home">Properly Handle the Application Home Screen</h2>
+
+<p>By default, the <em>Home</em> button in the action bar is interactive. Since it does not make much sense to navigate home&mdash;or up one level&mdash;while on the home screen, you should disable the button like so:</p>
+
+<pre>
+getActionBar().setHomeButtonEnabled(false);
+</pre>
diff --git a/docs/html/training/implementing-navigation/descendant.jd b/docs/html/training/implementing-navigation/descendant.jd
new file mode 100644
index 0000000..7d0063c
--- /dev/null
+++ b/docs/html/training/implementing-navigation/descendant.jd
@@ -0,0 +1,65 @@
+page.title=Implementing Descendant Navigation
+parent.title=Implementing Effective Navigation
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Implementing Temporal Navigation
+previous.link=temporal.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to:</h2>
+<ol>
+  <li><a href="#master-detail">Implement Master/Detail Flows Across Handsets and Tablets</a></li>
+  <li><a href="#external-activities">Navigate into External Activities</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}training/design-navigation/descendant-lateral.html">Providing Descendant and Lateral Navigation</a></li>
+  <li><a href="{@docRoot}design/patterns/app-structure.html">Android Design: App Structure</a></li>
+  <li><a href="{@docRoot}design/patterns/multi-pane-layouts.html">Android Design: Multi-pane Layouts</a></li>
+</ul>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+<a href="http://developer.android.com/shareables/training/EffectiveNavigation.zip"
+  class="button">Download the sample app</a>
+<p class="filename">EffectiveNavigation.zip</p>
+</div>
+
+</div>
+</div>
+
+
+<p><em>Descendant navigation</em> is navigation down the application's information hierarchy. This is described in <a href="{@docRoot}training/design-navigation/descendant-lateral.html">Designing Effective Navigation</a> and also covered in <a href="{@docRoot}design/patterns/app-structure.html">Android Design: Application Structure</a>.</p>
+
+<p>Descendant navigation is usually implemented using {@link android.content.Intent} objects and {@link android.content.Context#startActivity startActivity()}, or by adding fragments to an activity using {@link android.app.FragmentTransaction} objects. This lesson covers other interesting cases that arise when implementing descendant navigation.</p>
+
+<h2 id="master-detail">Implement Master/Detail Flows Across Handsets and Tablets</h2>
+
+<p>In a <em>master/detail</em> navigation flow, a <em>master</em> screen contains a list of items in a collection, and a <em>detail</em> screen shows detailed information about a specific item within that collection. Implementing navigation from the master screen to the detail screen is one form of descendant navigation.</p>
+
+<p>Handset touchscreens are most suitable for displaying one screen at a time (either the master or the detail screen); this concern is further discussed in <a href="{@docRoot}training/design-navigation/multiple-sizes.html">Planning for Multiple Touchscreen Sizes</a>. Descendant navigation in this case is often implemented using an {@link android.content.Intent} that starts an activity representing the detail screen. On the other hand, tablet displays, especially when viewed in the landscape orientation, are best suited for showing multiple content panes at a time: the master on the left, and the detail to the right). Here, descendant navigation is usually implemented using a {@link android.app.FragmentTransaction} that adds, removes, or replaces the detail pane with new content.</p>
+
+<p>The basics of implementing this pattern are described in the <a href="{@docRoot}training/multiscreen/adaptui.html">Implementing Adaptive UI Flows</a> lesson of the <em>Designing for Multiple Screens</em> class. The class describes how to implement a master/detail flow using two activities on a handset and a single activity on a tablet.</p>
+
+<h2 id="external-activities">Navigate into External Activities</h2>
+
+<p>There are cases where descending into your application's information hierarchy leads to activities from other applications. For example, when viewing the contact details screen for an entry in the phone address book, a child screen detailing recent posts by the contact on a social network may belong to a social networking application.</p>
+
+<p>When launching another application's activity to allow the user to say, compose an email or pick a photo attachment, you generally don't want the user to return to this activity if they relaunch your application from the Launcher (the device home screen). It would be confusing if touching your application icon brought the user to a "compose email" screen.</p>
+
+<p>To prevent this from occurring, simply add the {@link android.content.Intent#FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET} flag to the intent used to launch the external activity, like so:</p>
+
+<pre>
+Intent externalActivityIntent = new Intent(Intent.ACTION_PICK);
+externalActivityIntent.setType("image/*");
+externalActivityIntent.addFlags(
+        Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+startActivity(externalActivityIntent);
+</pre>
diff --git a/docs/html/training/implementing-navigation/index.jd b/docs/html/training/implementing-navigation/index.jd
new file mode 100644
index 0000000..da61c81
--- /dev/null
+++ b/docs/html/training/implementing-navigation/index.jd
@@ -0,0 +1,68 @@
+page.title=Implementing Effective Navigation
+
+trainingnavtop=true
+startpage=true
+next.title=Implementing Lateral Navigation
+next.link=lateral.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>Dependencies and prerequisites</h2>
+
+<ul>
+  <li>API level 14</li>
+  <li>Understanding of fragments and Android layouts</li>
+  <li><a href="{@docRoot}sdk/compatibility-library.html">The Android Support Package</a></li>
+  <li><a href="{@docRoot}training/design-navigation/index.html">Designing Effective Navigation</a></li>
+</ul>
+
+<h2>You should also read</h2>
+
+<ul>
+  <li><a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a></li>
+  <li><a href="{@docRoot}guide/topics/fundamentals/fragments.html">Fragments</a></li>
+  <li><a href="{@docRoot}training/multiscreen/index.html">Designing for Multiple Screens</a></li>
+</ul>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+<a href="http://developer.android.com/shareables/training/EffectiveNavigation.zip"
+  class="button">Download the sample app</a>
+<p class="filename">EffectiveNavigation.zip</p>
+</div>
+
+</div>
+</div>
+
+
+<p>This class demonstrates how to implement the key navigation design patterns detailed in the
+<a href="{@docRoot}training/design-navigation/index.html">Designing Effective Navigation</a> class.
+The lessons in this class cover implementing navigation up, down, and across your application's <a
+href="{@docRoot}training/design-navigation/screen-planning.html#diagram- relationships">screen
+map</a>.</p>
+
+<p>After reading through the lessons in this class and exploring the associated sample application
+(see right), you should also have a basic understanding of how to use
+{@link android.app.ActionBar} and {@link android.support.v4.view.ViewPager}, two components that are fundamental to core app navigation.</p>
+
+
+<h2 id="lessons">Lessons</h2>
+
+
+<dl>
+  <dt><strong><a href="lateral.html">Implementing Lateral Navigation</a></strong></dt>
+    <dd>Learn how to implement tabs and horizontal paging (swipe views).</dd>
+
+  <dt><strong><a href="ancestral.html">Implementing Ancestral Navigation</a></strong></dt>
+    <dd>Learn how to implement <em>Up</em> navigation.</dd>
+
+  <dt><strong><a href="temporal.html">Implementing Temporal Navigation</a></strong></dt>
+    <dd>Learn how to correctly handle the <em>Back</em> button.</dd>
+
+  <dt><strong><a href="descendant.html">Implementing Descendant Navigation</a></strong></dt>
+    <dd>Learn the finer points of implementing navigation into your application's information hierarchy.</dd>
+</dl>
diff --git a/docs/html/training/implementing-navigation/lateral.jd b/docs/html/training/implementing-navigation/lateral.jd
new file mode 100644
index 0000000..d9ba5c9
--- /dev/null
+++ b/docs/html/training/implementing-navigation/lateral.jd
@@ -0,0 +1,252 @@
+page.title=Implementing Lateral Navigation
+parent.title=Implementing Effective Navigation
+parent.link=index.html
+
+trainingnavtop=true
+next.title=Implementing Ancestral Navigation
+next.link=ancestral.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#tabs">Implement Tabs</a></li>
+  <li><a href="#horizontal-paging">Implement Horizontal Paging (Swipe Views)</a></li>
+  <li><a href="#swipe-tabs">Implement Swiping Between Tabs</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}training/design-navigation/descendant-lateral.html">Providing Descendant and Lateral Navigation</a></li>
+  <li><a href="{@docRoot}design/building-blocks/tabs.html">Android Design: Tabs</a></li>
+  <li><a href="{@docRoot}design/patterns/swipe-views.html">Android Design: Swipe Views</a></li>
+</ul>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+<a href="http://developer.android.com/shareables/training/EffectiveNavigation.zip"
+  class="button">Download the sample app</a>
+<p class="filename">EffectiveNavigation.zip</p>
+</div>
+
+</div>
+</div>
+
+
+<p><em>Lateral navigation</em> is navigation between sibling screens in the application's screen hierarchy (sometimes referred to as a screen map). The most prominent lateral navigation patterns are tabs and horizontal paging (also known as swipe views). This pattern and others are described in <a href="{@docRoot}training/design-navigation/descendant-lateral.html">Designing Effective Navigation</a>. This lesson covers how to implement several of the primary lateral navigation patterns in Android.</p>
+
+<h2 id="tabs">Implement Tabs</h2>
+
+<p>Tabs allow the user to navigate between sibling screens by selecting the appropriate tab indicator available at the top of the display. In Android 3.0 and later, tabs are implemented using the {@link android.app.ActionBar} class, and are generally set up in {@link android.app.Activity#onCreate Activity.onCreate()}. In some cases, such as when horizontal space is limited and/or the number of tabs is large, an appropriate alternate presentation for tabs is a dropdown list (sometimes implemented using a {@link android.widget.Spinner}).</p>
+
+<p>In previous versions of Android, tabs could be implemented using a {@link android.widget.TabWidget} and {@link android.widget.TabHost}. For details, see the <a href="{@docRoot}resources/tutorials/views/hello-tabwidget.html">Hello, Views</a> tutorial.</p>
+
+<p>As of Android 3.0, however, you should use either {@link android.app.ActionBar#NAVIGATION_MODE_TABS} or {@link android.app.ActionBar#NAVIGATION_MODE_LIST} along with the {@link android.app.ActionBar} class.</p>
+
+<h3>Implement the Tabs Pattern with NAVIGATION_MODE_TABS</h3>
+
+<p>To create tabs, you can use the following code in your activity's {@link android.app.Activity#onCreate onCreate()} method. Note that the exact presentation of tabs may vary per device and by the current device configuration, to make best use of available screen space. For example, Android may automatically collapse tabs into a dropdown list if tabs don't fit horizontally in the action bar.</p>
+
+<pre>
+{@literal @}Override
+public void onCreate(Bundle savedInstanceState) {
+    ...
+    final ActionBar actionBar = getActionBar();
+
+    // Specify that tabs should be displayed in the action bar.
+    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+
+    // Create a tab listener that is called when the user changes tabs.
+    ActionBar.TabListener tabListener = new ActionBar.TabListener() {
+        public void onTabSelected(ActionBar.Tab tab,
+                FragmentTransaction ft) { }
+
+        public void onTabUnselected(ActionBar.Tab tab,
+                FragmentTransaction ft) { }
+
+        public void onTabReselected(ActionBar.Tab tab,
+                FragmentTransaction ft) { }
+    };
+
+    // Add 3 tabs.
+    for (int i = 0; i &lt; 3; i++) {
+        actionBar.addTab(
+                actionBar.newTab()
+                        .setText("Tab " + (i + 1))
+                        .setTabListener(tabListener));
+    }
+    ...
+}
+</pre>
+
+<h3>Implement the Tabs Pattern with NAVIGATION_MODE_LIST</h3>
+
+<p>To use a dropdown list instead, use the following code in your activity's {@link android.app.Activity#onCreate onCreate()} method. Dropdown lists are often preferable in cases where more information must be shown per navigation item, such as unread message counts, or where the number of available navigation items is large.</p>
+
+<pre>
+{@literal @}Override
+public void onCreate(Bundle savedInstanceState) {
+    ...
+    final ActionBar actionBar = getActionBar();
+
+    // Specify that a dropdown list should be displayed in the action bar.
+    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
+
+    actionBar.setListNavigationCallbacks(
+            // Specify a SpinnerAdapter to populate the dropdown list.
+            new ArrayAdapter<String>(
+                    actionBar.getThemedContext(),
+                    android.R.layout.simple_list_item_1,
+                    android.R.id.text1,
+                    new String[]{ "Tab 1", "Tab 2", "Tab 3" }),
+
+            // Provide a listener to be called when an item is selected.
+            new ActionBar.OnNavigationListener() {
+                public boolean onNavigationItemSelected(
+                        int position, long id) {
+                    // Take action here, e.g. switching to the
+                    // corresponding fragment.
+                    return true;
+                }
+            });
+    ...
+}
+</pre>
+
+<h2 id="horizontal-paging">Implement Horizontal Paging (Swipe Views)</h2>
+
+<p>Horizontal paging, or swipe views, allow users to <a href="{@docRoot}design/patterns/swipe-views">swipe</a> horizontally on the current screen to navigate to adjacent screens. This pattern can be implemented using the {@link android.support.v4.view.ViewPager} widget, currently available as part of the <a href="{@docRoot}sdk/compatibility-library.html">Android Support Package</a>. For navigating between sibling screens representing a fixed number of sections, it's best to provide the {@link android.support.v4.view.ViewPager} with a {@link android.support.v4.app.FragmentPagerAdapter}. For horizontal paging across collections of objects, it's best to use a {@link android.support.v4.app.FragmentStatePagerAdapter}, which destroys fragments as the user navigates to other pages, minimizing memory usage.</p>
+
+<p>Below is an example of using a {@link android.support.v4.view.ViewPager} to swipe across a collection of objects.</p>
+
+<pre>
+public class CollectionDemoActivity extends FragmentActivity {
+    // When requested, this adapter returns a DemoObjectFragment,
+    // representing an object in the collection.
+    DemoCollectionPagerAdapter mDemoCollectionPagerAdapter;
+    ViewPager mViewPager;
+
+    public void onCreate(Bundle savedInstanceState) {
+        // ViewPager and its adapters use support library
+        // fragments, so use getSupportFragmentManager.
+        mDemoCollectionPagerAdapter =
+                new DemoCollectionPagerAdapter(
+                        getSupportFragmentManager());
+        mViewPager = (ViewPager) findViewById(R.id.pager);
+        mViewPager.setAdapter(mDemoCollectionPagerAdapter);
+    }
+}
+
+// Since this is an object collection, use a FragmentStatePagerAdapter,
+// and NOT a FragmentPagerAdapter.
+public class DemoCollectionPagerAdapter extends
+        FragmentStatePagerAdapter {
+    public DemoCollectionPagerAdapter(FragmentManager fm) {
+        super(fm);
+    }
+
+    {@literal @}Override
+    public Fragment getItem(int i) {
+        Fragment fragment = new DemoObjectFragment();
+        Bundle args = new Bundle();
+        // Our object is just an integer :-P
+        args.putInt(DemoObjectFragment.ARG_OBJECT, i + 1);
+        fragment.setArguments(args);
+        return fragment;
+    }
+
+    {@literal @}Override
+    public int getCount() {
+        return 100;
+    }
+
+    {@literal @}Override
+    public CharSequence getPageTitle(int position) {
+        return "OBJECT " + (position + 1);
+    }
+}
+
+// Instances of this class are fragments representing a single
+// object in our collection.
+public static class DemoObjectFragment extends Fragment {
+    public static final String ARG_OBJECT = "object";
+
+    {@literal @}Override
+    public View onCreateView(LayoutInflater inflater,
+            ViewGroup container, Bundle savedInstanceState) {
+        // The last two arguments ensure LayoutParams are inflated
+        // properly.
+        View rootView = inflater.inflate(
+                R.layout.fragment_collection_object, container, false);
+        Bundle args = getArguments();
+        ((TextView) rootView.findViewById(android.R.id.text1)).setText(
+                Integer.toString(args.getInt(ARG_OBJECT)));
+        return rootView;
+    }
+}
+</pre>
+
+<p>You can also add indicators to your horizontal paging UI by adding a {@link android.support.v4.view.PagerTitleStrip}. Below is an example layout XML file for an activity whose entire contents are a {@link android.support.v4.view.ViewPager} and a top-aligned {@link android.support.v4.view.PagerTitleStrip} inside it. Individual pages (provided by the adapter) occupy the remaining space inside the {@link android.support.v4.view.ViewPager}.</p>
+
+<pre>
+&lt;android.support.v4.view.ViewPager
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/pager"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"&gt;
+
+    &lt;android.support.v4.view.PagerTitleStrip
+        android:id="@+id/pager_title_strip"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="top"
+        android:background="#33b5e5"
+        android:textColor="#fff"
+        android:paddingTop="4dp"
+        android:paddingBottom="4dp" /&gt;
+
+&lt;/android.support.v4.view.ViewPager&gt;
+</pre>
+
+<h2 id="swipe-tabs">Implement Swiping Between Tabs</h2>
+
+<p>One of the key design recommendations in Android 4.0 for tabs is to <a href="{@docRoot}design/patterns/swipe-views.html">allow swiping</a> between them where appropriate. This behavior enables users to swipe horizontally across the selected tab's contents to navigate to adjacent tabs, without needed to directly interact with the tabs themselves. To implement this, you can use a {@link android.support.v4.view.ViewPager} in conjunction with the {@link android.app.ActionBar} tabs API.</p>
+
+<p>Upon observing the current page changing, select the corresponding tab. You can set up this behavior using an {@link android.support.v4.view.ViewPager.OnPageChangeListener} in your activity's {@link android.app.Activity#onCreate onCreate()} method:</p>
+
+<pre>
+{@literal @}Override
+public void onCreate(Bundle savedInstanceState) {
+    ...
+    mViewPager.setOnPageChangeListener(
+            new ViewPager.SimpleOnPageChangeListener() {
+                {@literal @}Override
+                public void onPageSelected(int position) {
+                    // When swiping between pages, select the
+                    // corresponding tab.
+                    getActionBar().setSelectedNavigationItem(position);
+                }
+            });
+    ...
+}
+</pre>
+
+<p>And upon selecting a tab, switch to the corresponding page in the {@link android.support.v4.view.ViewPager}. To do this, add an {@link android.app.ActionBar.TabListener} to your tab when creating it using the {@link android.app.ActionBar#newTab newTab()} method:</p>
+
+<pre>
+actionBar.newTab()
+        ...
+        .setTabListener(new ActionBar.TabListener() {
+            public void onTabSelected(ActionBar.Tab tab,
+                    FragmentTransaction ft) {
+                // When the tab is selected, switch to the
+                // corresponding page in the ViewPager.
+                mViewPager.setCurrentItem(tab.getPosition());
+            }
+            ...
+        }));
+</pre>
diff --git a/docs/html/training/implementing-navigation/temporal.jd b/docs/html/training/implementing-navigation/temporal.jd
new file mode 100644
index 0000000..f36991f
--- /dev/null
+++ b/docs/html/training/implementing-navigation/temporal.jd
@@ -0,0 +1,83 @@
+page.title=Implementing Temporal Navigation
+parent.title=Implementing Effective Navigation
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Implementing Ancestral Navigation
+previous.link=ancestral.html
+next.title=Implementing Descendant Navigation
+next.link=descendant.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to:</h2>
+<ol>
+  <li><a href="#back-fragments">Implement <em>Back</em> Navigation with Fragments</a></li>
+  <li><a href="#back-webviews">Implement <em>Back</em> Navigation with WebViews</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}training/design-navigation/ancestral-temporal.html">Providing Ancestral and Temporal Navigation</a></li>
+  <li><a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back Stack</a></li>
+  <li><a href="{@docRoot}design/patterns/navigation.html">Android Design: Navigation</a></li>
+</ul>
+
+</div>
+</div>
+
+
+<p><em>Temporal navigation</em> is navigation to previously visited screens. Users can visit previous screens by pressing the device <em>Back</em> button. This user interface pattern is described further in <a href="{@docRoot}training/design-navigation/ancestral-temporal.html">Providing Ancestral and Temporal Navigation</a> in <em>Designing Effective Navigation</em> and in <a href="{@docRoot}design/patterns/navigation.html">Android Design: Navigation</a>.</p>
+
+<p>Android handles basic <em>Back</em> navigation for you (see <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back Stack</a> for details on this behavior). This lesson discusses a number of cases where applications should provide specialized logic for the <em>Back</em> button.</p>
+
+
+<h2 id="back-fragments">Implement <em>Back</em> Navigation with Fragments</h2>
+
+<p>When using fragments in your application, individual {@link android.app.FragmentTransaction} objects can represent context changes that should be added to the back stack. For example, if you are implementing a <a href="descendant.html#master-detail">master/detail flow</a> on a handset by swapping out fragments (thus emulating a {@link android.app.Activity#startActivity startActivity()} call), you should ensure that pressing the <em>Back</em> button on a detail screen returns the user to the master screen. To do so, you can use {@link android.app.FragmentTransaction#addToBackStack addToBackStack()}:</p>
+
+<pre>
+// Works with either the framework FragmentManager or the
+// support package FragmentManager (getSupportFragmentManager).
+getFragmentManager().beginTransaction()
+        .add(detailFragment, "detail")
+
+        // Add this transaction to the back stack and commit.
+        .addToBackStack()
+        .commit();
+</pre>
+
+<p>The activity's {@link android.app.FragmentManager} handles <em>Back</em> button presses if there are {@link android.app.FragmentTransaction} objects on the back stack. When this happens, the {@link android.app.FragmentManager} pops the most recent transaction off the back stack and performs the reverse action (e.g., removing a fragment if the transaction added it).</p>
+
+<p>If your application updates other user interface elements to reflect the current state of your fragments, such as the action bar, remember to update the UI when you commit the transaction. You should update your user interface after the fragment manager back stack changes in addition to when you commit the transaction. You can listen for when a <code>FragmentTransaction</code> is reverted by setting up an {@link android.app.FragmentManager.OnBackStackChangedListener}:</p>
+
+<pre>
+getFragmentManager().addOnBackStackChangedListener(
+        new FragmentManager.OnBackStackChangedListener() {
+            public void onBackStackChanged() {
+                // Update your UI here.
+            }
+        });
+</pre>
+
+<h2 id="back-webviews">Implement <em>Back</em> Navigation with WebViews</h2>
+
+<p>If a part of your application is contained in a {@link android.webkit.WebView}, it may be appropriate for <em>Back</em> to traverse browser history. To do so, you can override {@link android.app.Activity#onBackPressed onBackPressed()} and proxy to the <code>WebView</code> if it has history state:</p>
+
+<pre>
+{@literal @}Override
+public void onBackPressed() {
+    if (mWebView.canGoBack()) {
+        mWebView.goBack();
+        return;
+    }
+
+    // Otherwise defer to system default behavior.
+    super.onBackPressed();
+}
+</pre>
+
+<p>Be careful when using this mechanism with highly dynamic web pages that can grow a large history. Pages that generate an extensive history, such as those that make frequent changes to the document hash, may make it tedious for users to get out of your activity.</p>
diff --git a/docs/html/training/location/locationmanager.jd b/docs/html/training/location/locationmanager.jd
index 5da1205..61abcbd 100644
--- a/docs/html/training/location/locationmanager.jd
+++ b/docs/html/training/location/locationmanager.jd
@@ -18,6 +18,7 @@
   <li><a href="locationmanager.html#TaskDeclarePermissions">Declare Proper Permissions in Android Manifest</a></li>
   <li><a href="locationmanager.html#TaskGetLocationManagerRef">Get a Reference to LocationManager</a></li>
   <li><a href="locationmanager.html#TaskPickLocationProvider">Pick a Location Provider</a></li>
+  <li><a href="locationmanager.html#TaskVerifyProvider">Verify the Location Provider is Enabled</a></li>
 </ol>
 
 <h2>You should also read</h2>
@@ -88,3 +89,32 @@
    ...
 }
 </pre>
+
+<h2 id="TaskVerifyProvider">Verify the Location Provider is Enabled</h2>
+
+<p>Some location providers such as the GPS can be disabled in Settings.  It is good practice to check whether the desired location provider is currently enabled by calling the {@link android.location.LocationManager#isProviderEnabled(java.lang.String) isProviderEnabled()} method.  If the location provider is disabled, you can offer the user an opportunity to enable it in Settings by firing an {@link android.content.Intent} with the {@link android.provider.Settings#ACTION_LOCATION_SOURCE_SETTINGS} action.</p>
+
+<pre>
+&#64;Override
+protected void onStart() {
+    super.onStart();
+
+    // This verification should be done during onStart() because the system calls
+    // this method when the user returns to the activity, which ensures the desired
+    // location provider is enabled each time the activity resumes from the stopped state.
+    LocationManager locationManager =
+            (LocationManager) getSystemService(Context.LOCATION_SERVICE);
+    final boolean gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
+
+    if (!gpsEnabled) {
+        // Build an alert dialog here that requests that the user enable
+        // the location services, then when the user clicks the "OK" button,
+        // call enableLocationSettings()
+    }
+}
+
+private void enableLocationSettings() {
+    Intent settingsIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
+    startActivity(settingsIntent);
+}
+</pre>
diff --git a/graphics/java/android/graphics/Insets.java b/graphics/java/android/graphics/Insets.java
new file mode 100644
index 0000000..c570cd4
--- /dev/null
+++ b/graphics/java/android/graphics/Insets.java
@@ -0,0 +1,114 @@
+/*
+ * 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;
+
+/**
+ * An Insets instance holds four integer offsets which describe changes to the four
+ * edges of a Rectangle. By convention, positive values move edges towards the
+ * centre of the rectangle.
+ * <p>
+ * Insets are immutable so may be treated as values.
+ *
+ * @hide
+ */
+public class Insets {
+    public static final Insets NONE = new Insets(0, 0, 0, 0);
+
+    public final int left;
+    public final int top;
+    public final int right;
+    public final int bottom;
+
+    private Insets(int left, int top, int right, int bottom) {
+        this.left = left;
+        this.top = top;
+        this.right = right;
+        this.bottom = bottom;
+    }
+
+    // Factory methods
+
+    /**
+     * Return an Insets instance with the appropriate values.
+     *
+     * @param left the left inset
+     * @param top the top inset
+     * @param right the right inset
+     * @param bottom the bottom inset
+     *
+     * @return Insets instance with the appropriate values
+     */
+    public static Insets of(int left, int top, int right, int bottom) {
+        if (left == 0 && top == 0 && right == 0 && bottom == 0) {
+            return NONE;
+        }
+        return new Insets(left, top, right, bottom);
+    }
+
+    /**
+     * Return an Insets instance with the appropriate values.
+     *
+     * @param r the rectangle from which to take the values
+     *
+     * @return an Insets instance with the appropriate values
+     */
+    public static Insets of(Rect r) {
+        return of(r.left, r.top, r.right, r.bottom);
+    }
+
+    /**
+     * Two Insets instances are equal iff they belong to the same class and their fields are
+     * pairwise equal.
+     *
+     * @param o the object to compare this instance with.
+     *
+     * @return true iff this object is equal {@code o}
+     */
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Insets insets = (Insets) o;
+
+        if (bottom != insets.bottom) return false;
+        if (left != insets.left) return false;
+        if (right != insets.right) return false;
+        if (top != insets.top) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = left;
+        result = 31 * result + top;
+        result = 31 * result + right;
+        result = 31 * result + bottom;
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "Insets{" +
+                "left=" + left +
+                ", top=" + top +
+                ", right=" + right +
+                ", bottom=" + bottom +
+                '}';
+    }
+}
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index e101581..4beaecd 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -155,21 +155,23 @@
 
     /**
      * Update the texture image to the most recent frame from the image stream.  This may only be
-     * called while the OpenGL ES context that owns the texture is bound to the thread.  It will
-     * implicitly bind its texture to the GL_TEXTURE_EXTERNAL_OES texture target.
+     * called while the OpenGL ES context that owns the texture is current on the calling thread.
+     * It will implicitly bind its texture to the GL_TEXTURE_EXTERNAL_OES texture target.
      */
     public void updateTexImage() {
-        int err = nativeUpdateTexImage(); 
-        if (err != 0) {
-            throw new RuntimeException("Error during updateTexImage (see logcat for details)");
-        }
+        nativeUpdateTexImage();
     }
 
     /**
-     * Detach the SurfaceTexture from the OpenGL ES context with which it is currently associated.
-     * This can be used to change from one OpenGL ES context to another.
+     * 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
+     * calls to {@link #updateTexImage} will throw an {@link java.lang.IllegalStateException} until
+     * a successful call to {@link #attachToGLContext} is made.
      *
-     * @hide
+     * This can be used to access the SurfaceTexture image contents from multiple OpenGL ES
+     * contexts.  Note, however, that the image contents are only accessible from one OpenGL ES
+     * context at a time.
      */
     public void detachFromGLContext() {
         int err = nativeDetachFromGLContext();
@@ -179,8 +181,17 @@
     }
 
     /**
+     * Attach the SurfaceTexture to the OpenGL ES context that is current on the calling thread.  A
+     * new OpenGL ES texture object is created and populated with the SurfaceTexture image frame
+     * that was current at the time of the last call to {@link #detachFromGLContext}.  This new
+     * texture is bound to the GL_TEXTURE_EXTERNAL_OES texture target.
      *
-     * @hide
+     * This can be used to access the SurfaceTexture image contents from multiple OpenGL ES
+     * contexts.  Note, however, that the image contents are only accessible from one OpenGL ES
+     * context at a time.
+     *
+     * @param texName The name of the OpenGL ES texture that will be created.  This texture name
+     * must be unusued in the OpenGL ES context that is current on the calling thread.
      */
     public void attachToGLContext(int texName) {
         int err = nativeAttachToGLContext(texName);
@@ -292,7 +303,7 @@
     private native void nativeGetTransformMatrix(float[] mtx);
     private native long nativeGetTimestamp();
     private native void nativeSetDefaultBufferSize(int width, int height);
-    private native int nativeUpdateTexImage();
+    private native void nativeUpdateTexImage();
     private native int nativeDetachFromGLContext();
     private native int nativeAttachToGLContext(int texName);
     private native int nativeGetQueuedCount();
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 86e824b..7d1942a 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -705,6 +705,20 @@
     }
 
     /**
+     * Return in insets the layout insets suggested by this Drawable for use with alignment
+     * operations during layout. Positive values move toward the
+     * center of the Drawable. Returns true if this drawable
+     * actually has a layout insets, else false. When false is returned, the padding
+     * is always set to 0.
+     *
+     * @hide
+     */
+    public boolean getLayoutInsets(Rect insets) {
+        insets.set(0, 0, 0, 0);
+        return false;
+    }
+
+    /**
      * Make this drawable mutable. This operation cannot be reversed. A mutable
      * drawable is guaranteed to not share its state with any other drawable.
      * This is especially useful when you need to modify properties of drawables
@@ -965,9 +979,7 @@
             Rect pad, Rect layoutBounds, String srcName) {
 
         if (np != null) {
-            NinePatchDrawable npd = new NinePatchDrawable(res, bm, np, pad, srcName);
-            npd.setLayoutBounds(layoutBounds);
-            return npd;
+            return new NinePatchDrawable(res, bm, np, pad, layoutBounds, srcName);
         }
 
         return new BitmapDrawable(res, bm);
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index b0f7fd3..e10f9e8 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -90,6 +90,18 @@
         }
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    public boolean getLayoutInsets(Rect insets) {
+        if (mCurrDrawable != null) {
+            return mCurrDrawable.getLayoutInsets(insets);
+        } else {
+            return super.getLayoutInsets(insets);
+        }
+    }
+
     @Override
     public void setAlpha(int alpha) {
         if (mAlpha != alpha) {
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 1272071..e502b7a 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -16,9 +16,17 @@
 
 package android.graphics.drawable;
 
-import android.graphics.*;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.NinePatch;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.Region;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.TypedValue;
@@ -29,7 +37,7 @@
 import java.io.InputStream;
 
 /**
- * 
+ *
  * A resizeable bitmap, with stretchable areas that you define. This type of image
  * is defined in a .png file with a special format.
  *
@@ -47,7 +55,6 @@
     private NinePatchState mNinePatchState;
     private NinePatch mNinePatch;
     private Rect mPadding;
-    private Rect mLayoutBounds;
     private Paint mPaint;
     private boolean mMutated;
 
@@ -56,7 +63,7 @@
     // These are scaled to match the target density.
     private int mBitmapWidth;
     private int mBitmapHeight;
-    
+
     NinePatchDrawable() {
     }
 
@@ -69,7 +76,7 @@
     public NinePatchDrawable(Bitmap bitmap, byte[] chunk, Rect padding, String srcName) {
         this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), null);
     }
-    
+
     /**
      * Create drawable from raw nine-patch data, setting initial target density
      * based on the display metrics of the resources.
@@ -79,7 +86,19 @@
         this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), res);
         mNinePatchState.mTargetDensity = mTargetDensity;
     }
-    
+
+    /**
+     * Create drawable from raw nine-patch data, setting initial target density
+     * based on the display metrics of the resources.
+     *
+     * @hide
+     */
+    public NinePatchDrawable(Resources res, Bitmap bitmap, byte[] chunk,
+            Rect padding, Rect layoutInsets, String srcName) {
+        this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding, layoutInsets), res);
+        mNinePatchState.mTargetDensity = mTargetDensity;
+    }
+
     /**
      * Create drawable from existing nine-patch, not dealing with density.
      * @deprecated Use {@link #NinePatchDrawable(Resources, NinePatch)}
@@ -99,13 +118,6 @@
         mNinePatchState.mTargetDensity = mTargetDensity;
     }
 
-    /**
-     * @hide
-     */
-    void setLayoutBounds(Rect layoutBounds) {
-        mLayoutBounds = layoutBounds;
-    }
-
     private void setNinePatchState(NinePatchState state, Resources res) {
         mNinePatchState = state;
         mNinePatch = state.mNinePatch;
@@ -201,13 +213,26 @@
     public int getChangingConfigurations() {
         return super.getChangingConfigurations() | mNinePatchState.mChangingConfigurations;
     }
-    
+
     @Override
     public boolean getPadding(Rect padding) {
         padding.set(mPadding);
         return true;
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    public boolean getLayoutInsets(Rect insets) {
+        Rect layoutInsets = mNinePatchState.mLayoutInsets;
+        if (layoutInsets == null) {
+            return super.getLayoutInsets(insets);
+        }
+        insets.set(layoutInsets);
+        return true;
+    }
+
     @Override
     public void setAlpha(int alpha) {
         if (mPaint == null && alpha == 0xFF) {
@@ -217,7 +242,7 @@
         getPaint().setAlpha(alpha);
         invalidateSelf();
     }
-    
+
     @Override
     public void setColorFilter(ColorFilter cf) {
         if (mPaint == null && cf == null) {
@@ -267,6 +292,7 @@
         options.inScreenDensity = DisplayMetrics.DENSITY_DEVICE;
 
         final Rect padding = new Rect();
+        final Rect layoutInsets = new Rect();
         Bitmap bitmap = null;
 
         try {
@@ -290,7 +316,7 @@
 
         setNinePatchState(new NinePatchState(
                 new NinePatch(bitmap, bitmap.getNinePatchChunk(), "XML 9-patch"),
-                padding, dither), r);
+                padding, layoutInsets, dither), r);
         mNinePatchState.mTargetDensity = mTargetDensity;
 
         a.recycle();
@@ -344,7 +370,7 @@
     public Region getTransparentRegion() {
         return mNinePatch.getTransparentRegion(getBounds());
     }
-    
+
     @Override
     public ConstantState getConstantState() {
         mNinePatchState.mChangingConfigurations = getChangingConfigurations();
@@ -361,27 +387,36 @@
         return this;
     }
 
-    final static class NinePatchState extends ConstantState {
+    private final static class NinePatchState extends ConstantState {
         final NinePatch mNinePatch;
         final Rect mPadding;
+        final Rect mLayoutInsets;
         final boolean mDither;
         int mChangingConfigurations;
         int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
 
         NinePatchState(NinePatch ninePatch, Rect padding) {
-            this(ninePatch, padding, DEFAULT_DITHER);
+            this(ninePatch, padding, new Rect(), DEFAULT_DITHER);
         }
 
-        NinePatchState(NinePatch ninePatch, Rect rect, boolean dither) {
+        NinePatchState(NinePatch ninePatch, Rect padding, Rect layoutInsets) {
+            this(ninePatch, padding, layoutInsets, DEFAULT_DITHER);
+        }
+
+        NinePatchState(NinePatch ninePatch, Rect rect, Rect layoutInsets, boolean dither) {
             mNinePatch = ninePatch;
             mPadding = rect;
+            mLayoutInsets = layoutInsets;
             mDither = dither;
         }
 
+        // Copy constructor
+
         NinePatchState(NinePatchState state) {
             mNinePatch = new NinePatch(state.mNinePatch);
             // Note we don't copy the padding because it is immutable.
             mPadding = state.mPadding;
+            mLayoutInsets = state.mLayoutInsets;
             mDither = state.mDither;
             mChangingConfigurations = state.mChangingConfigurations;
             mTargetDensity = state.mTargetDensity;
@@ -391,12 +426,12 @@
         public Drawable newDrawable() {
             return new NinePatchDrawable(this, null);
         }
-        
+
         @Override
         public Drawable newDrawable(Resources res) {
             return new NinePatchDrawable(this, res);
         }
-        
+
         @Override
         public int getChangingConfigurations() {
             return mChangingConfigurations;
diff --git a/include/androidfw/InputDevice.h b/include/androidfw/InputDevice.h
index 2eac544..38203af 100644
--- a/include/androidfw/InputDevice.h
+++ b/include/androidfw/InputDevice.h
@@ -93,6 +93,9 @@
         return mKeyCharacterMap;
     }
 
+    inline void setVibrator(bool hasVibrator) { mHasVibrator = hasVibrator; }
+    inline bool hasVibrator() const { return mHasVibrator; }
+
     inline const Vector<MotionRange>& getMotionRanges() const {
         return mMotionRanges;
     }
@@ -105,6 +108,7 @@
     uint32_t mSources;
     int32_t mKeyboardType;
     sp<KeyCharacterMap> mKeyCharacterMap;
+    bool mHasVibrator;
 
     Vector<MotionRange> mMotionRanges;
 };
diff --git a/include/androidfw/KeyCharacterMap.h b/include/androidfw/KeyCharacterMap.h
index 3cc1cb2..8db5781 100644
--- a/include/androidfw/KeyCharacterMap.h
+++ b/include/androidfw/KeyCharacterMap.h
@@ -49,6 +49,17 @@
         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.
@@ -58,7 +69,15 @@
     };
 
     /* Loads a key character map from a file. */
-    static status_t load(const String8& filename, sp<KeyCharacterMap>* outMap);
+    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();
@@ -101,6 +120,10 @@
     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);
@@ -115,6 +138,7 @@
 private:
     struct Behavior {
         Behavior();
+        Behavior(const Behavior& other);
 
         /* The next behavior in the list, or NULL if none. */
         Behavior* next;
@@ -131,6 +155,7 @@
 
     struct Key {
         Key();
+        Key(const Key& other);
         ~Key();
 
         /* The single character label printed on the key, or 0 if none. */
@@ -166,16 +191,19 @@
 
         KeyCharacterMap* mMap;
         Tokenizer* mTokenizer;
+        Format mFormat;
         State mState;
         int32_t mKeyCode;
 
     public:
-        Parser(KeyCharacterMap* map, Tokenizer* tokenizer);
+        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 parseModifier(const String8& token, int32_t* outMetaState);
@@ -187,7 +215,11 @@
     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,
@@ -195,6 +227,8 @@
 
     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,
diff --git a/include/utils/Trace.h b/include/utils/Trace.h
new file mode 100644
index 0000000..a0112d0
--- /dev/null
+++ b/include/utils/Trace.h
@@ -0,0 +1,43 @@
+/*
+ * 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 ANDROID_TRACE_H
+#define ANDROID_TRACE_H
+
+#define ATRACE_TAG_NEVER    0           // The "never" tag is never enabled.
+#define ATRACE_TAG_ALWAYS   (1<<0)      // The "always" tag is always enabled.
+#define ATRACE_TAG_GRAPHICS (1<<1)
+#define ATRACE_TAG_INPUT    (1<<2)
+#define ATRACE_TAG_VIEW     (1<<3)
+#define ATRACE_TAG_WEBVIEW  (1<<4)
+
+#define ATRACE_CALL()
+
+#define ATRACE_INT(name, value)
+
+#define ATRACE_ENABLED() false
+
+namespace android {
+
+class ScopedTrace {
+
+public:
+    inline ScopedTrace(uint64_t tag, const char* name) {}
+};
+
+}; // namespace android
+
+#endif // ANDROID_TRACE_H
diff --git a/libs/androidfw/InputDevice.cpp b/libs/androidfw/InputDevice.cpp
index 6bb06a9..d6c49f7 100644
--- a/libs/androidfw/InputDevice.cpp
+++ b/libs/androidfw/InputDevice.cpp
@@ -136,6 +136,7 @@
         mSources(other.mSources),
         mKeyboardType(other.mKeyboardType),
         mKeyCharacterMap(other.mKeyCharacterMap),
+        mHasVibrator(other.mHasVibrator),
         mMotionRanges(other.mMotionRanges) {
 }
 
@@ -150,6 +151,7 @@
     mDescriptor = descriptor;
     mSources = 0;
     mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE;
+    mHasVibrator = false;
     mMotionRanges.clear();
 }
 
diff --git a/libs/androidfw/KeyCharacterMap.cpp b/libs/androidfw/KeyCharacterMap.cpp
index 9abbf38..c8f9439 100644
--- a/libs/androidfw/KeyCharacterMap.cpp
+++ b/libs/androidfw/KeyCharacterMap.cpp
@@ -89,6 +89,14 @@
     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);
@@ -96,7 +104,8 @@
     }
 }
 
-status_t KeyCharacterMap::load(const String8& filename, sp<KeyCharacterMap>* outMap) {
+status_t KeyCharacterMap::load(const String8& filename,
+        Format format, sp<KeyCharacterMap>* outMap) {
     outMap->clear();
 
     Tokenizer* tokenizer;
@@ -104,31 +113,87 @@
     if (status) {
         ALOGE("Error %d opening key character map file %s.", status, filename.string());
     } else {
-        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);
-            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;
-            }
-        }
+        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;
 }
@@ -261,6 +326,37 @@
     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) {
@@ -508,6 +604,11 @@
         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) {
@@ -524,11 +625,17 @@
         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) :
-        mMap(map), mTokenizer(tokenizer), mState(STATE_TOP) {
+KeyCharacterMap::Parser::Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format) :
+        mMap(map), mTokenizer(tokenizer), mFormat(format), mState(STATE_TOP) {
 }
 
 KeyCharacterMap::Parser::~Parser() {
@@ -551,6 +658,10 @@
                     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();
@@ -588,10 +699,24 @@
         return BAD_VALUE;
     }
 
-    if (mMap->mType == KEYBOARD_TYPE_UNKNOWN) {
-        ALOGE("%s: Missing required keyboard 'type' declaration.",
-                mTokenizer->getLocation().string());
-        return BAD_VALUE;
+    if (mFormat == FORMAT_BASE) {
+        if (mMap->mType == KEYBOARD_TYPE_UNKNOWN) {
+            ALOGE("%s: Base keyboard layout missing required keyboard 'type' declaration.",
+                    mTokenizer->getLocation().string());
+            return BAD_VALUE;
+        }
+        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;
@@ -616,6 +741,8 @@
         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());
@@ -629,6 +756,58 @@
     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());
diff --git a/libs/androidfw/KeyLayoutMap.cpp b/libs/androidfw/KeyLayoutMap.cpp
index a7c2199..2db19c5 100644
--- a/libs/androidfw/KeyLayoutMap.cpp
+++ b/libs/androidfw/KeyLayoutMap.cpp
@@ -199,17 +199,26 @@
 }
 
 status_t KeyLayoutMap::Parser::parseKey() {
-    String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE);
+    String8 codeToken = mTokenizer->nextToken(WHITESPACE);
+    bool mapUsage = false;
+    if (codeToken == "usage") {
+        mapUsage = true;
+        mTokenizer->skipDelimiters(WHITESPACE);
+        codeToken = mTokenizer->nextToken(WHITESPACE);
+    }
+
     char* end;
-    int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0));
+    int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
     if (*end) {
-        ALOGE("%s: Expected key scan code number, got '%s'.", mTokenizer->getLocation().string(),
-                scanCodeToken.string());
+        ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(),
+                mapUsage ? "usage" : "scan code", codeToken.string());
         return BAD_VALUE;
     }
-    if (mMap->mKeysByScanCode.indexOfKey(scanCode) >= 0) {
-        ALOGE("%s: Duplicate entry for key scan code '%s'.", mTokenizer->getLocation().string(),
-                scanCodeToken.string());
+    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;
     }
 
@@ -243,12 +252,13 @@
     }
 
 #if DEBUG_PARSER
-    ALOGD("Parsed key: scanCode=%d, keyCode=%d, flags=0x%08x.", scanCode, keyCode, flags);
+    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;
-    mMap->mKeysByScanCode.add(scanCode, key);
+    map.add(code, key);
     return NO_ERROR;
 }
 
diff --git a/libs/androidfw/Keyboard.cpp b/libs/androidfw/Keyboard.cpp
index a84a8c7..4ddbeab 100644
--- a/libs/androidfw/Keyboard.cpp
+++ b/libs/androidfw/Keyboard.cpp
@@ -129,7 +129,8 @@
         return NAME_NOT_FOUND;
     }
 
-    status_t status = KeyCharacterMap::load(path, &keyCharacterMap);
+    status_t status = KeyCharacterMap::load(path,
+            KeyCharacterMap::FORMAT_BASE, &keyCharacterMap);
     if (status) {
         return status;
     }
diff --git a/media/java/android/media/Crypto.java b/media/java/android/media/Crypto.java
deleted file mode 100644
index 43e34fb..0000000
--- a/media/java/android/media/Crypto.java
+++ /dev/null
@@ -1,49 +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 android.media;
-
-/**
- * Crypto class can be used in conjunction with MediaCodec to decode
- * encrypted media data.
- * @hide
-*/
-public final class Crypto {
-    public static final native boolean isCryptoSchemeSupported(byte[] uuid);
-
-    public Crypto(byte[] uuid, byte[] initData) {
-        native_setup(uuid, initData);
-    }
-
-    public final native boolean requiresSecureDecoderComponent(String mime);
-
-    @Override
-    protected void finalize() {
-        native_finalize();
-    }
-
-    public native final void release();
-    private static native final void native_init();
-    private native final void native_setup(byte[] uuid, byte[] initData);
-    private native final void native_finalize();
-
-    static {
-        System.loadLibrary("media_jni");
-        native_init();
-    }
-
-    private int mNativeContext;
-}
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 410383d..a65c2aa 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -16,7 +16,7 @@
 
 package android.media;
 
-import android.media.Crypto;
+import android.media.MediaCrypto;
 import android.view.Surface;
 import java.nio.ByteBuffer;
 import java.util.Map;
@@ -24,7 +24,122 @@
 /**
  * MediaCodec class can be used to access low-level media codec, i.e.
  * encoder/decoder components.
- * @hide
+ *
+ * <p>MediaCodec is generally used like this:
+ * <pre>
+ * MediaCodec codec = MediaCodec.createDecoderByType(type);
+ * codec.configure(format, ...);
+ * codec.start();
+ * ByteBuffer[] inputBuffers = codec.getInputBuffers();
+ * ByteBuffer[] outputBuffers = codec.getOutputBuffers();
+ * Map<String, Object> format = codec.getOutputFormat();
+ * for (;;) {
+ *   int inputBufferIndex = codec.dequeueInputBuffer(timeoutUs);
+ *   if (inputBufferIndex &gt;= 0) {
+ *     // fill inputBuffers[inputBufferIndex] with valid data
+ *     ...
+ *     codec.queueInputBuffer(inputBufferIndex, ...);
+ *   }
+ *
+ *   int outputBufferIndex = codec.dequeueOutputBuffer(timeoutUs);
+ *   if (outputBufferIndex &gt;= 0) {
+ *     // outputBuffer is ready to be processed or rendered.
+ *     ...
+ *     codec.releaseOutputBuffer(outputBufferIndex, ...);
+ *   } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
+ *     outputBuffers = codec.getOutputBuffers();
+ *   } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+ *     // Subsequent data will conform to new format.
+ *     format = codec.getOutputFormat();
+ *     ...
+ *   }
+ * }
+ * codec.stop();
+ * codec.release();
+ * codec = null;
+ * </pre>
+ *
+ * Each codec maintains a number of input and output buffers that are
+ * referred to by index in API calls.
+ * The contents of these buffers is represented by the ByteBuffer[] arrays
+ * accessible through getInputBuffers() and getOutputBuffers().
+ *
+ * After a successful call to {@link #start} the client "owns" neither
+ * input nor output buffers, subsequent calls to {@link #dequeueInputBuffer}
+ * and {@link #dequeueOutputBuffer} then transfer ownership from the codec
+ * to the client.<p>
+ * The client is not required to resubmit/release buffers immediately
+ * to the codec, the sample code above simply does this for simplicity's sake.<p>
+ * Once the client has an input buffer available it can fill it with data
+ * and submit it it to the codec via a call to {@link #queueInputBuffer}.<p>
+ * The codec in turn will return an output buffer to the client in response
+ * to {@link #dequeueOutputBuffer}. After the output buffer has been processed
+ * a call to {@link #releaseOutputBuffer} will return it to the codec.
+ * If a video surface has been provided in the call to {@link #configure},
+ * {@link #releaseOutputBuffer} optionally allows rendering of the buffer
+ * to the surface.<p>
+ *
+ * Input buffers (for decoders) and Output buffers (for encoders) contain
+ * encoded data according to the format's type. For video types this data
+ * is all the encoded data representing a single moment in time, for audio
+ * data this is slightly relaxed in that a buffer may contain multiple
+ * encoded frames of audio. In either case, buffers do not start and end on
+ * arbitrary byte boundaries, this is not a stream of bytes, it's a stream
+ * of access units.<p>
+ *
+ * Most formats also require the actual data to be prefixed by a number
+ * of buffers containing setup data, or codec specific data, i.e. the
+ * first few buffers submitted to the codec object after starting it must
+ * be codec specific data marked as such using the flag {@link #FLAG_CODECCONFIG}
+ * in a call to {@link #queueInputBuffer}.
+ *
+ * Once the client reaches the end of the input data it signals the end of
+ * the input stream by specifying a flag of {@link #FLAG_EOS} in the call to
+ * {@link #queueInputBuffer}. The codec will continue to return output buffers
+ * until it eventually signals the end of the output stream by specifying
+ * the same flag ({@link #FLAG_EOS}) on the BufferInfo returned in
+ * {@link #dequeueOutputBuffer}.
+ *
+ * In order to start decoding data that's not adjacent to previously submitted
+ * data (i.e. after a seek) it is necessary to {@link #flush} the decoder.
+ * Any input or output buffers the client may own at the point of the flush are
+ * immediately revoked, i.e. after a call to {@link #flush} the client does not
+ * own any buffers anymore.
+ * Note that the format of the data submitted after a flush must not change,
+ * flush does not support format discontinuities,
+ * for this a full stop(), configure(), start() cycle is necessary.
+ *
+ * The format of the media data is specified as string/value pairs represented
+ * as a Map<String, Object>.<p>
+ *
+ * Fields common to all formats:
+ *
+ * <table>
+ * <tr><th>Name</th><th>Value Type</th><th>Description</th></tr>
+ * <tr><td>mime</td><td>String</td><td>The type of the format.</td></tr>
+ * <tr><td>max-input-size</td><td>Integer</td><td>optional, maximum size of a buffer of input data</td></tr>
+ * <tr><td>bitrate</td><td>Integer</td><td><b>encoder-only</b>, desired bitrate in bits/second</td></tr>
+ * </table>
+ *
+ * Video formats have the following fields:
+ * <table>
+ * <tr><th>Name</th><th>Value Type</th><th>Description</th></tr>
+ * <tr><td>width</td><td>Integer</td><td></td></tr>
+ * <tr><td>height</td><td>Integer</td><td></td></tr>
+ * <tr><td>color-format</td><td>Integer</td><td><b>encoder-only</b></td></tr>
+ * <tr><td>frame-rate</td><td>Integer or Float</td><td><b>encoder-only</b></td></tr>
+ * <tr><td>i-frame-interval</td><td>Integer</td><td><b>encoder-only</b></td></tr>
+ * <tr><td>stride</td><td>Integer</td><td><b>encoder-only</b>, optional, defaults to width</td></tr>
+ * <tr><td>slice-height</td><td>Integer</td><td><b>encoder-only</b>, optional, defaults to height</td></tr>
+ * </table>
+ *
+ * Audio formats have the following fields:
+ * <table>
+ * <tr><th>Name</th><th>Value Type</th><th>Description</th></tr>
+ * <tr><td>channel-count</td><td>Integer</td><td></td></tr>
+ * <tr><td>sample-rate</td><td>Integer</td><td></td></tr>
+ * </table>
+ *
 */
 final public class MediaCodec {
     /** Per buffer metadata includes an offset and size specifying
@@ -32,43 +147,62 @@
     */
     public final static class BufferInfo {
         public void set(
-                int offset, int size, long timeUs, int flags) {
-            mOffset = offset;
-            mSize = size;
-            mPresentationTimeUs = timeUs;
-            mFlags = flags;
+                int newOffset, int newSize, long newTimeUs, int newFlags) {
+            offset = newOffset;
+            size = newSize;
+            presentationTimeUs = newTimeUs;
+            flags = newFlags;
         }
 
-        public int mOffset;
-        public int mSize;
-        public long mPresentationTimeUs;
-        public int mFlags;
+        public int offset;
+        public int size;
+        public long presentationTimeUs;
+        public int flags;
     };
 
     // The follow flag constants MUST stay in sync with their equivalents
     // in MediaCodec.h !
-    public static int FLAG_SYNCFRAME   = 1;
-    public static int FLAG_CODECCONFIG = 2;
-    public static int FLAG_EOS         = 4;
+
+    /** This indicates that the buffer marked as such contains the data
+        for a sync frame.
+    */
+    public static final int FLAG_SYNCFRAME   = 1;
+
+    /** This indicated that the buffer marked as such contains codec
+        initialization / codec specific data instead of media data.
+    */
+    public static final int FLAG_CODECCONFIG = 2;
+
+    /** This signals the end of stream, i.e. no buffers will be available
+        after this, unless of course, {@link #flush} follows.
+    */
+    public static final int FLAG_EOS         = 4;
 
     // The following mode constants MUST stay in sync with their equivalents
     // in media/hardware/CryptoAPI.h !
-    public static int MODE_UNENCRYPTED = 0;
-    public static int MODE_AES_CTR     = 1;
+    public static final int MODE_UNENCRYPTED = 0;
+    public static final int MODE_AES_CTR     = 1;
 
-    /** Instantiate a codec component by mime type. For decoder components
-        this is the mime type of media that this decoder should be able to
-        decoder, for encoder components it's the type of media this encoder
-        should encode _to_.
+    /** Instantiate a decoder supporting input data of the given mime type.
+      * @param type The mime type of the input data.
     */
-    public static MediaCodec CreateByType(String type, boolean encoder) {
-        return new MediaCodec(type, true /* nameIsType */, encoder);
+    public static MediaCodec createDecoderByType(String type) {
+        return new MediaCodec(type, true /* nameIsType */, false /* encoder */);
+    }
+
+    /** Instantiate an encoder supporting output data of the given mime type.
+      * @param type The desired mime type of the output data.
+    */
+    public static MediaCodec createEncoderByType(String type) {
+        return new MediaCodec(type, true /* nameIsType */, true /* encoder */);
     }
 
     /** If you know the exact name of the component you want to instantiate
         use this method to instantiate it. Use with caution.
+        Likely to be used with information obtained from {@link android.media.MediaCodecList}
+        @param name The name of the codec to be instantiated.
     */
-    public static MediaCodec CreateByComponentName(String name) {
+    public static MediaCodec createByCodecName(String name) {
         return new MediaCodec(
                 name, false /* nameIsType */, false /* unused */);
     }
@@ -88,35 +222,14 @@
     // to do this for you at some point in the future.
     public native final void release();
 
+    /** If this codec is to be used as an encoder, pass this flag.
+      */
     public static int CONFIGURE_FLAG_ENCODE = 1;
 
     /** Configures a component.
-     *  @param format A map of string/value pairs describing the input format
-     *                (decoder) or the desired output format.
      *
-     *                Video formats have the following fields:
-     *                  "mime"          - String
-     *                  "width"         - Integer
-     *                  "height"        - Integer
-     *                  optional "max-input-size"       - Integer
-     *
-     *                Audio formats have the following fields:
-     *                  "mime"          - String
-     *                  "channel-count" - Integer
-     *                  "sample-rate"   - Integer
-     *                  optional "max-input-size"       - Integer
-     *
-     *                If the format is used to configure an encoder, additional
-     *                fields must be included:
-     *                  "bitrate" - Integer (in bits/sec)
-     *
-     *                for video formats:
-     *                  "color-format"          - Integer
-     *                  "frame-rate"            - Integer or Float
-     *                  "i-frame-interval"      - Integer
-     *                  optional "stride"       - Integer, defaults to "width"
-     *                  optional "slice-height" - Integer, defaults to "height"
-     *
+     *  @param format The format of the input data (decoder) or the desired
+     *                format of the output data (encoder).
      *  @param surface Specify a surface on which to render the output of this
      *                 decoder.
      *  @param crypto  Specify a crypto object to facilitate secure decryption
@@ -126,7 +239,7 @@
     */
     public void configure(
             Map<String, Object> format,
-            Surface surface, Crypto crypto, int flags) {
+            Surface surface, MediaCrypto crypto, int flags) {
         String[] keys = null;
         Object[] values = null;
 
@@ -147,18 +260,23 @@
 
     private native final void native_configure(
             String[] keys, Object[] values,
-            Surface surface, Crypto crypto, int flags);
+            Surface surface, MediaCrypto crypto, int flags);
 
     /** After successfully configuring the component, call start. On return
      *  you can query the component for its input/output buffers.
     */
     public native final void start();
 
+    /** Finish the decode/encode session, note that the codec instance
+      * remains active and ready to be {@link #start}ed again.
+      * To ensure that it is available to other client call {@link #release}
+      * and don't just rely on garbage collection to eventually do this for you.
+    */
     public native final void stop();
 
     /** Flush both input and output ports of the component, all indices
-     *  previously returned in calls to dequeueInputBuffer and
-     *  dequeueOutputBuffer become invalid.
+     *  previously returned in calls to {@link #dequeueInputBuffer} and
+     *  {@link #dequeueOutputBuffer} become invalid.
     */
     public native final void flush();
 
@@ -169,24 +287,36 @@
      *  preceded by "codec specific data", i.e. setup data used to initialize
      *  the codec such as PPS/SPS in the case of AVC video or code tables
      *  in the case of vorbis audio.
-     *  The class MediaExtractor provides codec specific data as part of
+     *  The class {@link android.media.MediaExtractor} provides codec
+     *  specific data as part of
      *  the returned track format in entries named "csd-0", "csd-1" ...
      *
      *  These buffers should be submitted using the flag {@link #FLAG_CODECCONFIG}.
      *
      *  To indicate that this is the final piece of input data (or rather that
      *  no more input data follows unless the decoder is subsequently flushed)
-     *  specify the flag {@link FLAG_EOS}.
+     *  specify the flag {@link #FLAG_EOS}.
+     *
+     *  @param index The index of a client-owned input buffer previously returned
+     *               in a call to {@link #dequeueInputBuffer}.
+     *  @param offset The byte offset into the input buffer at which the data starts.
+     *  @param size The number of bytes of valid input data.
+     *  @param presentationTimeUs The time at which this buffer should be rendered.
+     *  @param flags A bitmask of flags {@link #FLAG_SYNCFRAME},
+     *               {@link #FLAG_CODECCONFIG} or {@link #FLAG_EOS}.
     */
     public native final void queueInputBuffer(
             int index,
             int offset, int size, long presentationTimeUs, int flags);
 
-    /** Similar to {@link queueInputBuffer} but submits a buffer that is
+    /** Similar to {@link #queueInputBuffer} but submits a buffer that is
      *  potentially encrypted. The buffer's data is considered to be
      *  partitioned into "subSamples", each subSample starts with a
      *  (potentially empty) run of plain, unencrypted bytes followed
      *  by a (also potentially empty) run of encrypted bytes.
+     *  @param index The index of a client-owned input buffer previously returned
+     *               in a call to {@link #dequeueInputBuffer}.
+     *  @param offset The byte offset into the input buffer at which the data starts.
      *  @param numBytesOfClearData The number of leading unencrypted bytes in
      *                             each subSample.
      *  @param numBytesOfEncryptedData The number of trailing encrypted bytes
@@ -212,27 +342,48 @@
             long presentationTimeUs,
             int flags);
 
-    // Returns the index of an input buffer to be filled with valid data
-    // or -1 if no such buffer is currently available.
-    // This method will return immediately if timeoutUs == 0, wait indefinitely
-    // for the availability of an input buffer if timeoutUs < 0 or wait up
-    // to "timeoutUs" microseconds if timeoutUs > 0.
+    /** Returns the index of an input buffer to be filled with valid data
+     *  or -1 if no such buffer is currently available.
+     *  This method will return immediately if timeoutUs == 0, wait indefinitely
+     *  for the availability of an input buffer if timeoutUs &lt; 0 or wait up
+     *  to "timeoutUs" microseconds if timeoutUs &gt; 0.
+     *  @param timeoutUs The timeout in microseconds, a negative timeout indicates "infinite".
+    */
     public native final int dequeueInputBuffer(long timeoutUs);
 
-    // Returns the index of an output buffer that has been successfully
-    // decoded or one of the INFO_* constants below.
-    // The provided "info" will be filled with buffer meta data.
+    /** If a non-negative timeout had been specified in the call
+     * to {@link #dequeueOutputBuffer}, indicates that the call timed out.
+    */
     public static final int INFO_TRY_AGAIN_LATER        = -1;
+
+    /** The output format has changed, subsequent data will follow the new
+     *  format. {@link #getOutputFormat} returns the new format.
+    */
     public static final int INFO_OUTPUT_FORMAT_CHANGED  = -2;
+
+    /** The output buffers have changed, the client must refer to the new
+     *  set of output buffers returned by {@link #getOutputBuffers} from
+     *  this point on.
+    */
     public static final int INFO_OUTPUT_BUFFERS_CHANGED = -3;
 
-    /** Dequeue an output buffer, block at most "timeoutUs" microseconds. */
+    /** Dequeue an output buffer, block at most "timeoutUs" microseconds.
+     *  Returns the index of an output buffer that has been successfully
+     *  decoded or one of the INFO_* constants below.
+     *  @param info Will be filled with buffer meta data.
+     *  @param timeoutUs The timeout in microseconds, a negative timeout indicates "infinite".
+    */
     public native final int dequeueOutputBuffer(
             BufferInfo info, long timeoutUs);
 
-    // If you are done with a buffer, use this call to return the buffer to
-    // the codec. If you previously specified a surface when configuring this
-    // video decoder you can optionally render the buffer.
+    /** If you are done with a buffer, use this call to return the buffer to
+     *  the codec. If you previously specified a surface when configuring this
+     *  video decoder you can optionally render the buffer.
+     *  @param index The index of a client-owned output buffer previously returned
+     *               in a call to {@link #dequeueOutputBuffer}.
+     *  @param render If a valid surface was specified when configuring the codec,
+     *                passing true renders this output buffer to the surface.
+    */
     public native final void releaseOutputBuffer(int index, boolean render);
 
     /** Call this after dequeueOutputBuffer signals a format change by returning
diff --git a/media/java/android/media/MediaCodecList.java b/media/java/android/media/MediaCodecList.java
index b46ce96..1772e9c 100644
--- a/media/java/android/media/MediaCodecList.java
+++ b/media/java/android/media/MediaCodecList.java
@@ -20,22 +20,42 @@
  * MediaCodecList class can be used to enumerate available codecs,
  * find a codec supporting a given format and query the capabilities
  * of a given codec.
- * @hide
 */
 final public class MediaCodecList {
+    /** Count the number of available codecs.
+      */
     public static native final int countCodecs();
+
+    /** Retrieve the codec name at the specified index. */
     public static native final String getCodecName(int index);
+
+    /** Query if the codec at the specified index is an encoder. */
     public static native final boolean isEncoder(int index);
+
+    /** Query the media types supported by the codec at the specified index */
     public static native final String[] getSupportedTypes(int index);
 
     public static final class CodecProfileLevel {
-        public int mProfile;
-        public int mLevel;
+        /** Defined in the OpenMAX IL specs, depending on the type of media
+          * this can be OMX_VIDEO_AVCPROFILETYPE, OMX_VIDEO_H263PROFILETYPE
+          * or OMX_VIDEO_MPEG4PROFILETYPE.
+        */
+        public int profile;
+
+        /** Defined in the OpenMAX IL specs, depending on the type of media
+          * this can be OMX_VIDEO_AVCLEVELTYPE, OMX_VIDEO_H263LEVELTYPE
+          * or OMX_VIDEO_MPEG4LEVELTYPE.
+        */
+        public int level;
     };
 
     public static final class CodecCapabilities {
-        public CodecProfileLevel[] mProfileLevels;
-        public int[] mColorFormats;
+        public CodecProfileLevel[] profileLevels;
+
+        /** Defined in the OpenMAX IL specs, color format values are drawn from
+          * OMX_COLOR_FORMATTYPE.
+        */
+        public int[] colorFormats;
     };
     public static native final CodecCapabilities getCodecCapabilities(
             int index, String type);
diff --git a/media/java/android/media/MediaCrypto.java b/media/java/android/media/MediaCrypto.java
new file mode 100644
index 0000000..b84ed72
--- /dev/null
+++ b/media/java/android/media/MediaCrypto.java
@@ -0,0 +1,66 @@
+/*
+ * 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.media;
+
+/**
+ * MediaCrypto class can be used in conjunction with {@link android.media.MediaCodec}
+ * to decode encrypted media data.
+ *
+ * Crypto schemes are assigned 16 byte UUIDs,
+ * the method {@link #isCryptoSchemeSupported} can be used to query if a given
+ * scheme is supported on the device.
+ *
+*/
+public final class MediaCrypto {
+    /** Query if the given scheme identified by its UUID is supported on
+      * this device.
+      * @param uuid The UUID of the crypto scheme.
+    */
+    public static final native boolean isCryptoSchemeSupported(byte[] uuid);
+
+    /** Instantiate a MediaCrypto object using opaque, crypto scheme specific
+      * data.
+      * @param uuid The UUID of the crypto scheme.
+      * @param initData Opaque initialization data specific to the crypto scheme.
+    */
+    public MediaCrypto(byte[] uuid, byte[] initData) throws RuntimeException {
+        native_setup(uuid, initData);
+    }
+
+    /** Query if the crypto scheme requires the use of a secure decoder
+      * to decode data of the given mime type.
+      * @param mime The mime type of the media data
+    */
+    public final native boolean requiresSecureDecoderComponent(String mime);
+
+    @Override
+    protected void finalize() {
+        native_finalize();
+    }
+
+    public native final void release();
+    private static native final void native_init();
+    private native final void native_setup(byte[] uuid, byte[] initData);
+    private native final void native_finalize();
+
+    static {
+        System.loadLibrary("media_jni");
+        native_init();
+    }
+
+    private int mNativeContext;
+}
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index 9c3b6a7..3f8b2ca 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -16,63 +16,227 @@
 
 package android.media;
 
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.net.Uri;
+import java.io.FileDescriptor;
+import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.Map;
 
 /**
- * MediaExtractor
- * @hide
+ * MediaExtractor facilitates extraction of demuxed, typically encoded,  media data
+ * from a data source.
+ * <p>It is generally used like this:
+ * <pre>
+ * MediaExtractor extractor = new MediaExtractor();
+ * extractor.setDataSource(...);
+ * int numTracks = extractor.countTracks();
+ * for (int i = 0; i &lt; numTracks; ++i) {
+ *   Map%lt;String, Object&gt; format = extractor.getTrackFormat(i);
+ *   String mime = (String)format.get("mime");
+ *   if (weAreInterestedInThisTrack) {
+ *     extractor.selectTrack(i);
+ *   }
+ * }
+ * ByteBuffer inputBuffer = ByteBuffer.allocate(...)
+ * while (extractor.readSampleData(inputBuffer, ...) &gt;= 0) {
+ *   int trackIndex = extractor.getTrackIndex();
+ *   long presentationTimeUs = extractor.getSampleTime();
+ *   ...
+ *   extractor.advance();
+ * }
+ *
+ * extractor.release();
+ * extractor = null;
+ * </pre>
 */
 final public class MediaExtractor {
-    public MediaExtractor(String path) {
-        native_setup(path);
+    public MediaExtractor() {
+        native_setup();
     }
 
+    /**
+     * Sets the data source as a content Uri.
+     *
+     * @param context the Context to use when resolving the Uri
+     * @param uri the Content URI of the data you want to extract from.
+     * @param headers the headers to be sent together with the request for the data
+     */
+    public final void setDataSource(
+            Context context, Uri uri, Map<String, String> headers)
+        throws IOException {
+        String scheme = uri.getScheme();
+        if(scheme == null || scheme.equals("file")) {
+            setDataSource(uri.getPath());
+            return;
+        }
+
+        AssetFileDescriptor fd = null;
+        try {
+            ContentResolver resolver = context.getContentResolver();
+            fd = resolver.openAssetFileDescriptor(uri, "r");
+            if (fd == null) {
+                return;
+            }
+            // Note: using getDeclaredLength so that our behavior is the same
+            // as previous versions when the content provider is returning
+            // a full file.
+            if (fd.getDeclaredLength() < 0) {
+                setDataSource(fd.getFileDescriptor());
+            } else {
+                setDataSource(
+                        fd.getFileDescriptor(),
+                        fd.getStartOffset(),
+                        fd.getDeclaredLength());
+            }
+            return;
+        } catch (SecurityException ex) {
+        } catch (IOException ex) {
+        } finally {
+            if (fd != null) {
+                fd.close();
+            }
+        }
+
+        setDataSource(uri.toString(), headers);
+    }
+
+    /**
+     * Sets the data source (file-path or http URL) to use.
+     *
+     * @param path the path of the file, or the http URL
+     * @param headers the headers associated with the http request for the stream you want to play
+     */
+    public final void setDataSource(String path, Map<String, String> headers) {
+        String[] keys = null;
+        String[] values = null;
+
+        if (headers != null) {
+            keys = new String[headers.size()];
+            values = new String[headers.size()];
+
+            int i = 0;
+            for (Map.Entry<String, String> entry: headers.entrySet()) {
+                keys[i] = entry.getKey();
+                values[i] = entry.getValue();
+                ++i;
+            }
+        }
+        setDataSource(path, keys, values);
+    }
+
+    private native final void setDataSource(
+            String path, String[] keys, String[] values);
+
+    /**
+     * Sets the data source (file-path or http URL) to use.
+     *
+     * @param path the path of the file, or the http URL of the stream
+     *
+     * <p>When <code>path</code> refers to a local file, the file may actually be opened by a
+     * process other than the calling application.  This implies that the pathname
+     * should be an absolute path (as any other process runs with unspecified current working
+     * directory), and that the pathname should reference a world-readable file.
+     * As an alternative, the application could first open the file for reading,
+     * and then use the file descriptor form {@link #setDataSource(FileDescriptor)}.
+     */
+    public final void setDataSource(String path) {
+        setDataSource(path, null, null);
+    }
+
+    /**
+     * Sets the data source (FileDescriptor) to use. It is the caller's responsibility
+     * to close the file descriptor. It is safe to do so as soon as this call returns.
+     *
+     * @param fd the FileDescriptor for the file you want to extract from.
+     */
+    public final void setDataSource(FileDescriptor fd) {
+        setDataSource(fd, 0, 0x7ffffffffffffffL);
+    }
+
+    /**
+     * Sets the data source (FileDescriptor) to use.  The FileDescriptor must be
+     * seekable (N.B. a LocalSocket is not seekable). It is the caller's responsibility
+     * to close the file descriptor. It is safe to do so as soon as this call returns.
+     *
+     * @param fd the FileDescriptor for the file you want to extract from.
+     * @param offset the offset into the file where the data to be extracted starts, in bytes
+     * @param length the length in bytes of the data to be extracted
+     */
+    public native final void setDataSource(
+            FileDescriptor fd, long offset, long length);
+
     @Override
     protected void finalize() {
         native_finalize();
     }
 
-    // Make sure you call this when you're done to free up any resources
-    // instead of relying on the garbage collector to do this for you at
-    // some point in the future.
+    /** Make sure you call this when you're done to free up any resources
+     *  instead of relying on the garbage collector to do this for you at
+     *   some point in the future.
+    */
     public native final void release();
 
+    /** Count the number of tracks found in the data source.
+     */
     public native int countTracks();
+
+    /** Get the track format at the specified index.
+      * More detail on the representation can be found at {@link android.media.MediaCodec}
+    */
     public native Map<String, Object> getTrackFormat(int index);
 
-    // Subsequent calls to "readSampleData", "getSampleTrackIndex" and
-    // "getSampleTime" only retrieve information for the subset of tracks
-    // selected by the call below.
-    // Selecting the same track multiple times has no effect, the track
-    // is only selected once.
+    /** Subsequent calls to {@link #readSampleData}, {@link #getSampleTrackIndex} and
+     *  {@link #getSampleTime} only retrieve information for the subset of tracks
+     *  selected by the call below.
+     *  Selecting the same track multiple times has no effect, the track
+     *  only selected once.
+     *  Media data will be returned in the order of their timestamps.
+    */
     public native void selectTrack(int index);
 
-    // All selected tracks seek near the requested time. The next sample
-    // returned for each selected track will be a sync sample.
+    /** All selected tracks seek near the requested time. The next sample
+     *  returned for each selected track will be a sync sample.
+    */
     public native void seekTo(long timeUs);
 
+    /** Advance to the next sample. Returns false if no more sample data
+     *  is available (end of stream).
+     */
     public native boolean advance();
 
-    // Retrieve the current encoded sample and store it in the byte buffer
-    // starting at the given offset. Returns the sample size.
+    /** Retrieve the current encoded sample and store it in the byte buffer
+     *  starting at the given offset. Returns the sample size (or -1 if
+     *  no more samples are available).
+    */
     public native int readSampleData(ByteBuffer byteBuf, int offset);
 
-    // Returns the track index the current sample originates from.
+    /** Returns the track index the current sample originates from (or -1
+     *  if no more samples are available)
+    */
     public native int getSampleTrackIndex();
 
-    // Returns the current sample's presentation time in microseconds.
+    /** Returns the current sample's presentation time in microseconds.
+     *  or -1 if no more samples are available.
+    */
     public native long getSampleTime();
 
     // Keep these in sync with their equivalents in NuMediaExtractor.h
+    /** The sample is a sync sample */
     public static final int SAMPLE_FLAG_SYNC      = 1;
+
+    /** The sample is (at least partially) encrypted, see also the documentation
+     *  for {@link android.media.MediaCodec#queueSecureInputBuffer}
+    */
     public static final int SAMPLE_FLAG_ENCRYPTED = 2;
 
-    // Returns the current sample's flags.
+    /** Returns the current sample's flags. */
     public native int getSampleFlags();
 
     private static native final void native_init();
-    private native final void native_setup(String path);
+    private native final void native_setup();
     private native final void native_finalize();
 
     static {
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index dd01db6..545752c 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1619,18 +1619,22 @@
     // FIXME: define error codes and throws exceptions according to the error codes.
     // (IllegalStateException, IOException).
     public void addExternalSource(String path, String mimeType)
-            throws IllegalArgumentException {
+            throws IOException, IllegalArgumentException {
         if (!availableMimeTypeForExternalSource(mimeType)) {
-            throw new IllegalArgumentException("Illegal mimeType for external source: " + mimeType);
+            final String msg = "Illegal mimeType for external source: " + mimeType;
+            throw new IllegalArgumentException(msg);
         }
 
-        Parcel request = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        request.writeInterfaceToken(IMEDIA_PLAYER);
-        request.writeInt(INVOKE_ID_ADD_EXTERNAL_SOURCE);
-        request.writeString(path);
-        request.writeString(mimeType);
-        invoke(request, reply);
+        File file = new File(path);
+        if (file.exists()) {
+            FileInputStream is = new FileInputStream(file);
+            FileDescriptor fd = is.getFD();
+            addExternalSource(fd, mimeType);
+            is.close();
+        } else {
+            // We do not support the case where the path is not a file.
+            throw new IOException(path);
+        }
     }
 
     /**
@@ -1671,8 +1675,6 @@
                 fd.close();
             }
         }
-
-        // TODO: try server side.
     }
 
     /* Do not change these values without updating their counterparts
@@ -1732,6 +1734,7 @@
         if (!availableMimeTypeForExternalSource(mimeType)) {
             throw new IllegalArgumentException("Illegal mimeType for external source: " + mimeType);
         }
+
         Parcel request = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         request.writeInterfaceToken(IMEDIA_PLAYER);
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index a3361d4..98e1bc5 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -2,7 +2,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-    android_media_Crypto.cpp \
+    android_media_MediaCrypto.cpp \
     android_media_MediaCodec.cpp \
     android_media_MediaCodecList.cpp \
     android_media_MediaExtractor.cpp \
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 01d3833..979ffb0 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -20,7 +20,7 @@
 
 #include "android_media_MediaCodec.h"
 
-#include "android_media_Crypto.h"
+#include "android_media_MediaCrypto.h"
 #include "android_media_Utils.h"
 #include "android_runtime/AndroidRuntime.h"
 #include "android_runtime/android_view_Surface.h"
@@ -656,7 +656,7 @@
 
     { "native_configure",
       "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"
-      "Landroid/media/Crypto;I)V",
+      "Landroid/media/MediaCrypto;I)V",
       (void *)android_media_MediaCodec_native_configure },
 
     { "start", "()V", (void *)android_media_MediaCodec_start },
diff --git a/media/jni/android_media_MediaCodecList.cpp b/media/jni/android_media_MediaCodecList.cpp
index 2b8f91e..7139560 100644
--- a/media/jni/android_media_MediaCodecList.cpp
+++ b/media/jni/android_media_MediaCodecList.cpp
@@ -118,10 +118,10 @@
         env->NewObjectArray(profileLevels.size(), profileLevelClazz, NULL);
 
     jfieldID profileField =
-        env->GetFieldID(profileLevelClazz, "mProfile", "I");
+        env->GetFieldID(profileLevelClazz, "profile", "I");
 
     jfieldID levelField =
-        env->GetFieldID(profileLevelClazz, "mLevel", "I");
+        env->GetFieldID(profileLevelClazz, "level", "I");
 
     for (size_t i = 0; i < profileLevels.size(); ++i) {
         const MediaCodecList::ProfileLevel &src = profileLevels.itemAt(i);
@@ -139,7 +139,7 @@
 
     jfieldID profileLevelsField = env->GetFieldID(
             capsClazz,
-            "mProfileLevels",
+            "profileLevels",
             "[Landroid/media/MediaCodecList$CodecProfileLevel;");
 
     env->SetObjectField(caps, profileLevelsField, profileLevelArray);
@@ -155,7 +155,7 @@
     }
 
     jfieldID colorFormatsField = env->GetFieldID(
-            capsClazz, "mColorFormats", "[I");
+            capsClazz, "colorFormats", "[I");
 
     env->SetObjectField(caps, colorFormatsField, colorFormatsArray);
 
diff --git a/media/jni/android_media_Crypto.cpp b/media/jni/android_media_MediaCrypto.cpp
similarity index 79%
rename from media/jni/android_media_Crypto.cpp
rename to media/jni/android_media_MediaCrypto.cpp
index e1a60a1..f4f0953 100644
--- a/media/jni/android_media_Crypto.cpp
+++ b/media/jni/android_media_MediaCrypto.cpp
@@ -15,10 +15,10 @@
  */
 
 //#define LOG_NDEBUG 0
-#define LOG_TAG "Crypto-JNI"
+#define LOG_TAG "MediaCrypto-JNI"
 #include <utils/Log.h>
 
-#include "android_media_Crypto.h"
+#include "android_media_MediaCrypto.h"
 
 #include "android_runtime/AndroidRuntime.h"
 #include "jni.h"
@@ -124,7 +124,7 @@
 
 // static
 sp<ICrypto> JCrypto::GetCrypto(JNIEnv *env, jobject obj) {
-    jclass clazz = env->FindClass("android/media/Crypto");
+    jclass clazz = env->FindClass("android/media/MediaCrypto");
     CHECK(clazz != NULL);
 
     if (!env->IsInstanceOf(obj, clazz)) {
@@ -158,19 +158,19 @@
     return old;
 }
 
-static void android_media_Crypto_release(JNIEnv *env, jobject thiz) {
+static void android_media_MediaCrypto_release(JNIEnv *env, jobject thiz) {
     setCrypto(env, thiz, NULL);
 }
 
-static void android_media_Crypto_native_init(JNIEnv *env) {
-    jclass clazz = env->FindClass("android/media/Crypto");
+static void android_media_MediaCrypto_native_init(JNIEnv *env) {
+    jclass clazz = env->FindClass("android/media/MediaCrypto");
     CHECK(clazz != NULL);
 
     gFields.context = env->GetFieldID(clazz, "mNativeContext", "I");
     CHECK(gFields.context != NULL);
 }
 
-static void android_media_Crypto_native_setup(
+static void android_media_MediaCrypto_native_setup(
         JNIEnv *env, jobject thiz,
         jbyteArray uuidObj, jbyteArray initDataObj) {
     jsize uuidLength = env->GetArrayLength(uuidObj);
@@ -186,16 +186,23 @@
     jboolean isCopy;
     jbyte *uuid = env->GetByteArrayElements(uuidObj, &isCopy);
 
-    jsize initDataLength = env->GetArrayLength(initDataObj);
-    jbyte *initData = env->GetByteArrayElements(initDataObj, &isCopy);
+    jsize initDataLength = 0;
+    jbyte *initData = NULL;
+
+    if (initDataObj != NULL) {
+        initDataLength = env->GetArrayLength(initDataObj);
+        initData = env->GetByteArrayElements(initDataObj, &isCopy);
+    }
 
     sp<JCrypto> crypto = new JCrypto(
             env, thiz, (const uint8_t *)uuid, initData, initDataLength);
 
     status_t err = crypto->initCheck();
 
-    env->ReleaseByteArrayElements(initDataObj, initData, 0);
-    initData = NULL;
+    if (initDataObj != NULL) {
+        env->ReleaseByteArrayElements(initDataObj, initData, 0);
+        initData = NULL;
+    }
 
     env->ReleaseByteArrayElements(uuidObj, uuid, 0);
     uuid = NULL;
@@ -203,7 +210,7 @@
     if (err != OK) {
         jniThrowException(
                 env,
-                "java/io/IOException",
+                "java/lang/RuntimeException",
                 "Failed to instantiate crypto object.");
         return;
     }
@@ -211,12 +218,12 @@
     setCrypto(env,thiz, crypto);
 }
 
-static void android_media_Crypto_native_finalize(
+static void android_media_MediaCrypto_native_finalize(
         JNIEnv *env, jobject thiz) {
-    android_media_Crypto_release(env, thiz);
+    android_media_MediaCrypto_release(env, thiz);
 }
 
-static jboolean android_media_Crypto_isCryptoSchemeSupported(
+static jboolean android_media_MediaCrypto_isCryptoSchemeSupported(
         JNIEnv *env, jobject thiz, jbyteArray uuidObj) {
     jsize uuidLength = env->GetArrayLength(uuidObj);
 
@@ -239,7 +246,7 @@
     return result;
 }
 
-static jboolean android_media_Crypto_requiresSecureDecoderComponent(
+static jboolean android_media_MediaCrypto_requiresSecureDecoderComponent(
         JNIEnv *env, jobject thiz, jstring mimeObj) {
     if (mimeObj == NULL) {
         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
@@ -268,24 +275,24 @@
 }
 
 static JNINativeMethod gMethods[] = {
-    { "release", "()V", (void *)android_media_Crypto_release },
-    { "native_init", "()V", (void *)android_media_Crypto_native_init },
+    { "release", "()V", (void *)android_media_MediaCrypto_release },
+    { "native_init", "()V", (void *)android_media_MediaCrypto_native_init },
 
     { "native_setup", "([B[B)V",
-      (void *)android_media_Crypto_native_setup },
+      (void *)android_media_MediaCrypto_native_setup },
 
     { "native_finalize", "()V",
-      (void *)android_media_Crypto_native_finalize },
+      (void *)android_media_MediaCrypto_native_finalize },
 
     { "isCryptoSchemeSupported", "([B)Z",
-      (void *)android_media_Crypto_isCryptoSchemeSupported },
+      (void *)android_media_MediaCrypto_isCryptoSchemeSupported },
 
     { "requiresSecureDecoderComponent", "(Ljava/lang/String;)Z",
-      (void *)android_media_Crypto_requiresSecureDecoderComponent },
+      (void *)android_media_MediaCrypto_requiresSecureDecoderComponent },
 };
 
 int register_android_media_Crypto(JNIEnv *env) {
     return AndroidRuntime::registerNativeMethods(env,
-                "android/media/Crypto", gMethods, NELEM(gMethods));
+                "android/media/MediaCrypto", gMethods, NELEM(gMethods));
 }
 
diff --git a/media/jni/android_media_Crypto.h b/media/jni/android_media_MediaCrypto.h
similarity index 100%
rename from media/jni/android_media_Crypto.h
rename to media/jni/android_media_MediaCrypto.h
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index 8c661b7..e2cdbca 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -63,8 +63,13 @@
     mClass = NULL;
 }
 
-status_t JMediaExtractor::setDataSource(const char *path) {
-    return mImpl->setDataSource(path);
+status_t JMediaExtractor::setDataSource(
+        const char *path, const KeyedVector<String8, String8> *headers) {
+    return mImpl->setDataSource(path, headers);
+}
+
+status_t JMediaExtractor::setDataSource(int fd, off64_t offset, off64_t size) {
+    return mImpl->setDataSource(fd, offset, size);
 }
 
 size_t JMediaExtractor::countTracks() const {
@@ -200,7 +205,7 @@
 
     if (extractor == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException", NULL);
-        return NULL;
+        return -1;
     }
 
     return extractor->countTracks();
@@ -252,12 +257,7 @@
         return;
     }
 
-    status_t err = extractor->seekTo(timeUs);
-
-    if (err != OK) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
-        return;
-    }
+    extractor->seekTo(timeUs);
 }
 
 static jboolean android_media_MediaExtractor_advance(
@@ -380,24 +380,42 @@
 }
 
 static void android_media_MediaExtractor_native_setup(
-        JNIEnv *env, jobject thiz, jstring path) {
+        JNIEnv *env, jobject thiz) {
     sp<JMediaExtractor> extractor = new JMediaExtractor(env, thiz);
+    setMediaExtractor(env,thiz, extractor);
+}
 
-    if (path == NULL) {
+static void android_media_MediaExtractor_setDataSource(
+        JNIEnv *env, jobject thiz,
+        jstring pathObj, jobjectArray keysArray, jobjectArray valuesArray) {
+    sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
+
+    if (extractor == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return;
+    }
+
+    if (pathObj == NULL) {
         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
         return;
     }
 
-    const char *tmp = env->GetStringUTFChars(path, NULL);
-
-    if (tmp == NULL) {
+    KeyedVector<String8, String8> headers;
+    if (!ConvertKeyValueArraysToKeyedVector(
+                env, keysArray, valuesArray, &headers)) {
         return;
     }
 
-    status_t err = extractor->setDataSource(tmp);
+    const char *path = env->GetStringUTFChars(pathObj, NULL);
 
-    env->ReleaseStringUTFChars(path, tmp);
-    tmp = NULL;
+    if (path == NULL) {
+        return;
+    }
+
+    status_t err = extractor->setDataSource(path, &headers);
+
+    env->ReleaseStringUTFChars(pathObj, path);
+    path = NULL;
 
     if (err != OK) {
         jniThrowException(
@@ -406,8 +424,34 @@
                 "Failed to instantiate extractor.");
         return;
     }
+}
 
-    setMediaExtractor(env,thiz, extractor);
+static void android_media_MediaExtractor_setDataSourceFd(
+        JNIEnv *env, jobject thiz,
+        jobject fileDescObj, jlong offset, jlong length) {
+    sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
+
+    if (extractor == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return;
+    }
+
+    if (fileDescObj == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return;
+    }
+
+    int fd = jniGetFDFromFileDescriptor(env, fileDescObj);
+
+    status_t err = extractor->setDataSource(fd, offset, length);
+
+    if (err != OK) {
+        jniThrowException(
+                env,
+                "java/io/IOException",
+                "Failed to instantiate extractor.");
+        return;
+    }
 }
 
 static void android_media_MediaExtractor_native_finalize(
@@ -443,11 +487,18 @@
 
     { "native_init", "()V", (void *)android_media_MediaExtractor_native_init },
 
-    { "native_setup", "(Ljava/lang/String;)V",
+    { "native_setup", "()V",
       (void *)android_media_MediaExtractor_native_setup },
 
     { "native_finalize", "()V",
       (void *)android_media_MediaExtractor_native_finalize },
+
+    { "setDataSource", "(Ljava/lang/String;[Ljava/lang/String;"
+                       "[Ljava/lang/String;)V",
+      (void *)android_media_MediaExtractor_setDataSource },
+
+    { "setDataSource", "(Ljava/io/FileDescriptor;JJ)V",
+      (void *)android_media_MediaExtractor_setDataSourceFd },
 };
 
 int register_android_media_MediaExtractor(JNIEnv *env) {
diff --git a/media/jni/android_media_MediaExtractor.h b/media/jni/android_media_MediaExtractor.h
index 49a64d6..1aacea2 100644
--- a/media/jni/android_media_MediaExtractor.h
+++ b/media/jni/android_media_MediaExtractor.h
@@ -19,7 +19,9 @@
 
 #include <media/stagefright/foundation/ABase.h>
 #include <utils/Errors.h>
+#include <utils/KeyedVector.h>
 #include <utils/RefBase.h>
+#include <utils/String8.h>
 
 #include "jni.h"
 
@@ -30,7 +32,11 @@
 struct JMediaExtractor : public RefBase {
     JMediaExtractor(JNIEnv *env, jobject thiz);
 
-    status_t setDataSource(const char *path);
+    status_t setDataSource(
+            const char *path,
+            const KeyedVector<String8, String8> *headers);
+
+    status_t setDataSource(int fd, off64_t offset, off64_t size);
 
     size_t countTracks() const;
     status_t getTrackFormat(size_t index, jobject *format) const;
diff --git a/media/jni/android_media_Utils.cpp b/media/jni/android_media_Utils.cpp
index 1190448..a4d88ff 100644
--- a/media/jni/android_media_Utils.cpp
+++ b/media/jni/android_media_Utils.cpp
@@ -85,6 +85,16 @@
     return env->NewObject(clazz, integerConstructID, value);
 }
 
+static jobject makeLongObject(JNIEnv *env, int64_t value) {
+    jclass clazz = env->FindClass("java/lang/Long");
+    CHECK(clazz != NULL);
+
+    jmethodID longConstructID = env->GetMethodID(clazz, "<init>", "(J)V");
+    CHECK(longConstructID != NULL);
+
+    return env->NewObject(clazz, longConstructID, value);
+}
+
 static jobject makeFloatObject(JNIEnv *env, float value) {
     jclass clazz = env->FindClass("java/lang/Float");
     CHECK(clazz != NULL);
@@ -158,6 +168,15 @@
                 break;
             }
 
+            case AMessage::kTypeInt64:
+            {
+                int64_t val;
+                CHECK(msg->findInt64(key, &val));
+
+                valueObj = makeLongObject(env, val);
+                break;
+            }
+
             case AMessage::kTypeFloat:
             {
                 float val;
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 2a4d59b..8acbae3 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -1298,7 +1298,9 @@
                             }
 
                             // Update the pause state.
+                            boolean pausing = false;
                             if (mPaused != mRequestPaused) {
+                                pausing = mRequestPaused;
                                 mPaused = mRequestPaused;
                                 sGLThreadManager.notifyAll();
                                 if (LOG_PAUSE_RESUME) {
@@ -1324,12 +1326,16 @@
                                 lostEglContext = false;
                             }
 
-                            // Do we need to release the EGL surface?
-                            if (mHaveEglSurface && mPaused) {
+                            // When pausing, release the EGL surface:
+                            if (pausing && mHaveEglSurface) {
                                 if (LOG_SURFACE) {
                                     Log.i("GLThread", "releasing EGL surface because paused tid=" + getId());
                                 }
                                 stopEglSurfaceLocked();
+                            }
+
+                            // When pausing, optionally release the EGL Context:
+                            if (pausing && mHaveEglContext) {
                                 GLSurfaceView view = mGLSurfaceViewWeakRef.get();
                                 boolean preserveEglContextOnPause = view == null ?
                                         false : view.mPreserveEGLContextOnPause;
@@ -1339,6 +1345,10 @@
                                         Log.i("GLThread", "releasing EGL context because paused tid=" + getId());
                                     }
                                 }
+                            }
+
+                            // When pausing, optionally terminate EGL:
+                            if (pausing) {
                                 if (sGLThreadManager.shouldTerminateEGLWhenPausing()) {
                                     mEglHelper.finish();
                                     if (LOG_SURFACE) {
diff --git a/packages/BackupRestoreConfirmation/AndroidManifest.xml b/packages/BackupRestoreConfirmation/AndroidManifest.xml
index f3feee8..4fb26ae 100644
--- a/packages/BackupRestoreConfirmation/AndroidManifest.xml
+++ b/packages/BackupRestoreConfirmation/AndroidManifest.xml
@@ -19,6 +19,7 @@
     package="com.android.backupconfirm" >
 
     <uses-permission android:name="android.permission.BACKUP" />
+    <uses-permission android:name="android.permission.CRYPT_KEEPER" />
 
     <application android:allowClearUserData="false"
                  android:allowBackup="false"
diff --git a/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java b/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
index 7f1d059..82ac8cb 100644
--- a/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
+++ b/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
@@ -265,6 +265,7 @@
         } catch (Exception e) {
             // If we can't talk to the mount service we have a serious problem; fail
             // "secure" i.e. assuming that the device is encrypted.
+            Slog.e(TAG, "Unable to communicate with mount service: " + e.getMessage());
             return true;
         }
     }
diff --git a/packages/InputDevices/Android.mk b/packages/InputDevices/Android.mk
index 446b47e..37f2428 100644
--- a/packages/InputDevices/Android.mk
+++ b/packages/InputDevices/Android.mk
@@ -1,3 +1,17 @@
+# 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.
+
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
@@ -12,5 +26,17 @@
 
 include $(BUILD_PACKAGE)
 
-########################
-include $(call all-makefiles-under,$(LOCAL_PATH))
+# 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
+
+validate_input_devices_keymaps: $(files)
+	$(hide) $(validatekeymaps) $(files)
+
+include $(BUILD_PHONY_PACKAGE)
diff --git a/packages/InputDevices/res/raw/keyboard_layout_english_us.kcm b/packages/InputDevices/res/raw/keyboard_layout_english_us.kcm
index a7823fd..2c663bc 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_english_us.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_english_us.kcm
@@ -12,4 +12,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# PLACEHOLDER CONTENT #
+#
+# English (US) keyboard layout.
+# Assumes that the base keyboard layout is already English (US).
+#
+
+type OVERLAY
diff --git a/packages/InputDevices/res/raw/keyboard_layout_english_us_dvorak.kcm b/packages/InputDevices/res/raw/keyboard_layout_english_us_dvorak.kcm
index a7823fd..a2d110e 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_english_us_dvorak.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_english_us_dvorak.kcm
@@ -12,4 +12,45 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# PLACEHOLDER CONTENT #
+#
+# English (US), Dvorak keyboard layout.
+# Assumes that the base keyboard layout is already English (US).
+#
+
+type OVERLAY
+
+map key 12 LEFT_BRACKET
+map key 13 RIGHT_BRACKET
+map key 16 APOSTROPHE
+map key 17 COMMA
+map key 18 PERIOD
+map key 19 P
+map key 20 Y
+map key 21 F
+map key 22 G
+map key 23 C
+map key 24 R
+map key 25 L
+map key 26 SLASH
+map key 27 EQUALS
+map key 30 A
+map key 31 O
+map key 32 E
+map key 33 U
+map key 34 I
+map key 35 D
+map key 36 H
+map key 37 T
+map key 38 N
+map key 39 S
+map key 40 MINUS
+map key 44 SEMICOLON
+map key 45 Q
+map key 46 J
+map key 47 K
+map key 48 X
+map key 49 B
+map key 50 M
+map key 51 W
+map key 52 V
+map key 53 Z
diff --git a/packages/InputDevices/res/raw/keyboard_layout_german.kcm b/packages/InputDevices/res/raw/keyboard_layout_german.kcm
index a7823fd..6b3b3b4 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_german.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_german.kcm
@@ -12,4 +12,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# PLACEHOLDER CONTENT #
+#
+# German keyboard layout.
+#
+
+type OVERLAY
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 56826fa..1654eca 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Kennisgewings"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth-verbind"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Stel invoer metodes op"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fisiese sleutelbord"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Laat die program <xliff:g id="APPLICATION">%1$s</xliff:g> toe om toegang tot die USB-toestel te kry?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Laat die program <xliff:g id="APPLICATION">%1$s</xliff:g> toe om toegang tot die USB-toebehoorsel te kry?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Maak <xliff:g id="ACTIVITY">%1$s</xliff:g> oop wanneer hierdie USB-toestel gekoppel is?"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 7013862..42eef13 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"ማሳወቂያዎች"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"ብሉቱዝ አያይዝ"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"የግቤት ስልቶችን አዘጋጅ"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"የሚዳሰስ የቁልፍ ሰሌዳ"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"መተግበሪያ <xliff:g id="APPLICATION">%1$s</xliff:g> የUSB መሣሪያን ለመድረስ ይፍቀድ?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"መተግበሪያ <xliff:g id="APPLICATION">%1$s</xliff:g> የUSB ተቀጥላ ላይ እንዲደርስ ፍቀድ?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"የዚህ USB ተቀጥላ ሲያያዝ <xliff:g id="ACTIVITY">%1$s</xliff:g>ይከፈት?"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 201f72c..9d6051e 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"التنبيهات"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"تم إنشاء الاتصال بالإنترنت عن طريق البلوتوث."</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"إعداد أسلوب الإدخال"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"لوحة مفاتيح فعلية"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"هل تريد السماح للتطبيق <xliff:g id="APPLICATION">%1$s</xliff:g> بالدخول إلى جهاز USB؟"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"هل تريد السماح للتطبيق <xliff:g id="APPLICATION">%1$s</xliff:g> بالدخول إلى ملحق USB؟"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"هل تريد فتح <xliff:g id="ACTIVITY">%1$s</xliff:g> عند توصيل جهاز USB هذا؟"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index b885503..433c124 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Паведамленні"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Прывязаныя праз Bluetooth"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Налада метадаў уводу"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Фізічная клавіятура"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Дазволіць праыкладанню <xliff:g id="APPLICATION">%1$s</xliff:g> атрымлiваць доступ да прылады USB?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Дазволіць прыкладанню <xliff:g id="APPLICATION">%1$s</xliff:g> доступ да прылады USB?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Адкрыць <xliff:g id="ACTIVITY">%1$s</xliff:g>, калі гэтая USB-прылада падлучаная?"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 0ebced0..427abce 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Notificacions"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth sense fil"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Configura els mètodes d\'entrada"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Teclat físic"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Vols permetre que l\'aplicació <xliff:g id="APPLICATION">%1$s</xliff:g> accedeixi al dispositiu USB?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Vols permetre que l\'aplicació <xliff:g id="APPLICATION">%1$s</xliff:g> accedeixi a l\'accessori USB?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Vols que s\'obri <xliff:g id="ACTIVITY">%1$s</xliff:g> quan aquest dispositiu USB estigui connectat?"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index ac58b06..6c614cd 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Underretninger"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth-tethering anvendt"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Konfigurer inputmetoder"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fysisk tastatur"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Tillad, at appen <xliff:g id="APPLICATION">%1$s</xliff:g> kan få adgang til USB-enheden?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Vil du tillade, at appen <xliff:g id="APPLICATION">%1$s</xliff:g> får adgang til USB-enheden?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Vil du åbne <xliff:g id="ACTIVITY">%1$s</xliff:g>, når denne USB-enhed er tilsluttet?"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 39d5c33..e3d82b1 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Benachrichtigungen"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth-Tethering aktiv"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Eingabemethoden einrichten"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Physische Tastatur"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"App <xliff:g id="APPLICATION">%1$s</xliff:g> Zugriff auf USB-Gerät gewähren?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"App <xliff:g id="APPLICATION">%1$s</xliff:g> Zugriff auf USB-Zubehör gewähren?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"<xliff:g id="ACTIVITY">%1$s</xliff:g> öffnen, wenn dieses USB-Gerät verbunden ist?"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 48158db..5511b1a 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Ειδοποιήσεις"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Έγινε σύνδεση μέσω Bluetooth"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Ρύθμιση μεθόδων εισαγωγής"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Φυσικό πληκτρολόγιο"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Να επιτρέπεται στην εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g> η πρόσβαση στη συσκευή USB;"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Να επιτρέπεται στην εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g> η πρόσβαση στο αξεσουάρ USB;"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Άνοιγμα του <xliff:g id="ACTIVITY">%1$s</xliff:g> κατά τη σύνδεση αυτής της συσκευής USB;"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 148924a..b20a5f3 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Notifications"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth tethered"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Set up input methods"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Physical keyboard"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Allow the app <xliff:g id="APPLICATION">%1$s</xliff:g> to access the USB device?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Allow the app <xliff:g id="APPLICATION">%1$s</xliff:g> to access the USB accessory?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Open <xliff:g id="ACTIVITY">%1$s</xliff:g> when this USB device is connected?"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 4db7130..96c8c23 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Notificaciones"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth anclado"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Configurar métodos de intro."</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Teclado físico"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"¿Deseas que la aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> acceda al dispositivo USB?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"¿Deseas que la aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> acceda al accesorio USB?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"¿Abrir <xliff:g id="ACTIVITY">%1$s</xliff:g> cuando este dispositivo USB esté conectado?"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index f7f73d7..0b3e4e4 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Notificaciones"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth anclado"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Configurar métodos de introducción"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Teclado físico"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"¿Permitir que la aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> acceda al dispositivo USB?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"¿Permitir que la aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> acceda al accesorio USB?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"¿Quieres abrir <xliff:g id="ACTIVITY">%1$s</xliff:g> al conectar este dispositivo USB?"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 8e3a1e3..055e3ee 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Teatised"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth on jagatud"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Seadista sisestusmeetodeid"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Füüsiline klaviatuur"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Kas lubate rakendusel <xliff:g id="APPLICATION">%1$s</xliff:g> USB-seadmele juurde pääseda?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Kas lubate rakendusel <xliff:g id="APPLICATION">%1$s</xliff:g> USB-seadmele juurde pääseda?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Kas avada <xliff:g id="ACTIVITY">%1$s</xliff:g>, kui see USB-seade on ühendatud?"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 569e929..df25d5e 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"اعلان ها"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"اتصال اینترنتی با بلوتوث تلفن همراه"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"تنظیم روش‌های ورودی"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"صفحه کلید فیزیکی"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"به برنامه <xliff:g id="APPLICATION">%1$s</xliff:g> اجازه می دهید به دستگاه USB دسترسی داشته باشد؟"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"به برنامه <xliff:g id="APPLICATION">%1$s</xliff:g> اجازه میدهد تا به وسیله جانبی USB دسترسی داشته باشد؟"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"وقتی این دستگاه USB وصل است، <xliff:g id="ACTIVITY">%1$s</xliff:g> باز شود؟"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 93e6b62..370d234 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Ilmoitukset"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth yhdistetty"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Määritä syöttötavat"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fyysinen näppäimistö"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Annetaanko sovellukselle <xliff:g id="APPLICATION">%1$s</xliff:g> lupa käyttää USB-laitetta?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Annetaanko sovellukselle <xliff:g id="APPLICATION">%1$s</xliff:g> lupa käyttää USB-lisälaitetta?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Avataanko <xliff:g id="ACTIVITY">%1$s</xliff:g> tämän USB-laitteen ollessa kytkettynä?"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 1a8c6a7..c7f307c 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Notifications"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Connexion Bluetooth partagée"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Configurer les modes de saisie"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Clavier physique"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Autoriser l\'application <xliff:g id="APPLICATION">%1$s</xliff:g> à accéder au périphérique USB ?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Autoriser l\'application <xliff:g id="APPLICATION">%1$s</xliff:g> à accéder à l\'accessoire USB ?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Ouvrir <xliff:g id="ACTIVITY">%1$s</xliff:g> lors de la connexion de ce périphérique USB ?"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 741f1b4..9805f90 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"सूचनाएं"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth टीदर किया गया"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"इनपुट पद्धति सेट करें"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"भौतिक कीबोर्ड"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"एप्लिकेशन <xliff:g id="APPLICATION">%1$s</xliff:g> को USB उपकरण तक पहुंचने दें?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"एप्लिकेशन <xliff:g id="APPLICATION">%1$s</xliff:g> को USB सहायक उपकरण तक पहुंचने दें?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"जब यह USB उपकरण कनेक्ट किया जाए, तब <xliff:g id="ACTIVITY">%1$s</xliff:g> को खोलें?"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 1c28b57..87a9d45 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Értesítések"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth megosztva"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Beviteli módok beállítása"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fizikai billentyűzet"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"A(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazás hozzáférhet az USB-eszközhöz?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"A(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazás hozzáférhet az USB-kiegészítőhöz?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"<xliff:g id="ACTIVITY">%1$s</xliff:g> megnyitása, ha USB-kiegészítő csatlakoztatva van?"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index cdf7c9d..a725377 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Notifiche"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth con tethering"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Configura metodi di immissione"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Tastiera fisica"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Consentire all\'applicazione <xliff:g id="APPLICATION">%1$s</xliff:g> di accedere al dispositivo USB?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Consentire all\'applicazione <xliff:g id="APPLICATION">%1$s</xliff:g> di accedere all\'accessorio USB?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Aprire <xliff:g id="ACTIVITY">%1$s</xliff:g> quando questo dispositivo USB è collegato?"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index bc5e873..03fba7e 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"התראות"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth קשור"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"הגדר שיטות קלט"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"מקלדת פיזית"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"לאפשר ליישום <xliff:g id="APPLICATION">%1$s</xliff:g> גישה להתקן ה-USB?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"לאפשר ליישום <xliff:g id="APPLICATION">%1$s</xliff:g> גישה לאביזר ה-USB?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"האם לפתוח את <xliff:g id="ACTIVITY">%1$s</xliff:g> כאשר מכשיר USB זה מחובר?"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 01d76eb..4818ca9 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"通知"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetoothテザリング接続"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"入力方法をセットアップ"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"物理キーボード"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"アプリ「<xliff:g id="APPLICATION">%1$s</xliff:g>」にUSBデバイスへのアクセスを許可しますか?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"アプリ「<xliff:g id="APPLICATION">%1$s</xliff:g>」にUSBアクセサリへのアクセスを許可しますか?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"このUSBデバイスが接続されたときに<xliff:g id="ACTIVITY">%1$s</xliff:g>を開きますか?"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 88194df..3321912 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"알림"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"블루투스 테더링됨"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"입력 방법 설정"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"물리적 키보드"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"<xliff:g id="APPLICATION">%1$s</xliff:g> 앱이 USB 기기에 액세스하도록 허용하시겠습니까?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"<xliff:g id="APPLICATION">%1$s</xliff:g> 앱이 USB 액세서리에 액세스하도록 허용하시겠습니까?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"USB 기기가 연결될 때 <xliff:g id="ACTIVITY">%1$s</xliff:g>(을)를 여시겠습니까?"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 942e159..831fa41 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Pranešimai"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"„Bluetooth“ susieta"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Nustatyti įvesties metodus"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fizinė klaviatūra"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Leisti programai „<xliff:g id="APPLICATION">%1$s</xliff:g>“ pasiekti USB įrenginį?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Leisti programai „<xliff:g id="APPLICATION">%1$s</xliff:g>“ pasiekti USB priedą?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Atidaryti <xliff:g id="ACTIVITY">%1$s</xliff:g>, kai prijungtas šis USB įrenginys?"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index b5c9130..158c850 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Paziņojumi"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth piesaiste"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Iestatīt ievades metodes"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fiziskā tastatūra"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Vai ļaut lietotnei <xliff:g id="APPLICATION">%1$s</xliff:g> piekļūt šai USB ierīcei?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Vai ļaut lietotnei <xliff:g id="APPLICATION">%1$s</xliff:g> piekļūt šim USB piederumam?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Vai atvērt darbību <xliff:g id="ACTIVITY">%1$s</xliff:g>, kad tiek pievienota šī USB ierīce?"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index f08013d..899a204 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Pemberitahuan"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth ditambatkan"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Sediakan kaedah input"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Papan kekunci fizikal"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Benarkan aplikasi <xliff:g id="APPLICATION">%1$s</xliff:g> mengakses peranti USB?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Benarkan aplikasi <xliff:g id="APPLICATION">%1$s</xliff:g> mengakses aksesori USB?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Buka <xliff:g id="ACTIVITY">%1$s</xliff:g> apabila peranti USB ini disambungkan?"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 5314ba3..e05e2c9 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Meldingen"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth getetherd"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Invoermethoden instellen"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fysiek toetsenbord"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"De app <xliff:g id="APPLICATION">%1$s</xliff:g> toegang geven tot het USB-apparaat?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"De app <xliff:g id="APPLICATION">%1$s</xliff:g> toegang geven tot het USB-accessoire?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"<xliff:g id="ACTIVITY">%1$s</xliff:g> openen wanneer dit USB-apparaat wordt aangesloten?"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 26e3989..0618eb5 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Powiadomienia"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth – podłączono"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Konfiguruj metody wprowadzania"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Klawiatura fizyczna"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Zezwolić aplikacji <xliff:g id="APPLICATION">%1$s</xliff:g> na dostęp do urządzenia USB?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Zezwolić aplikacji <xliff:g id="APPLICATION">%1$s</xliff:g> na dostęp do urządzenia USB?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Czy otworzyć <xliff:g id="ACTIVITY">%1$s</xliff:g> po podłączeniu tego urządzenia USB?"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index a5999e3..6a278ba 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Notificações"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth ligado"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Configurar métodos introdução"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Teclado físico"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Permitir que a aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> aceda ao dispositivo USB?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Permitir que a aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> aceda ao acessório USB?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Abrir <xliff:g id="ACTIVITY">%1$s</xliff:g> quando este dispositivo USB estiver ligado?"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 02bef77..23a2ba5 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Notificações"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth vinculado"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Configurar métodos de entrada"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Teclado físico"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Permitir que o aplicativo <xliff:g id="APPLICATION">%1$s</xliff:g> acesse o dispositivo USB?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Permitir que o aplicativo <xliff:g id="APPLICATION">%1$s</xliff:g> acesse o acessório USB?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Abrir <xliff:g id="ACTIVITY">%1$s</xliff:g> quando este dispositivo USB estiver conectado?"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 4057599..3753309 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Уведомления"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Общий модем доступен через Bluetooth"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Настройка способов ввода"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Физическая клавиатура"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Открыть приложению \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" доступ к USB-устройству?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Открыть приложению \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" доступ к USB-устройству?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Запускать <xliff:g id="ACTIVITY">%1$s</xliff:g> при подключении этого USB-устройства?"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 67368ac..599f99c 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Upozornenia"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Zdieľané dátové pripojenie cez Bluetooth"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Nastavenie metód vstupu"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fyzická klávesnica"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Povoliť aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g> prístup k zariadeniu USB?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Povoliť aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g> prístup k periférnemu zariadeniu USB?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Chcete pri pripojení tohto zariadenia USB otvoriť aplikáciu <xliff:g id="ACTIVITY">%1$s</xliff:g>?"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 77aef3d..fb229e2 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Obvestila"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Internetna povezava prek Bluetootha"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Nastavi načine vnosa"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fizična tipkovnica"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Želite programu <xliff:g id="APPLICATION">%1$s</xliff:g> dovoliti dostop do naprave USB?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Želite dovoliti programu <xliff:g id="APPLICATION">%1$s</xliff:g> dostop do dodatka USB?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Želite, da se odpre <xliff:g id="ACTIVITY">%1$s</xliff:g>, ko priključite to napravo USB?"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index ba4edea..8eaa126 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Aviseringar"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Internetdelning via Bluetooth"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Konfigurera inmatningsmetoder"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fysiskt tangentbord"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Vill du tillåta att appen <xliff:g id="APPLICATION">%1$s</xliff:g> använder USB-enheten?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Vill du tillåta att appen <xliff:g id="APPLICATION">%1$s</xliff:g> använder USB-tillbehöret?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Vill du öppna <xliff:g id="ACTIVITY">%1$s</xliff:g> när den här USB-enheten ansluts?"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 8a6b050..19bd4ab 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -46,8 +46,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Arifa"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth imefungwa"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Weka mbinu za ingizo"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Kibodi halisi"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Ruhusu programu <xliff:g id="APPLICATION">%1$s</xliff:g> kufikia kifaa cha USB?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Ruhusu programu <xliff:g id="APPLICATION">%1$s</xliff:g> kufikia kifaa cha ziada cha USB?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Je, ungetaka kufungua  <xliff:g id="ACTIVITY">%1$s</xliff:g>wakati kifaa cha USB kimeunganishwa?"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 55ecfae..2054121 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Mga Notification"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Na-tether ang bluetooth"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"I-set up paraan ng pag-input"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Aktwal na keyboard"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Payagan ang app na <xliff:g id="APPLICATION">%1$s</xliff:g> na i-access ang USB device?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Payagan ang app na <xliff:g id="APPLICATION">%1$s</xliff:g> na i-access ang USB accessory?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Buksan ang <xliff:g id="ACTIVITY">%1$s</xliff:g> kapag nakakonekta ang USB device na ito?"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index f0aa516..ca422f7 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Bildirimler"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth paylaşımı tamam"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Giriş yöntemlerini ayarla"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fiziksel klavye"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasının USB cihazına erişmesine izin verilsin mi?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasının USB aksesuarına erişmesine izin verilsin mi?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Bu USB cihaz bağlandığında <xliff:g id="ACTIVITY">%1$s</xliff:g> açılsın mı?"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index abd024a..05ab87c 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Thông báo"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth được dùng làm điểm truy cập Internet"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Thiết lập phương thức nhập"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Bàn phím thực"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Cho phép ứng dụng <xliff:g id="APPLICATION">%1$s</xliff:g> truy cập thiết bị USB?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Cho phép ứng dụng <xliff:g id="APPLICATION">%1$s</xliff:g> truy cập phụ kiện USB?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Mở <xliff:g id="ACTIVITY">%1$s</xliff:g> khi thiết bị USB này được kết nối?"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index ec92713c..c862d74 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"通知"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"已通过蓝牙共享网络"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"设置输入法"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"物理键盘"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"允许应用“<xliff:g id="APPLICATION">%1$s</xliff:g>”访问该 USB 设备吗?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"允许应用“<xliff:g id="APPLICATION">%1$s</xliff:g>”访问该 USB 配件吗?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"要在连接此 USB 设备时打开<xliff:g id="ACTIVITY">%1$s</xliff:g>吗?"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 27dd8fd..91f6566 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Izaziso"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Ukusebenzisa i-Bluetooth njengemodemu"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Izilungiselelo zezindlela zokufakwayo"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Ukwakheka kwekhibhodi"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Vumela insiza <xliff:g id="APPLICATION">%1$s</xliff:g> ukuthi ufinyelele ezintweni eziphuma ne-USB?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Vumela insiza <xliff:g id="APPLICATION">%1$s</xliff:g> ukuthi ufinyelele ezintweni eziphuma ne-USB?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Vula <xliff:g id="ACTIVITY">%1$s</xliff:g> uma ledivayisi ye-USB ixhunyiwe?"</string>
diff --git a/policy/src/com/android/internal/policy/impl/BiometricSensorUnlock.java b/policy/src/com/android/internal/policy/impl/BiometricSensorUnlock.java
index d445d5c..e2c317d 100644
--- a/policy/src/com/android/internal/policy/impl/BiometricSensorUnlock.java
+++ b/policy/src/com/android/internal/policy/impl/BiometricSensorUnlock.java
@@ -29,6 +29,7 @@
     // Show the interface, but don't start the unlock procedure.  The interface should disappear
     // after the specified timeout.  If the timeout is 0, the interface shows until another event,
     // such as calling hide(), causes it to disappear.
+    // Called on the UI Thread
     public void show(long timeoutMilliseconds);
 
     // Hide the interface, if any, exposing the lockscreen.
@@ -39,6 +40,7 @@
 
     // Start the unlock procedure.  Returns ‘false’ if it can’t be started or if the backup should
     // be used.
+    // Called on the UI thread.
     public boolean start(boolean suppressBiometricUnlock);
 
     // Provide a view to work within.
diff --git a/policy/src/com/android/internal/policy/impl/FaceUnlock.java b/policy/src/com/android/internal/policy/impl/FaceUnlock.java
index 7b0a086..09a1c8b 100644
--- a/policy/src/com/android/internal/policy/impl/FaceUnlock.java
+++ b/policy/src/com/android/internal/policy/impl/FaceUnlock.java
@@ -88,7 +88,9 @@
     }
 
     // Shows the FaceLock area for a period of time
+    // Called on the UI thread
     public void show(long timeoutMillis) {
+        removeAreaDisplayMessages();
         showArea();
         if (timeoutMillis > 0)
             mHandler.sendEmptyMessageDelayed(MSG_HIDE_AREA_VIEW, timeoutMillis);
@@ -134,6 +136,7 @@
     /**
      * When screen is turned on and focused, need to bind to FaceLock service if we are using
      * FaceLock, but only if we're not dealing with a call
+     * Called on the UI thread
      */
     public boolean start(boolean suppressBiometricUnlock) {
         final boolean tooManyFaceUnlockTries = mUpdateMonitor.getMaxFaceUnlockAttemptsReached();
@@ -146,12 +149,13 @@
                 && !suppressBiometricUnlock
                 && !tooManyFaceUnlockTries
                 && !backupIsTimedOut) {
-            bind();
-
             // Show FaceLock area, but only for a little bit so lockpattern will become visible if
             // FaceLock fails to start or crashes
+            // This must show before bind to guarantee that Face Unlock has a place to display
             show(VIEW_AREA_SERVICE_TIMEOUT);
 
+            bind();
+
             // When switching between portrait and landscape view while FaceLock is running, the
             // screen will eventually go dark unless we poke the wakelock when FaceLock is
             // restarted
@@ -170,6 +174,8 @@
             mAreaView = topView.findViewById(R.id.faceLockAreaView);
             if (mAreaView == null) {
                 Log.e(TAG, "Layout does not have areaView and FaceLock is enabled");
+            } else {
+                show(0);
             }
         } else {
             mAreaView = null; // Set to null if not using FaceLock
@@ -192,6 +198,14 @@
         return DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
     }
 
+    // Shows the FaceLock area
+    // Called on the UI thread
+    private void showArea() {
+        if (mAreaView != null) {
+            mAreaView.setVisibility(View.VISIBLE);
+        }
+    }
+
     // Handles covering or exposing FaceLock area on the client side when FaceLock starts or stops
     // This needs to be done in a handler because the call could be coming from a callback from the
     // FaceLock service that is in a thread that can't modify the UI
@@ -199,9 +213,7 @@
     public boolean handleMessage(Message msg) {
         switch (msg.what) {
         case MSG_SHOW_AREA_VIEW:
-            if (mAreaView != null) {
-                mAreaView.setVisibility(View.VISIBLE);
-            }
+            showArea();
             break;
         case MSG_HIDE_AREA_VIEW:
             if (mAreaView != null) {
@@ -221,13 +233,6 @@
         mHandler.removeMessages(MSG_HIDE_AREA_VIEW);
     }
 
-    // Shows the FaceLock area immediately
-    private void showArea() {
-        // Remove messages to prevent a delayed hide message from undo-ing the show
-        removeAreaDisplayMessages();
-        mHandler.sendEmptyMessage(MSG_SHOW_AREA_VIEW);
-    }
-
     // Binds to FaceLock service.  This call does not tell it to start, but it causes the service
     // to call the onServiceConnected callback, which then starts FaceLock.
     private void bind() {
@@ -329,7 +334,11 @@
         @Override
         public void unlock() {
             if (DEBUG) Log.d(TAG, "FaceLock unlock()");
-            showArea(); // Keep fallback covered
+
+            // Keep fallback covered
+            removeAreaDisplayMessages();
+            mHandler.sendEmptyMessage(MSG_SHOW_AREA_VIEW);
+
             stop();
 
             mKeyguardScreenCallback.keyguardDone(true);
diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
index c382646..10c3381 100644
--- a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
+++ b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
@@ -613,13 +613,7 @@
             ((KeyguardScreen) mUnlockScreen).onResume();
         }
 
-        if (mBiometricUnlock.installedAndSelected() && !mSupressBiometricUnlock) {
-            // Note that show() gets called before the screen turns off to set it up for next time
-            // it is turned on.  We don't want to set a timeout on the biometric unlock here because
-            // it may be gone by the time the screen is turned on again.  We set the timeout when
-            // the screen turns on instead.
-            mBiometricUnlock.show(0);
-        } else {
+        if (!mBiometricUnlock.installedAndSelected() || mSupressBiometricUnlock) {
             mBiometricUnlock.hide();
         }
     }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 0a63840..897b8d0 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -909,7 +909,7 @@
             mPluggedIn = (0 != intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0));
         }
 
-        mVibrator = new Vibrator();
+        mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
         mLongPressVibePattern = getLongIntArray(mContext.getResources(),
                 com.android.internal.R.array.config_longPressVibePattern);
         mVirtualKeyVibePattern = getLongIntArray(mContext.getResources(),
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index fbffc94..326dc32 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -161,12 +161,14 @@
         const InputDeviceIdentifier& identifier) :
         next(NULL),
         fd(fd), id(id), path(path), identifier(identifier),
-        classes(0), configuration(NULL), virtualKeyMap(NULL) {
+        classes(0), configuration(NULL), virtualKeyMap(NULL),
+        ffEffectPlaying(false), ffEffectId(-1) {
     memset(keyBitmask, 0, sizeof(keyBitmask));
     memset(absBitmask, 0, sizeof(absBitmask));
     memset(relBitmask, 0, sizeof(relBitmask));
     memset(swBitmask, 0, sizeof(swBitmask));
     memset(ledBitmask, 0, sizeof(ledBitmask));
+    memset(ffBitmask, 0, sizeof(ffBitmask));
     memset(propBitmask, 0, sizeof(propBitmask));
 }
 
@@ -441,11 +443,22 @@
     AutoMutex _l(mLock);
     Device* device = getDeviceLocked(deviceId);
 
-    if (device && device->keyMap.haveKeyLayout()) {
-        status_t err = device->keyMap.keyLayoutMap->mapKey(
-                scanCode, usageCode, outKeycode, outFlags);
-        if (err == NO_ERROR) {
-            return NO_ERROR;
+    if (device) {
+        // Check the key character map first.
+        sp<KeyCharacterMap> kcm = device->getKeyCharacterMap();
+        if (kcm != NULL) {
+            if (!kcm->mapKey(scanCode, usageCode, outKeycode)) {
+                *outFlags = 0;
+                return NO_ERROR;
+            }
+        }
+
+        // Check the key layout next.
+        if (device->keyMap.haveKeyLayout()) {
+            if (!device->keyMap.keyLayoutMap->mapKey(
+                    scanCode, usageCode, outKeycode, outFlags)) {
+                return NO_ERROR;
+            }
         }
     }
 
@@ -529,11 +542,82 @@
     AutoMutex _l(mLock);
     Device* device = getDeviceLocked(deviceId);
     if (device) {
-        return device->keyMap.keyCharacterMap;
+        return device->getKeyCharacterMap();
     }
     return NULL;
 }
 
+bool EventHub::setKeyboardLayoutOverlay(int32_t deviceId,
+        const sp<KeyCharacterMap>& map) {
+    AutoMutex _l(mLock);
+    Device* device = getDeviceLocked(deviceId);
+    if (device) {
+        if (map != device->overlayKeyMap) {
+            device->overlayKeyMap = map;
+            device->combinedKeyMap = KeyCharacterMap::combine(
+                    device->keyMap.keyCharacterMap, map);
+            return true;
+        }
+    }
+    return false;
+}
+
+void EventHub::vibrate(int32_t deviceId, nsecs_t duration) {
+    AutoMutex _l(mLock);
+    Device* device = getDeviceLocked(deviceId);
+    if (device && !device->isVirtual()) {
+        ff_effect effect;
+        memset(&effect, 0, sizeof(effect));
+        effect.type = FF_RUMBLE;
+        effect.id = device->ffEffectId;
+        effect.u.rumble.strong_magnitude = 0xc000;
+        effect.u.rumble.weak_magnitude = 0xc000;
+        effect.replay.length = (duration + 999999LL) / 1000000LL;
+        effect.replay.delay = 0;
+        if (ioctl(device->fd, EVIOCSFF, &effect)) {
+            ALOGW("Could not upload force feedback effect to device %s due to error %d.",
+                    device->identifier.name.string(), errno);
+            return;
+        }
+        device->ffEffectId = effect.id;
+
+        struct input_event ev;
+        ev.time.tv_sec = 0;
+        ev.time.tv_usec = 0;
+        ev.type = EV_FF;
+        ev.code = device->ffEffectId;
+        ev.value = 1;
+        if (write(device->fd, &ev, sizeof(ev)) != sizeof(ev)) {
+            ALOGW("Could not start force feedback effect on device %s due to error %d.",
+                    device->identifier.name.string(), errno);
+            return;
+        }
+        device->ffEffectPlaying = true;
+    }
+}
+
+void EventHub::cancelVibrate(int32_t deviceId) {
+    AutoMutex _l(mLock);
+    Device* device = getDeviceLocked(deviceId);
+    if (device && !device->isVirtual()) {
+        if (device->ffEffectPlaying) {
+            device->ffEffectPlaying = false;
+
+            struct input_event ev;
+            ev.time.tv_sec = 0;
+            ev.time.tv_usec = 0;
+            ev.type = EV_FF;
+            ev.code = device->ffEffectId;
+            ev.value = 0;
+            if (write(device->fd, &ev, sizeof(ev)) != sizeof(ev)) {
+                ALOGW("Could not stop force feedback effect on device %s due to error %d.",
+                        device->identifier.name.string(), errno);
+                return;
+            }
+        }
+    }
+}
+
 EventHub::Device* EventHub::getDeviceLocked(int32_t deviceId) const {
     if (deviceId == BUILT_IN_KEYBOARD_ID) {
         deviceId = mBuiltInKeyboardId;
@@ -949,6 +1033,7 @@
     ioctl(fd, EVIOCGBIT(EV_REL, sizeof(device->relBitmask)), device->relBitmask);
     ioctl(fd, EVIOCGBIT(EV_SW, sizeof(device->swBitmask)), device->swBitmask);
     ioctl(fd, EVIOCGBIT(EV_LED, sizeof(device->ledBitmask)), device->ledBitmask);
+    ioctl(fd, EVIOCGBIT(EV_FF, sizeof(device->ffBitmask)), device->ffBitmask);
     ioctl(fd, EVIOCGPROP(sizeof(device->propBitmask)), device->propBitmask);
 
     // See if this is a keyboard.  Ignore everything in the button range except for
@@ -1010,6 +1095,11 @@
         }
     }
 
+    // Check whether this device supports the vibrator.
+    if (test_bit(FF_RUMBLE, device->ffBitmask)) {
+        device->classes |= INPUT_DEVICE_CLASS_VIBRATOR;
+    }
+
     // Configure virtual keys.
     if ((device->classes & INPUT_DEVICE_CLASS_TOUCH)) {
         // Load the virtual keys for the touch screen, if any.
diff --git a/services/input/EventHub.h b/services/input/EventHub.h
index 88159e7..afc12ef 100644
--- a/services/input/EventHub.h
+++ b/services/input/EventHub.h
@@ -113,6 +113,9 @@
     /* The input device is a joystick (implies gamepad, has joystick absolute axes). */
     INPUT_DEVICE_CLASS_JOYSTICK      = 0x00000100,
 
+    /* The input device has a vibrator (supports FF_RUMBLE). */
+    INPUT_DEVICE_CLASS_VIBRATOR      = 0x00000200,
+
     /* The input device is virtual (not a real device, not part of UI configuration). */
     INPUT_DEVICE_CLASS_VIRTUAL       = 0x40000000,
 
@@ -218,6 +221,11 @@
             Vector<VirtualKeyDefinition>& outVirtualKeys) const = 0;
 
     virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const = 0;
+    virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& map) = 0;
+
+    /* Control the vibrator. */
+    virtual void vibrate(int32_t deviceId, nsecs_t duration) = 0;
+    virtual void cancelVibrate(int32_t deviceId) = 0;
 
     /* Requests the EventHub to reopen all input devices on the next call to getEvents(). */
     virtual void requestReopenDevices() = 0;
@@ -276,6 +284,10 @@
             Vector<VirtualKeyDefinition>& outVirtualKeys) const;
 
     virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const;
+    virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& map);
+
+    virtual void vibrate(int32_t deviceId, nsecs_t duration);
+    virtual void cancelVibrate(int32_t deviceId);
 
     virtual void requestReopenDevices();
 
@@ -303,6 +315,7 @@
         uint8_t relBitmask[(REL_MAX + 1) / 8];
         uint8_t swBitmask[(SW_MAX + 1) / 8];
         uint8_t ledBitmask[(LED_MAX + 1) / 8];
+        uint8_t ffBitmask[(FF_MAX + 1) / 8];
         uint8_t propBitmask[(INPUT_PROP_MAX + 1) / 8];
 
         String8 configurationFile;
@@ -310,12 +323,25 @@
         VirtualKeyMap* virtualKeyMap;
         KeyMap keyMap;
 
+        sp<KeyCharacterMap> overlayKeyMap;
+        sp<KeyCharacterMap> combinedKeyMap;
+
+        bool ffEffectPlaying;
+        int16_t ffEffectId; // initially -1
+
         Device(int fd, int32_t id, const String8& path, const InputDeviceIdentifier& identifier);
         ~Device();
 
         void close();
 
         inline bool isVirtual() const { return fd < 0; }
+
+        const sp<KeyCharacterMap>& getKeyCharacterMap() const {
+            if (combinedKeyMap != NULL) {
+                return combinedKeyMap;
+            }
+            return keyMap.keyCharacterMap;
+        }
     };
 
     status_t openDeviceLocked(const char *devicePath);
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index 71eba52..95e56bf 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -36,6 +36,9 @@
 // Log debug messages about gesture detection.
 #define DEBUG_GESTURES 0
 
+// Log debug messages about the vibrator.
+#define DEBUG_VIBRATOR 0
+
 #include "InputReader.h"
 
 #include <cutils/log.h>
@@ -273,9 +276,7 @@
             mConfigurationChangesToRefresh = 0;
             timeoutMillis = 0;
             refreshConfigurationLocked(changes);
-        }
-
-        if (timeoutMillis < 0 && mNextTimeout != LLONG_MAX) {
+        } else if (mNextTimeout != LLONG_MAX) {
             nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
             timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
         }
@@ -426,6 +427,11 @@
         device->addMapper(new SwitchInputMapper(device));
     }
 
+    // Vibrator-like devices.
+    if (classes & INPUT_DEVICE_CLASS_VIBRATOR) {
+        device->addMapper(new VibratorInputMapper(device));
+    }
+
     // Keyboard-like devices.
     uint32_t keyboardSource = 0;
     int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;
@@ -594,6 +600,7 @@
 void InputReader::requestTimeoutAtTimeLocked(nsecs_t when) {
     if (when < mNextTimeout) {
         mNextTimeout = when;
+        mEventHub->wake();
     }
 }
 
@@ -721,6 +728,27 @@
     }
 }
 
+void InputReader::vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize,
+        ssize_t repeat, int32_t token) {
+    AutoMutex _l(mLock);
+
+    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
+    if (deviceIndex >= 0) {
+        InputDevice* device = mDevices.valueAt(deviceIndex);
+        device->vibrate(pattern, patternSize, repeat, token);
+    }
+}
+
+void InputReader::cancelVibrate(int32_t deviceId, int32_t token) {
+    AutoMutex _l(mLock);
+
+    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
+    if (deviceIndex >= 0) {
+        InputDevice* device = mDevices.valueAt(deviceIndex);
+        device->cancelVibrate(token);
+    }
+}
+
 void InputReader::dump(String8& dump) {
     AutoMutex _l(mLock);
 
@@ -934,6 +962,14 @@
             mContext->getEventHub()->getConfiguration(mId, &mConfiguration);
         }
 
+        if (!changes || (changes & InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUTS)) {
+            sp<KeyCharacterMap> keyboardLayout =
+                    mContext->getPolicy()->getKeyboardLayoutOverlay(mIdentifier.descriptor);
+            if (mContext->getEventHub()->setKeyboardLayoutOverlay(mId, keyboardLayout)) {
+                bumpGeneration();
+            }
+        }
+
         size_t numMappers = mMappers.size();
         for (size_t i = 0; i < numMappers; i++) {
             InputMapper* mapper = mMappers[i];
@@ -1054,6 +1090,23 @@
     return result;
 }
 
+void InputDevice::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
+        int32_t token) {
+    size_t numMappers = mMappers.size();
+    for (size_t i = 0; i < numMappers; i++) {
+        InputMapper* mapper = mMappers[i];
+        mapper->vibrate(pattern, patternSize, repeat, token);
+    }
+}
+
+void InputDevice::cancelVibrate(int32_t token) {
+    size_t numMappers = mMappers.size();
+    for (size_t i = 0; i < numMappers; i++) {
+        InputMapper* mapper = mMappers[i];
+        mapper->cancelVibrate(token);
+    }
+}
+
 int32_t InputDevice::getMetaState() {
     int32_t result = 0;
     size_t numMappers = mMappers.size();
@@ -1739,6 +1792,13 @@
     return false;
 }
 
+void InputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
+        int32_t token) {
+}
+
+void InputMapper::cancelVibrate(int32_t token) {
+}
+
 int32_t InputMapper::getMetaState() {
     return 0;
 }
@@ -1796,6 +1856,120 @@
 }
 
 
+// --- VibratorInputMapper ---
+
+VibratorInputMapper::VibratorInputMapper(InputDevice* device) :
+        InputMapper(device), mVibrating(false) {
+}
+
+VibratorInputMapper::~VibratorInputMapper() {
+}
+
+uint32_t VibratorInputMapper::getSources() {
+    return 0;
+}
+
+void VibratorInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
+    InputMapper::populateDeviceInfo(info);
+
+    info->setVibrator(true);
+}
+
+void VibratorInputMapper::process(const RawEvent* rawEvent) {
+    // TODO: Handle FF_STATUS, although it does not seem to be widely supported.
+}
+
+void VibratorInputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
+        int32_t token) {
+#if DEBUG_VIBRATOR
+    String8 patternStr;
+    for (size_t i = 0; i < patternSize; i++) {
+        if (i != 0) {
+            patternStr.append(", ");
+        }
+        patternStr.appendFormat("%lld", pattern[i]);
+    }
+    ALOGD("vibrate: deviceId=%d, pattern=[%s], repeat=%ld, token=%d",
+            getDeviceId(), patternStr.string(), repeat, token);
+#endif
+
+    mVibrating = true;
+    memcpy(mPattern, pattern, patternSize * sizeof(nsecs_t));
+    mPatternSize = patternSize;
+    mRepeat = repeat;
+    mToken = token;
+    mIndex = -1;
+
+    nextStep();
+}
+
+void VibratorInputMapper::cancelVibrate(int32_t token) {
+#if DEBUG_VIBRATOR
+    ALOGD("cancelVibrate: deviceId=%d, token=%d", getDeviceId(), token);
+#endif
+
+    if (mVibrating && mToken == token) {
+        stopVibrating();
+    }
+}
+
+void VibratorInputMapper::timeoutExpired(nsecs_t when) {
+    if (mVibrating) {
+        if (when >= mNextStepTime) {
+            nextStep();
+        } else {
+            getContext()->requestTimeoutAtTime(mNextStepTime);
+        }
+    }
+}
+
+void VibratorInputMapper::nextStep() {
+    mIndex += 1;
+    if (size_t(mIndex) >= mPatternSize) {
+        if (mRepeat < 0) {
+            // We are done.
+            stopVibrating();
+            return;
+        }
+        mIndex = mRepeat;
+    }
+
+    bool vibratorOn = mIndex & 1;
+    nsecs_t duration = mPattern[mIndex];
+    if (vibratorOn) {
+#if DEBUG_VIBRATOR
+        ALOGD("nextStep: sending vibrate deviceId=%d, duration=%lld",
+                getDeviceId(), duration);
+#endif
+        getEventHub()->vibrate(getDeviceId(), duration);
+    } else {
+#if DEBUG_VIBRATOR
+        ALOGD("nextStep: sending cancel vibrate deviceId=%d", getDeviceId());
+#endif
+        getEventHub()->cancelVibrate(getDeviceId());
+    }
+    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+    mNextStepTime = now + duration;
+    getContext()->requestTimeoutAtTime(mNextStepTime);
+#if DEBUG_VIBRATOR
+    ALOGD("nextStep: scheduled timeout in %0.3fms", duration * 0.000001f);
+#endif
+}
+
+void VibratorInputMapper::stopVibrating() {
+    mVibrating = false;
+#if DEBUG_VIBRATOR
+    ALOGD("stopVibrating: sending cancel vibrate deviceId=%d", getDeviceId());
+#endif
+    getEventHub()->cancelVibrate(getDeviceId());
+}
+
+void VibratorInputMapper::dump(String8& dump) {
+    dump.append(INDENT2 "Vibrator Input Mapper:\n");
+    dump.appendFormat(INDENT3 "Vibrating: %s\n", toString(mVibrating));
+}
+
+
 // --- KeyboardInputMapper ---
 
 KeyboardInputMapper::KeyboardInputMapper(InputDevice* device,
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index d29776d8..e5897e7 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -33,6 +33,14 @@
 #include <stddef.h>
 #include <unistd.h>
 
+// Maximum supported size of a vibration pattern.
+// Must be at least 2.
+#define MAX_VIBRATE_PATTERN_SIZE 100
+
+// Maximum allowable delay value in a vibration pattern before
+// which the delay will be truncated.
+#define MAX_VIBRATE_PATTERN_DELAY_NSECS (1000000 * 1000000000LL)
+
 namespace android {
 
 class InputDevice;
@@ -59,6 +67,9 @@
         // The visible touches option changed.
         CHANGE_SHOW_TOUCHES = 1 << 3,
 
+        // The keyboard layouts must be reloaded.
+        CHANGE_KEYBOARD_LAYOUTS = 1 << 4,
+
         // All devices must be reopened.
         CHANGE_MUST_REOPEN = 1 << 31,
     };
@@ -214,6 +225,9 @@
      * and provides information about all current input devices.
      */
     virtual void notifyInputDevicesChanged(const Vector<InputDeviceInfo>& inputDevices) = 0;
+
+    /* Gets the keyboard layout for a particular input device. */
+    virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const String8& inputDeviceDescriptor) = 0;
 };
 
 
@@ -267,6 +281,11 @@
      * The changes flag is a bitfield that indicates what has changed and whether
      * the input devices must all be reopened. */
     virtual void requestRefreshConfiguration(uint32_t changes) = 0;
+
+    /* Controls the vibrator of a particular input device. */
+    virtual void vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize,
+            ssize_t repeat, int32_t token) = 0;
+    virtual void cancelVibrate(int32_t deviceId, int32_t token) = 0;
 };
 
 
@@ -334,6 +353,10 @@
 
     virtual void requestRefreshConfiguration(uint32_t changes);
 
+    virtual void vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize,
+            ssize_t repeat, int32_t token);
+    virtual void cancelVibrate(int32_t deviceId, int32_t token);
+
 protected:
     // These members are protected so they can be instrumented by test cases.
     virtual InputDevice* createDeviceLocked(int32_t deviceId,
@@ -466,6 +489,8 @@
     int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode);
     bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
             const int32_t* keyCodes, uint8_t* outFlags);
+    void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token);
+    void cancelVibrate(int32_t token);
 
     int32_t getMetaState();
 
@@ -848,6 +873,9 @@
     virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode);
     virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
             const int32_t* keyCodes, uint8_t* outFlags);
+    virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
+            int32_t token);
+    virtual void cancelVibrate(int32_t token);
 
     virtual int32_t getMetaState();
 
@@ -880,6 +908,35 @@
 };
 
 
+class VibratorInputMapper : public InputMapper {
+public:
+    VibratorInputMapper(InputDevice* device);
+    virtual ~VibratorInputMapper();
+
+    virtual uint32_t getSources();
+    virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
+    virtual void process(const RawEvent* rawEvent);
+
+    virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
+            int32_t token);
+    virtual void cancelVibrate(int32_t token);
+    virtual void timeoutExpired(nsecs_t when);
+    virtual void dump(String8& dump);
+
+private:
+    bool mVibrating;
+    nsecs_t mPattern[MAX_VIBRATE_PATTERN_SIZE];
+    size_t mPatternSize;
+    ssize_t mRepeat;
+    int32_t mToken;
+    ssize_t mIndex;
+    nsecs_t mNextStepTime;
+
+    void nextStep();
+    void stopVibrating();
+};
+
+
 class KeyboardInputMapper : public InputMapper {
 public:
     KeyboardInputMapper(InputDevice* device, uint32_t source, int32_t keyboardType);
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index e59af4e..a4b7585 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -170,6 +170,10 @@
     virtual void notifyInputDevicesChanged(const Vector<InputDeviceInfo>& inputDevices) {
         mInputDevices = inputDevices;
     }
+
+    virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const String8& inputDeviceDescriptor) {
+        return NULL;
+    }
 };
 
 
@@ -646,6 +650,16 @@
         return NULL;
     }
 
+    virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& map) {
+        return false;
+    }
+
+    virtual void vibrate(int32_t deviceId, nsecs_t duration) {
+    }
+
+    virtual void cancelVibrate(int32_t deviceId) {
+    }
+
     virtual bool isExternal(int32_t deviceId) const {
         return false;
     }
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 352decf..359074a 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -875,6 +875,19 @@
         return null;
     }
 
+    @Override
+    public boolean isActiveNetworkMetered() {
+        enforceAccessPermission();
+        final NetworkState state = getNetworkStateUnchecked(mActiveDefaultNetwork);
+        if (state != null) {
+            try {
+                return mPolicyManager.isNetworkMetered(state);
+            } catch (RemoteException e) {
+            }
+        }
+        return false;
+    }
+
     public boolean setRadios(boolean turnOn) {
         boolean result = true;
         enforceChangePermission();
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index ca7241c..a474cec 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -118,7 +118,7 @@
 public class InputMethodManagerService extends IInputMethodManager.Stub
         implements ServiceConnection, Handler.Callback {
     static final boolean DEBUG = false;
-    static final String TAG = "InputManagerService";
+    static final String TAG = "InputMethodManagerService";
 
     static final int MSG_SHOW_IM_PICKER = 1;
     static final int MSG_SHOW_IM_SUBTYPE_PICKER = 2;
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 3db4601..b22be76 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -100,7 +100,7 @@
     private int mDisabledNotifications;
 
     private NotificationRecord mVibrateNotification;
-    private Vibrator mVibrator = new Vibrator();
+    private Vibrator mVibrator;
 
     // for enabling and disabling notification pulse behavior
     private boolean mScreenOn = true;
@@ -398,6 +398,7 @@
     {
         super();
         mContext = context;
+        mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
         mAm = ActivityManagerNative.getDefault();
         mSound = new NotificationPlayer(TAG);
         mSound.setUsesWakeLock(context);
diff --git a/services/java/com/android/server/NsdService.java b/services/java/com/android/server/NsdService.java
index a3ac8d0..8014e27 100644
--- a/services/java/com/android/server/NsdService.java
+++ b/services/java/com/android/server/NsdService.java
@@ -167,6 +167,18 @@
                                 NsdManager.ERROR);
                     }
                     break;
+                case NsdManager.UNREGISTER_SERVICE:
+                    if (DBG) Slog.d(TAG, "unregister service");
+                    clientInfo = mClients.get(msg.replyTo);
+                    int regId = msg.arg1;
+                    if (clientInfo.mRegisteredIds.remove(new Integer(regId)) &&
+                            unregisterService(regId)) {
+                        mReplyChannel.replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_SUCCEEDED);
+                    } else {
+                        mReplyChannel.replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
+                                NsdManager.ERROR);
+                    }
+                    break;
                 case NsdManager.UPDATE_SERVICE:
                     if (DBG) Slog.d(TAG, "Update service");
                     //TODO: implement
@@ -237,6 +249,8 @@
     }
 
     public Messenger getMessenger() {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET,
+            "NsdService");
         return new Messenger(mAsyncServiceHandler);
     }
 
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 2d2a881..9a371c6 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -37,6 +37,7 @@
 import android.hardware.SensorEvent;
 import android.hardware.SensorEventListener;
 import android.hardware.SensorManager;
+import android.hardware.SystemSensorManager;
 import android.os.BatteryManager;
 import android.os.BatteryStats;
 import android.os.Binder;
@@ -2946,7 +2947,7 @@
     }
 
     void systemReady() {
-        mSensorManager = new SensorManager(mHandlerThread.getLooper());
+        mSensorManager = new SystemSensorManager(mHandlerThread.getLooper());
         mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
         // don't bother with the light sensor if auto brightness is handled in hardware
         if (mUseSoftwareAutoBrightness) {
diff --git a/services/java/com/android/server/RecognitionManagerService.java b/services/java/com/android/server/RecognitionManagerService.java
index 8e55512..85224d8 100644
--- a/services/java/com/android/server/RecognitionManagerService.java
+++ b/services/java/com/android/server/RecognitionManagerService.java
@@ -75,7 +75,10 @@
             try {
                 mContext.getPackageManager().getServiceInfo(comp, 0);
             } catch (NameNotFoundException e) {
-                setCurRecognizer(null);
+                comp = findAvailRecognizer(null);
+                if (comp != null) {
+                    setCurRecognizer(comp);
+                }
             }
         } else {
             comp = findAvailRecognizer(null);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 241d04ff..02c4d5a 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -51,6 +51,7 @@
 import com.android.internal.widget.LockSettingsService;
 import com.android.server.accessibility.AccessibilityManagerService;
 import com.android.server.am.ActivityManagerService;
+import com.android.server.input.InputManagerService;
 import com.android.server.net.NetworkPolicyManagerService;
 import com.android.server.net.NetworkStatsService;
 import com.android.server.pm.PackageManagerService;
@@ -115,6 +116,7 @@
         LightsService lights = null;
         PowerManagerService power = null;
         BatteryService battery = null;
+        VibratorService vibrator = null;
         AlarmManagerService alarm = null;
         NetworkManagementService networkManagement = null;
         NetworkStatsService networkStats = null;
@@ -136,6 +138,7 @@
         ThrottleService throttle = null;
         NetworkTimeUpdateService networkTimeUpdater = null;
         CommonTimeManagementService commonTimeMgmtService = null;
+        InputManagerService inputManager = null;
 
         // Critical services...
         try {
@@ -203,7 +206,8 @@
             ServiceManager.addService("battery", battery);
 
             Slog.i(TAG, "Vibrator Service");
-            ServiceManager.addService("vibrator", new VibratorService(context));
+            vibrator = new VibratorService(context);
+            ServiceManager.addService("vibrator", vibrator);
 
             // only initialize the power service after we have started the
             // lights service, content providers and the battery service.
@@ -222,7 +226,8 @@
                     factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,
                     !firstBoot);
             ServiceManager.addService(Context.WINDOW_SERVICE, wm);
-            ServiceManager.addService(Context.INPUT_SERVICE, wm.getInputManagerService());
+            inputManager = wm.getInputManagerService();
+            ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
 
             ActivityManagerService.self().setWindowManager(wm);
 
@@ -645,6 +650,12 @@
 
         // It is now time to start up the app processes...
 
+        try {
+            vibrator.systemReady();
+        } catch (Throwable e) {
+            reportWtf("making Vibrator Service ready", e);
+        }
+
         if (devicePolicy != null) {
             try {
                 devicePolicy.systemReady();
@@ -714,6 +725,7 @@
         final TextServicesManagerService textServiceManagerServiceF = tsms;
         final StatusBarManagerService statusBarF = statusBar;
         final DreamManagerService dreamyF = dreamy;
+        final InputManagerService inputManagerF = inputManager;
 
         // 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
@@ -825,6 +837,11 @@
                 } catch (Throwable e) {
                     reportWtf("making DreamManagerService ready", e);
                 }
+                try {
+                    if (inputManagerF != null) inputManagerF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making InputManagerService ready", e);
+                }
             }
         });
 
diff --git a/services/java/com/android/server/VibratorService.java b/services/java/com/android/server/VibratorService.java
index de25747..6282c31 100755
--- a/services/java/com/android/server/VibratorService.java
+++ b/services/java/com/android/server/VibratorService.java
@@ -21,6 +21,8 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
+import android.database.ContentObserver;
+import android.hardware.input.InputManager;
 import android.os.Handler;
 import android.os.IVibratorService;
 import android.os.PowerManager;
@@ -29,18 +31,41 @@
 import android.os.IBinder;
 import android.os.Binder;
 import android.os.SystemClock;
+import android.os.Vibrator;
 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 VibratorService extends IVibratorService.Stub {
+public class VibratorService extends IVibratorService.Stub
+        implements InputManager.InputDeviceListener {
     private static final String TAG = "VibratorService";
 
     private final LinkedList<Vibration> mVibrations;
     private Vibration mCurrentVibration;
     private final WorkSource mTmpWorkSource = new WorkSource();
+    private final Handler mH = new Handler();
+
+    private final Context mContext;
+    private final PowerManager.WakeLock mWakeLock;
+    private InputManager mIm;
+
+    volatile VibrateThread mThread;
+
+    // mInputDeviceVibrators lock should be acquired after mVibrations lock, if both are
+    // to be acquired
+    private final ArrayList<Vibrator> mInputDeviceVibrators = new ArrayList<Vibrator>();
+    private boolean mVibrateInputDevicesSetting; // guarded by mInputDeviceVibrators
+    private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators
+
+    native static boolean vibratorExists();
+    native static void vibratorOn(long milliseconds);
+    native static void vibratorOff();
 
     private class Vibration implements IBinder.DeathRecipient {
         private final IBinder mToken;
@@ -112,10 +137,23 @@
         context.registerReceiver(mIntentReceiver, filter);
     }
 
-    public boolean hasVibrator() {
-        return vibratorExists();
+    public void systemReady() {
+        mIm = (InputManager)mContext.getSystemService(Context.INPUT_SERVICE);
+        mContext.getContentResolver().registerContentObserver(
+                Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES), true,
+                new ContentObserver(mH) {
+                    @Override
+                    public void onChange(boolean selfChange) {
+                        updateInputDeviceVibrators();
+                    }
+                });
+        updateInputDeviceVibrators();
     }
-    
+
+    public boolean hasVibrator() {
+        return doVibratorExists();
+    }
+
     public void vibrate(long milliseconds, IBinder token) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
                 != PackageManager.PERMISSION_GRANTED) {
@@ -131,6 +169,7 @@
             // longer than milliseconds.
             return;
         }
+
         Vibration vib = new Vibration(token, milliseconds, uid);
         synchronized (mVibrations) {
             removeVibrationLocked(token);
@@ -240,7 +279,7 @@
             }
             mThread = null;
         }
-        vibratorOff();
+        doVibratorOff();
         mH.removeCallbacks(mVibrationRunnable);
     }
 
@@ -257,7 +296,7 @@
     // Lock held on mVibrations
     private void startVibrationLocked(final Vibration vib) {
         if (vib.mTimeout != 0) {
-            vibratorOn(vib.mTimeout);
+            doVibratorOn(vib.mTimeout);
             mH.postDelayed(mVibrationRunnable, vib.mTimeout);
         } else {
             // mThread better be null here. doCancelVibrate should always be
@@ -295,6 +334,94 @@
         }
     }
 
+    private void updateInputDeviceVibrators() {
+        synchronized (mVibrations) {
+            doCancelVibrateLocked();
+
+            synchronized (mInputDeviceVibrators) {
+                mVibrateInputDevicesSetting = false;
+                try {
+                    mVibrateInputDevicesSetting = Settings.System.getInt(mContext.getContentResolver(),
+                            Settings.System.VIBRATE_INPUT_DEVICES) > 0;
+                } catch (SettingNotFoundException snfe) {
+                }
+
+                if (mVibrateInputDevicesSetting) {
+                    if (!mInputDeviceListenerRegistered) {
+                        mInputDeviceListenerRegistered = true;
+                        mIm.registerInputDeviceListener(this, mH);
+                    }
+                } else {
+                    if (mInputDeviceListenerRegistered) {
+                        mInputDeviceListenerRegistered = false;
+                        mIm.unregisterInputDeviceListener(this);
+                    }
+                }
+
+                mInputDeviceVibrators.clear();
+                if (mVibrateInputDevicesSetting) {
+                    int[] ids = mIm.getInputDeviceIds();
+                    for (int i = 0; i < ids.length; i++) {
+                        InputDevice device = mIm.getInputDevice(ids[i]);
+                        Vibrator vibrator = device.getVibrator();
+                        if (vibrator.hasVibrator()) {
+                            mInputDeviceVibrators.add(vibrator);
+                        }
+                    }
+                }
+            }
+
+            startNextVibrationLocked();
+        }
+    }
+
+    @Override
+    public void onInputDeviceAdded(int deviceId) {
+        updateInputDeviceVibrators();
+    }
+
+    @Override
+    public void onInputDeviceChanged(int deviceId) {
+        updateInputDeviceVibrators();
+    }
+
+    @Override
+    public void onInputDeviceRemoved(int deviceId) {
+        updateInputDeviceVibrators();
+    }
+
+    private boolean doVibratorExists() {
+        synchronized (mInputDeviceVibrators) {
+            return !mInputDeviceVibrators.isEmpty() || vibratorExists();
+        }
+    }
+
+    private void doVibratorOn(long millis) {
+        synchronized (mInputDeviceVibrators) {
+            final int vibratorCount = mInputDeviceVibrators.size();
+            if (vibratorCount != 0) {
+                for (int i = 0; i < vibratorCount; i++) {
+                    mInputDeviceVibrators.get(i).vibrate(millis);
+                }
+            } else {
+                vibratorOn(millis);
+            }
+        }
+    }
+
+    private void doVibratorOff() {
+        synchronized (mInputDeviceVibrators) {
+            final int vibratorCount = mInputDeviceVibrators.size();
+            if (vibratorCount != 0) {
+                for (int i = 0; i < vibratorCount; i++) {
+                    mInputDeviceVibrators.get(i).cancel();
+                }
+            } else {
+                vibratorOff();
+            }
+        }
+    }
+
     private class VibrateThread extends Thread {
         final Vibration mVibration;
         boolean mDone;
@@ -350,7 +477,7 @@
                         // duration is saved for delay() at top of loop
                         duration = pattern[index++];
                         if (duration > 0) {
-                            VibratorService.this.vibratorOn(duration);
+                            VibratorService.this.doVibratorOn(duration);
                         }
                     } else {
                         if (repeat < 0) {
@@ -394,15 +521,4 @@
             }
         }
     };
-
-    private Handler mH = new Handler();
-
-    private final Context mContext;
-    private final PowerManager.WakeLock mWakeLock;
-
-    volatile VibrateThread mThread;
-
-    native static boolean vibratorExists();
-    native static void vibratorOn(long milliseconds);
-    native static void vibratorOff();
 }
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index e2a2c83..bb38cd9 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -1202,6 +1202,8 @@
         pw.println();
         pw.println("WifiWatchdogStateMachine dump");
         mWifiWatchdogStateMachine.dump(pw);
+        pw.println("WifiStateMachine dump");
+        mWifiStateMachine.dump(fd, pw, args);
     }
 
     private class WifiLock extends DeathRecipient {
diff --git a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 31aa21e..889fbe4 100644
--- a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -16,6 +16,7 @@
 
 package com.android.server.accessibility;
 
+import com.android.server.accessibility.TouchExplorer.GestureListener;
 import com.android.server.input.InputFilter;
 
 import android.content.Context;
@@ -36,6 +37,8 @@
 
     private final Context mContext;
 
+    private final GestureListener mGestureListener;
+
     /**
      * This is an interface for explorers that take a {@link MotionEvent}
      * stream and perform touch exploration of the screen content.
@@ -64,11 +67,13 @@
     }
 
     private TouchExplorer mTouchExplorer;
+
     private int mTouchscreenSourceDeviceId;
 
-    public AccessibilityInputFilter(Context context) {
+    public AccessibilityInputFilter(Context context, GestureListener gestureListener) {
         super(context.getMainLooper());
         mContext = context;
+        mGestureListener = gestureListener;
     }
 
     @Override
@@ -76,7 +81,7 @@
         if (DEBUG) {
             Slog.d(TAG, "Accessibility input filter installed.");
         }
-        mTouchExplorer = new TouchExplorer(this, mContext);
+        mTouchExplorer = new TouchExplorer(this, mContext, mGestureListener);
         super.onInstalled();
     }
 
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index c99aa02..ed2a6c0 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -16,11 +16,14 @@
 
 package com.android.server.accessibility;
 
+import static android.accessibilityservice.AccessibilityServiceInfo.DEFAULT;
+import static android.accessibilityservice.AccessibilityServiceInfo.INCLUDE_NOT_IMPORTANT_VIEWS;
+
 import android.Manifest;
 import android.accessibilityservice.AccessibilityService;
 import android.accessibilityservice.AccessibilityServiceInfo;
+import android.accessibilityservice.IAccessibilityServiceClient;
 import android.accessibilityservice.IAccessibilityServiceConnection;
-import android.accessibilityservice.IEventListener;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -35,6 +38,7 @@
 import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
@@ -55,8 +59,7 @@
 import android.view.accessibility.IAccessibilityManagerClient;
 
 import com.android.internal.content.PackageMonitor;
-import com.android.internal.os.HandlerCaller;
-import com.android.internal.os.HandlerCaller.SomeArgs;
+import com.android.server.accessibility.TouchExplorer.GestureListener;
 import com.android.server.wm.WindowManagerService;
 
 import org.xmlpull.v1.XmlPullParserException;
@@ -80,7 +83,7 @@
  * @hide
  */
 public class AccessibilityManagerService extends IAccessibilityManager.Stub
-        implements HandlerCaller.Callback {
+        implements GestureListener {
 
     private static final boolean DEBUG = false;
 
@@ -93,12 +96,8 @@
 
     private static final int OWN_PROCESS_ID = android.os.Process.myPid();
 
-    private static final int DO_SET_SERVICE_INFO = 10;
-
     private static int sNextWindowId;
 
-    final HandlerCaller mCaller;
-
     final Context mContext;
 
     final Object mLock = new Object();
@@ -152,7 +151,7 @@
             int eventType = message.arg1;
 
             synchronized (mLock) {
-                notifyEventListenerLocked(service, eventType);
+                notifyAccessibilityEventLocked(service, eventType);
             }
         }
     };
@@ -165,7 +164,6 @@
     public AccessibilityManagerService(Context context) {
         mContext = context;
         mPackageManager = mContext.getPackageManager();
-        mCaller = new HandlerCaller(context, this);
         mWindowManagerService = (WindowManagerService) ServiceManager.getService(
                 Context.WINDOW_SERVICE);
         mSecurityPolicy = new SecurityPolicy();
@@ -395,32 +393,6 @@
         }
     }
 
-    public void executeMessage(Message message) {
-        switch (message.what) {
-            case DO_SET_SERVICE_INFO: {
-                SomeArgs arguments = ((SomeArgs) message.obj);
-
-                AccessibilityServiceInfo info = (AccessibilityServiceInfo) arguments.arg1;
-                Service service = (Service) arguments.arg2;
-
-                synchronized (mLock) {
-                    // If the XML manifest had data to configure the service its info
-                    // should be already set. In such a case update only the dynamically
-                    // configurable properties.
-                    AccessibilityServiceInfo oldInfo = service.mAccessibilityServiceInfo;
-                    if (oldInfo != null) {
-                        oldInfo.updateDynamicallyConfigurableProperties(info);
-                        service.setDynamicallyConfigurableProperties(oldInfo);
-                    } else {
-                        service.setDynamicallyConfigurableProperties(info);
-                    }
-                }
-            } return;
-            default:
-                Slog.w(LOG_TAG, "Unknown message type: " + message.what);
-        }
-    }
-
     public int addAccessibilityInteractionConnection(IWindow windowToken,
             IAccessibilityInteractionConnection connection) throws RemoteException {
         synchronized (mLock) {
@@ -455,7 +427,7 @@
         }
     }
 
-    public void registerUiTestAutomationService(IEventListener listener,
+    public void registerUiTestAutomationService(IAccessibilityServiceClient serviceClient,
             AccessibilityServiceInfo accessibilityServiceInfo) {
         mSecurityPolicy.enforceCallingPermission(Manifest.permission.RETRIEVE_WINDOW_CONTENT,
                 FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE);
@@ -480,18 +452,45 @@
         }
         // Hook the automation service up.
         mUiAutomationService = new Service(componentName, accessibilityServiceInfo, true);
-        mUiAutomationService.onServiceConnected(componentName, listener.asBinder());
+        mUiAutomationService.onServiceConnected(componentName, serviceClient.asBinder());
     }
 
-    public void unregisterUiTestAutomationService(IEventListener listener) {
+    public void unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient) {
         synchronized (mLock) {
             // Automation service is not bound, so pretend it died to perform clean up.
-            if (mUiAutomationService != null) {
+            if (mUiAutomationService != null
+                    && mUiAutomationService.mServiceInterface == serviceClient) {
                 mUiAutomationService.binderDied();
             }
         }
     }
 
+    @Override
+    public void onGesture(int gestureId) {
+        synchronized (mLock) {
+            final boolean dispatched = notifyGestureLocked(gestureId, false);
+            if (!dispatched) {
+                notifyGestureLocked(gestureId, true);
+            }
+        }
+    }
+
+    private boolean notifyGestureLocked(int gestureId, boolean isDefault) {
+        final int serviceCount = mServices.size();
+        for (int i = 0; i < serviceCount; i++) {
+            Service service = mServices.get(i);
+            if (service.mIsDefault == isDefault) {
+                try {
+                    service.mServiceInterface.onGesture(gestureId);
+                    return true;
+                } catch (RemoteException re) {
+                    Slog.e(LOG_TAG, "Error dispatching gesture.");
+                }
+            }
+        }
+        return false;
+    }
+
     /**
      * Removes an AccessibilityInteractionConnection.
      *
@@ -588,13 +587,13 @@
     }
 
     /**
-     * Notifies a service for a scheduled event given the event type.
+     * Notifies an accessibility service client for a scheduled event given the event type.
      *
-     * @param service The service.
+     * @param service The service client.
      * @param eventType The type of the event to dispatch.
      */
-    private void notifyEventListenerLocked(Service service, int eventType) {
-        IEventListener listener = service.mServiceInterface;
+    private void notifyAccessibilityEventLocked(Service service, int eventType) {
+        IAccessibilityServiceClient listener = service.mServiceInterface;
 
         // If the service died/was disabled while the message for dispatching
         // the accessibility event was propagating the listener may be null.
@@ -699,6 +698,11 @@
             return false;
         }
 
+        if (!event.isImportantForAccessibility()
+                && !service.mIncludeNotImportantViews) {
+            return false;
+        }
+
         int eventType = event.getEventType();
         if ((service.mEventTypes & eventType) != eventType) {
             return false;
@@ -864,7 +868,7 @@
             if (!mHasInputFilter) {
                 mHasInputFilter = true;
                 if (mInputFilter == null) {
-                    mInputFilter = new AccessibilityInputFilter(mContext);
+                    mInputFilter = new AccessibilityInputFilter(mContext, this);
                 }
                 mWindowManagerService.setInputFilter(mInputFilter);
             }
@@ -942,7 +946,7 @@
 
         IBinder mService;
 
-        IEventListener mServiceInterface;
+        IAccessibilityServiceClient mServiceInterface;
 
         int mEventTypes;
 
@@ -952,6 +956,8 @@
 
         boolean mIsDefault;
 
+        boolean mIncludeNotImportantViews;
+
         long mNotificationTimeout;
 
         ComponentName mComponentName;
@@ -983,6 +989,7 @@
                         mContext, 0, new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS), 0));
             } else {
                 mCanRetrieveScreenContent = true;
+                mIncludeNotImportantViews = true;
             }
             setDynamicallyConfigurableProperties(accessibilityServiceInfo);
         }
@@ -995,7 +1002,19 @@
                 mPackageNames.addAll(Arrays.asList(packageNames));
             }
             mNotificationTimeout = info.notificationTimeout;
-            mIsDefault = (info.flags & AccessibilityServiceInfo.DEFAULT) != 0;
+            mIsDefault = (info.flags & DEFAULT) != 0;
+
+            if (!mIsAutomation) {
+                final int targetSdkVersion =
+                    info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion;
+                // TODO: Uncomment this line and remove the line below when JellyBean
+                // SDK version is finalized.
+                // if (targetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN) {
+                if (targetSdkVersion > Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
+                    mIncludeNotImportantViews =
+                        (info.flags & INCLUDE_NOT_IMPORTANT_VIEWS) != 0;
+                }
+            }
 
             synchronized (mLock) {
                 tryAddServiceLocked(this);
@@ -1043,13 +1062,33 @@
             return (mEventTypes != 0 && mFeedbackType != 0 && mService != null);
         }
 
-        public void setServiceInfo(AccessibilityServiceInfo info) {
-            mCaller.obtainMessageOO(DO_SET_SERVICE_INFO, info, this).sendToTarget();
+        @Override
+        public AccessibilityServiceInfo getServiceInfo() {
+            synchronized (mLock) {
+                return mAccessibilityServiceInfo;
+            }
         }
 
+        @Override
+        public void setServiceInfo(AccessibilityServiceInfo info) {
+            synchronized (mLock) {
+                // If the XML manifest had data to configure the service its info
+                // should be already set. In such a case update only the dynamically
+                // configurable properties.
+                AccessibilityServiceInfo oldInfo = mAccessibilityServiceInfo;
+                if (oldInfo != null) {
+                    oldInfo.updateDynamicallyConfigurableProperties(info);
+                    setDynamicallyConfigurableProperties(oldInfo);
+                } else {
+                    setDynamicallyConfigurableProperties(info);
+                }
+            }
+        }
+
+        @Override
         public void onServiceConnected(ComponentName componentName, IBinder service) {
             mService = service;
-            mServiceInterface = IEventListener.Stub.asInterface(service);
+            mServiceInterface = IAccessibilityServiceClient.Stub.asInterface(service);
             try {
                 mServiceInterface.setConnection(this, mId);
                 synchronized (mLock) {
@@ -1060,6 +1099,7 @@
             }
         }
 
+        @Override
         public float findAccessibilityNodeInfoByViewId(int accessibilityWindowId,
                 long accessibilityNodeId, int viewId, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
@@ -1078,11 +1118,13 @@
                     }
                 }
             }
+            final int flags = (mIncludeNotImportantViews) ?
+                    AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
             final int interrogatingPid = Binder.getCallingPid();
             final long identityToken = Binder.clearCallingIdentity();
             try {
                 connection.findAccessibilityNodeInfoByViewId(accessibilityNodeId, viewId,
-                        interactionId, callback, interrogatingPid, interrogatingTid);
+                        interactionId, callback, flags, interrogatingPid, interrogatingTid);
             } catch (RemoteException re) {
                 if (DEBUG) {
                     Slog.e(LOG_TAG, "Error findAccessibilityNodeInfoByViewId().");
@@ -1093,6 +1135,7 @@
             return getCompatibilityScale(resolvedWindowId);
         }
 
+        @Override
         public float findAccessibilityNodeInfosByText(int accessibilityWindowId,
                 long accessibilityNodeId, String text, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
@@ -1112,11 +1155,13 @@
                     }
                 }
             }
+            final int flags = (mIncludeNotImportantViews) ?
+                    AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
             final int interrogatingPid = Binder.getCallingPid();
             final long identityToken = Binder.clearCallingIdentity();
             try {
                 connection.findAccessibilityNodeInfosByText(accessibilityNodeId, text,
-                        interactionId, callback, interrogatingPid, interrogatingTid);
+                        interactionId, callback, flags, interrogatingPid, interrogatingTid);
             } catch (RemoteException re) {
                 if (DEBUG) {
                     Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfosByText()");
@@ -1127,10 +1172,47 @@
             return getCompatibilityScale(resolvedWindowId);
         }
 
+        @Override
         public float findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
                 long accessibilityNodeId, int interactionId,
-                IAccessibilityInteractionConnectionCallback callback, long interrogatingTid,
-                int prefetchFlags)
+                IAccessibilityInteractionConnectionCallback callback, int flags,
+                long interrogatingTid) throws RemoteException {
+            final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId);
+            IAccessibilityInteractionConnection connection = null;
+            synchronized (mLock) {
+                mSecurityPolicy.enforceCanRetrieveWindowContent(this);
+                final boolean permissionGranted =
+                    mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
+                if (!permissionGranted) {
+                    return 0;
+                } else {
+                    connection = getConnectionLocked(resolvedWindowId);
+                    if (connection == null) {
+                        return 0;
+                    }
+                }
+            }
+            final int allFlags = flags | ((mIncludeNotImportantViews) ?
+                    AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0);
+            final int interrogatingPid = Binder.getCallingPid();
+            final long identityToken = Binder.clearCallingIdentity();
+            try {
+                connection.findAccessibilityNodeInfoByAccessibilityId(accessibilityNodeId,
+                        interactionId, callback, allFlags, interrogatingPid, interrogatingTid);
+            } catch (RemoteException re) {
+                if (DEBUG) {
+                    Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfoByAccessibilityId()");
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identityToken);
+            }
+            return getCompatibilityScale(resolvedWindowId);
+        }
+
+        @Override
+        public float findFocus(int accessibilityWindowId, long accessibilityNodeId,
+                int focusType, int interactionId,
+                IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
                 throws RemoteException {
             final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId);
             IAccessibilityInteractionConnection connection = null;
@@ -1147,14 +1229,16 @@
                     }
                 }
             }
+            final int flags = (mIncludeNotImportantViews) ?
+                    AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
             final int interrogatingPid = Binder.getCallingPid();
             final long identityToken = Binder.clearCallingIdentity();
             try {
-                connection.findAccessibilityNodeInfoByAccessibilityId(accessibilityNodeId,
-                        interactionId, callback, prefetchFlags, interrogatingPid, interrogatingTid);
+                connection.findFocus(accessibilityNodeId, interactionId, focusType, callback,
+                        flags, interrogatingPid, interrogatingTid);
             } catch (RemoteException re) {
                 if (DEBUG) {
-                    Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfoByAccessibilityId()");
+                    Slog.e(LOG_TAG, "Error calling findAccessibilityFocus()");
                 }
             } finally {
                 Binder.restoreCallingIdentity(identityToken);
@@ -1162,6 +1246,44 @@
             return getCompatibilityScale(resolvedWindowId);
         }
 
+        @Override
+        public float focusSearch(int accessibilityWindowId, long accessibilityNodeId,
+                int direction, int interactionId,
+                IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
+                throws RemoteException {
+            final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId);
+            IAccessibilityInteractionConnection connection = null;
+            synchronized (mLock) {
+                mSecurityPolicy.enforceCanRetrieveWindowContent(this);
+                final boolean permissionGranted =
+                    mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
+                if (!permissionGranted) {
+                    return 0;
+                } else {
+                    connection = getConnectionLocked(resolvedWindowId);
+                    if (connection == null) {
+                        return 0;
+                    }
+                }
+            }
+            final int flags = (mIncludeNotImportantViews) ?
+                    AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
+            final int interrogatingPid = Binder.getCallingPid();
+            final long identityToken = Binder.clearCallingIdentity();
+            try {
+                connection.focusSearch(accessibilityNodeId, interactionId, direction, callback,
+                        flags, interrogatingPid, interrogatingTid);
+            } catch (RemoteException re) {
+                if (DEBUG) {
+                    Slog.e(LOG_TAG, "Error calling accessibilityFocusSearch()");
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identityToken);
+            }
+            return getCompatibilityScale(resolvedWindowId);
+        }
+
+        @Override
         public boolean performAccessibilityAction(int accessibilityWindowId,
                 long accessibilityNodeId, int action, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) {
@@ -1179,11 +1301,13 @@
                     }
                 }
             }
+            final int flags = (mIncludeNotImportantViews) ?
+                    AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
             final int interrogatingPid = Binder.getCallingPid();
             final long identityToken = Binder.clearCallingIdentity();
             try {
                 connection.performAccessibilityAction(accessibilityNodeId, action, interactionId,
-                        callback, interrogatingPid, interrogatingTid);
+                        callback, flags, interrogatingPid, interrogatingTid);
             } catch (RemoteException re) {
                 if (DEBUG) {
                     Slog.e(LOG_TAG, "Error calling performAccessibilityAction()");
@@ -1263,22 +1387,35 @@
     }
 
     final class SecurityPolicy {
-        private static final int VALID_ACTIONS = AccessibilityNodeInfo.ACTION_FOCUS
-            | AccessibilityNodeInfo.ACTION_CLEAR_FOCUS | AccessibilityNodeInfo.ACTION_SELECT
-            | AccessibilityNodeInfo.ACTION_CLEAR_SELECTION;
+        private static final int VALID_ACTIONS =
+            AccessibilityNodeInfo.ACTION_CLICK
+            | AccessibilityNodeInfo.ACTION_FOCUS
+            | AccessibilityNodeInfo.ACTION_CLEAR_FOCUS
+            | AccessibilityNodeInfo.ACTION_SELECT
+            | AccessibilityNodeInfo.ACTION_CLEAR_SELECTION
+            | AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS
+            | AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS;
 
         private static final int RETRIEVAL_ALLOWING_EVENT_TYPES =
-            AccessibilityEvent.TYPE_VIEW_CLICKED | AccessibilityEvent.TYPE_VIEW_FOCUSED
-            | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT
-            | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED
-            | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED | AccessibilityEvent.TYPE_VIEW_SELECTED
+            AccessibilityEvent.TYPE_VIEW_CLICKED
+            | AccessibilityEvent.TYPE_VIEW_FOCUSED
+            | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER
+            | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT
+            | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED
+            | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED
+            | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
+            | AccessibilityEvent.TYPE_VIEW_SELECTED
             | AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
             | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED
-            | AccessibilityEvent.TYPE_VIEW_SCROLLED;
+            | AccessibilityEvent.TYPE_VIEW_SCROLLED
+            | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED
+            | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED;
 
         private static final int RETRIEVAL_ALLOWING_WINDOW_CHANGE_EVENT_TYPES =
-            AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER
-            | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT;
+            AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
+            | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER
+            | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT
+            | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED;
 
         private int mRetrievalAlowingWindowId;
 
diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java
index d07aa7a..5d01c77 100644
--- a/services/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/java/com/android/server/accessibility/TouchExplorer.java
@@ -20,17 +20,25 @@
 import static android.view.accessibility.AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START;
 
 import android.content.Context;
+import android.gesture.Gesture;
+import android.gesture.GestureLibraries;
+import android.gesture.GestureLibrary;
+import android.gesture.GesturePoint;
+import android.gesture.GestureStroke;
+import android.gesture.Prediction;
 import android.os.Handler;
 import android.util.Slog;
 import android.view.MotionEvent;
+import android.view.VelocityTracker;
 import android.view.ViewConfiguration;
 import android.view.WindowManagerPolicy;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 
-import com.android.server.accessibility.AccessibilityInputFilter.Explorer;
 import com.android.server.input.InputFilter;
+import com.android.internal.R;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 
 /**
@@ -54,34 +62,24 @@
  *
  * @hide
  */
-public class TouchExplorer implements Explorer {
+public class TouchExplorer {
+
     private static final boolean DEBUG = false;
 
     // Tag for logging received events.
-    private static final String LOG_TAG_RECEIVED = "TouchExplorer-RECEIVED";
-    // Tag for logging injected events.
-    private static final String LOG_TAG_INJECTED = "TouchExplorer-INJECTED";
-    // Tag for logging the current state.
-    private static final String LOG_TAG_STATE = "TouchExplorer-STATE";
+    private static final String LOG_TAG = "TouchExplorer";
 
     // States this explorer can be in.
     private static final int STATE_TOUCH_EXPLORING = 0x00000001;
     private static final int STATE_DRAGGING = 0x00000002;
     private static final int STATE_DELEGATING = 0x00000004;
-
-    // Invalid pointer ID.
-    private static final int INVALID_POINTER_ID = -1;
+    private static final int STATE_GESTURE_DETECTING = 0x00000005;
 
     // The time slop in milliseconds for activating an item after it has
     // been touch explored. Tapping on an item within this slop will perform
     // a click and tapping and holding down a long press.
     private static final long ACTIVATION_TIME_SLOP = 2000;
 
-    // This constant captures the current implementation detail that
-    // pointer IDs are between 0 and 31 inclusive (subject to change).
-    // (See MAX_POINTER_ID in frameworks/base/include/ui/Input.h)
-    private static final int MAX_POINTER_COUNT = 32;
-
     // The minimum of the cosine between the vectors of two moving
     // pointers so they can be considered moving in the same direction.
     private static final float MAX_DRAGGING_ANGLE_COS = 0.525321989f; // cos(pi/4)
@@ -92,6 +90,14 @@
     // Constant referring to the ids bits of all pointers.
     private static final int ALL_POINTER_ID_BITS = 0xFFFFFFFF;
 
+    // This constant captures the current implementation detail that
+    // pointer IDs are between 0 and 31 inclusive (subject to change).
+    // (See MAX_POINTER_ID in frameworks/base/include/ui/Input.h)
+    public static final int MAX_POINTER_COUNT = 32;
+
+    // Invalid pointer ID.
+    public static final int INVALID_POINTER_ID = -1;
+
     // Temporary array for storing pointer IDs.
     private final int[] mTempPointerIds = new int[MAX_POINTER_COUNT];
 
@@ -103,10 +109,6 @@
     // which delegates event processing to this touch explorer.
     private final InputFilter mInputFilter;
 
-    // Helper class for tracking pointers on the screen, for example which
-    // pointers are down, which are active, etc.
-    private final PointerTracker mPointerTracker;
-
     // Handle to the accessibility manager for firing accessibility events
     // announcing touch exploration gesture start and end.
     private final AccessibilityManager mAccessibilityManager;
@@ -132,21 +134,48 @@
     // Command for delayed sending of a long press.
     private final PerformLongPressDelayed mPerformLongPressDelayed;
 
+    private VelocityTracker mVelocityTracker;
+
+    private final ReceivedPointerTracker mReceivedPointerTracker;
+
+    private final InjectedPointerTracker mInjectedPointerTracker;
+
+    private final GestureListener mGestureListener;
+
+    /**
+     * Callback for gesture detection.
+     */
+    public interface GestureListener {
+
+        /**
+         * Called when a given gesture was performed.
+         *
+         * @param gestureId The gesture id.
+         */
+        public void onGesture(int gestureId);
+    }
+
     /**
      * Creates a new instance.
      *
      * @param inputFilter The input filter associated with this explorer.
      * @param context A context handle for accessing resources.
      */
-    public TouchExplorer(InputFilter inputFilter, Context context) {
+    public TouchExplorer(InputFilter inputFilter, Context context,
+            GestureListener gestureListener) {
+        mGestureListener = gestureListener;
+        mReceivedPointerTracker = new ReceivedPointerTracker(context);
+        mInjectedPointerTracker = new InjectedPointerTracker();
         mInputFilter = inputFilter;
         mTouchExplorationTapSlop =
-            ViewConfiguration.get(context).getScaledTouchExplorationTapSlop();
-        mPointerTracker = new PointerTracker(context);
+            ViewConfiguration.get(context).getScaledTouchExploreTapSlop();
         mHandler = new Handler(context.getMainLooper());
         mSendHoverDelayed = new SendHoverDelayed();
         mPerformLongPressDelayed = new PerformLongPressDelayed();
         mAccessibilityManager = AccessibilityManager.getInstance(context);
+        mGestureLibrary = GestureLibraries.fromRawResource(context, R.raw.accessibility_gestures);
+        mGestureLibrary.setOrientationStyle(4);
+        mGestureLibrary.load();
     }
 
     public void clear(MotionEvent event, int policyFlags) {
@@ -154,18 +183,14 @@
         clear();
     }
 
-    /**
-     * {@inheritDoc}
-     */
     public void onMotionEvent(MotionEvent event, int policyFlags) {
         if (DEBUG) {
-            Slog.d(LOG_TAG_RECEIVED, "Received event: " + event + ", policyFlags=0x"
+            Slog.d(LOG_TAG, "Received event: " + event + ", policyFlags=0x"
                     + Integer.toHexString(policyFlags));
-            Slog.d(LOG_TAG_STATE, getStateSymbolicName(mCurrentState));
+            Slog.d(LOG_TAG, getStateSymbolicName(mCurrentState));
         }
 
-        // Keep track of the pointers's state.
-        mPointerTracker.onReceivedMotionEvent(event);
+        mReceivedPointerTracker.onMotionEvent(event);
 
         switch(mCurrentState) {
             case STATE_TOUCH_EXPLORING: {
@@ -177,9 +202,11 @@
             case STATE_DELEGATING: {
                 handleMotionEventStateDelegating(event, policyFlags);
             } break;
-            default: {
+            case STATE_GESTURE_DETECTING: {
+                handleMotionEventGestureDetecting(event, policyFlags);
+            } break;
+            default:
                 throw new IllegalStateException("Illegal state: " + mCurrentState);
-            }
         }
     }
 
@@ -190,8 +217,14 @@
      * @param policyFlags The policy flags associated with the event.
      */
     private void handleMotionEventStateTouchExploring(MotionEvent event, int policyFlags) {
-        PointerTracker pointerTracker = mPointerTracker;
-        final int activePointerCount = pointerTracker.getActivePointerCount();
+        ReceivedPointerTracker receivedTracker = mReceivedPointerTracker;
+        InjectedPointerTracker injectedTracker = mInjectedPointerTracker;
+        final int activePointerCount = receivedTracker.getActivePointerCount();
+
+        if (mVelocityTracker == null) {
+            mVelocityTracker = VelocityTracker.obtain();
+        }
+        mVelocityTracker.addMovement(event);
 
         switch (event.getActionMasked()) {
             case MotionEvent.ACTION_DOWN:
@@ -205,9 +238,9 @@
                         mSendHoverDelayed.remove();
                         mPerformLongPressDelayed.remove();
                         // Send a hover for every finger down so the user gets feedback.
-                        final int pointerId = pointerTracker.getPrimaryActivePointerId();
+                        final int pointerId = receivedTracker.getPrimaryActivePointerId();
                         final int pointerIdBits = (1 << pointerId);
-                        final int lastAction = pointerTracker.getLastInjectedHoverAction();
+                        final int lastAction = injectedTracker.getLastInjectedHoverAction();
 
                         // Deliver hover enter with a delay to have a change to detect
                         // whether the user actually starts a scrolling gesture.
@@ -232,7 +265,7 @@
 
                         // If the down is in the time slop => schedule a long press.
                         final long pointerDownTime =
-                            pointerTracker.getReceivedPointerDownTime(pointerId);
+                            receivedTracker.getReceivedPointerDownTime(pointerId);
                         final long lastExploreTime = mLastTouchExploreEvent.getEventTime();
                         final long deltaTimeExplore = pointerDownTime - lastExploreTime;
                         if (deltaTimeExplore <= ACTIVATION_TIME_SLOP) {
@@ -247,7 +280,7 @@
                 }
             } break;
             case MotionEvent.ACTION_MOVE: {
-                final int pointerId = pointerTracker.getPrimaryActivePointerId();
+                final int pointerId = receivedTracker.getPrimaryActivePointerId();
                 final int pointerIndex = event.findPointerIndex(pointerId);
                 final int pointerIdBits = (1 << pointerId);
                 switch (activePointerCount) {
@@ -258,13 +291,27 @@
                         // Detect touch exploration gesture start by having one active pointer
                         // that moved more than a given distance.
                         if (!mTouchExploreGestureInProgress) {
-                            final float deltaX = pointerTracker.getReceivedPointerDownX(pointerId)
+                            final float deltaX = receivedTracker.getReceivedPointerDownX(pointerId)
                                 - event.getX(pointerIndex);
-                            final float deltaY = pointerTracker.getReceivedPointerDownY(pointerId)
+                            final float deltaY = receivedTracker.getReceivedPointerDownY(pointerId)
                                 - event.getY(pointerIndex);
                             final double moveDelta = Math.hypot(deltaX, deltaY);
 
                             if (moveDelta > mTouchExplorationTapSlop) {
+
+                                mVelocityTracker.computeCurrentVelocity(1000);
+                                final float maxAbsVelocity = Math.max(
+                                        Math.abs(mVelocityTracker.getXVelocity(pointerId)),
+                                        Math.abs(mVelocityTracker.getYVelocity(pointerId)));
+                                // TODO: Tune the velocity cut off and add a constant.
+                                if (maxAbsVelocity > 1000) {
+                                    clear(event, policyFlags);
+                                    mCurrentState = STATE_GESTURE_DETECTING;
+                                    event.setAction(MotionEvent.ACTION_DOWN);
+                                    handleMotionEventGestureDetecting(event, policyFlags);
+                                    return;
+                                }
+
                                 mTouchExploreGestureInProgress = true;
                                 sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_START);
                                 // Make sure the scheduled down/move event is sent.
@@ -272,7 +319,7 @@
                                 mPerformLongPressDelayed.remove();
                                 // If we have transitioned to exploring state from another one
                                 // we need to send a hover enter event here.
-                                final int lastAction = mPointerTracker.getLastInjectedHoverAction();
+                                final int lastAction = injectedTracker.getLastInjectedHoverAction();
                                 if (lastAction == MotionEvent.ACTION_HOVER_EXIT) {
                                     sendMotionEvent(event, MotionEvent.ACTION_HOVER_ENTER,
                                             pointerIdBits, policyFlags);
@@ -355,12 +402,12 @@
             } break;
             case MotionEvent.ACTION_UP:
             case MotionEvent.ACTION_POINTER_UP: {
-                final int pointerId = pointerTracker.getLastReceivedUpPointerId();
+                final int pointerId = receivedTracker.getLastReceivedUpPointerId();
                 final int pointerIdBits = (1 << pointerId);
                 switch (activePointerCount) {
                     case 0: {
                         // If the pointer that went up was not active we have nothing to do.
-                        if (!pointerTracker.wasLastReceivedUpPointerActive()) {
+                        if (!receivedTracker.wasLastReceivedUpPointerActive()) {
                             break;
                         }
 
@@ -381,7 +428,7 @@
                         if (mLastTouchExploreEvent != null) {
                             // If the down was not in the time slop => nothing else to do.
                             final long eventTime =
-                                pointerTracker.getLastReceivedUpPointerDownTime();
+                                receivedTracker.getLastReceivedUpPointerDownTime();
                             final long exploreTime = mLastTouchExploreEvent.getEventTime();
                             final long deltaTime = eventTime - exploreTime;
                             if (deltaTime > ACTIVATION_TIME_SLOP) {
@@ -422,14 +469,22 @@
                         }
                     } break;
                 }
+                if (mVelocityTracker != null) {
+                    mVelocityTracker.clear();
+                    mVelocityTracker = null;
+                }
             } break;
             case MotionEvent.ACTION_CANCEL: {
                 mSendHoverDelayed.remove();
                 mPerformLongPressDelayed.remove();
-                final int pointerId = pointerTracker.getPrimaryActivePointerId();
+                final int pointerId = receivedTracker.getPrimaryActivePointerId();
                 final int pointerIdBits = (1 << pointerId);                
                 ensureHoverExitSent(event, pointerIdBits, policyFlags);
                 clear();
+                if (mVelocityTracker != null) {
+                    mVelocityTracker.clear();
+                    mVelocityTracker = null;
+                }
             } break;
         }
     }
@@ -455,7 +510,7 @@
                 sendDownForAllActiveNotInjectedPointers(event, policyFlags);
             } break;
             case MotionEvent.ACTION_MOVE: {
-                final int activePointerCount = mPointerTracker.getActivePointerCount();
+                final int activePointerCount = mReceivedPointerTracker.getActivePointerCount();
                 switch (activePointerCount) {
                     case 1: {
                         // do nothing
@@ -487,7 +542,7 @@
                 }
             } break;
             case MotionEvent.ACTION_POINTER_UP: {
-                final int activePointerCount = mPointerTracker.getActivePointerCount();
+                final int activePointerCount = mReceivedPointerTracker.getActivePointerCount();
                 switch (activePointerCount) {
                     case 1: {
                         // Send an event to the end of the drag gesture.
@@ -525,7 +580,8 @@
             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 = mPointerTracker.getNotInjectedActivePointerCount();
+                final int notInjectedCount = getNotInjectedActivePointerCount(
+                        mReceivedPointerTracker, mInjectedPointerTracker);
                 if (notInjectedCount > 0) {
                     MotionEvent prototype = MotionEvent.obtain(event);
                     sendDownForAllActiveNotInjectedPointers(prototype, policyFlags);
@@ -533,7 +589,7 @@
             } break;
             case MotionEvent.ACTION_POINTER_UP: {
                 // No active pointers => go to initial state.
-                if (mPointerTracker.getActivePointerCount() == 0) {
+                if (mReceivedPointerTracker.getActivePointerCount() == 0) {
                     mCurrentState = STATE_TOUCH_EXPLORING;
                 }
             } break;
@@ -545,6 +601,72 @@
         sendMotionEventStripInactivePointers(event, policyFlags);
     }
 
+    private float mPreviousX;
+    private float mPreviousY;
+
+    private final ArrayList<GesturePoint> mStrokeBuffer = new ArrayList<GesturePoint>(100);
+
+    private static final int TOUCH_TOLERANCE = 3;
+    private static final float MIN_PREDICTION_SCORE = 2.0f;
+
+    private GestureLibrary mGestureLibrary;
+
+    private void handleMotionEventGestureDetecting(MotionEvent event, int policyFlags) {
+        switch (event.getActionMasked()) {
+            case MotionEvent.ACTION_DOWN: {
+                final float x = event.getX();
+                final float y = event.getY();
+                mPreviousX = x;
+                mPreviousY = y;
+                mStrokeBuffer.add(new GesturePoint(x, y, event.getEventTime()));
+            } break;
+            case MotionEvent.ACTION_MOVE: {
+                final float x = event.getX();
+                final float y = event.getY();
+                final float dX = Math.abs(x - mPreviousX);
+                final float dY = Math.abs(y - mPreviousY);
+                if (dX >= TOUCH_TOLERANCE || dY >= TOUCH_TOLERANCE) {
+                    mPreviousX = x;
+                    mPreviousY = y;
+                    mStrokeBuffer.add(new GesturePoint(x, y, event.getEventTime()));
+                }
+            } break;
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_POINTER_UP: {
+                float x = event.getX();
+                float y = event.getY();
+                mStrokeBuffer.add(new GesturePoint(x, y, event.getEventTime()));
+
+                Gesture gesture = new Gesture();
+                gesture.addStroke(new GestureStroke(mStrokeBuffer));
+
+                ArrayList<Prediction> predictions = mGestureLibrary.recognize(gesture);
+                if (!predictions.isEmpty()) {
+                    Prediction bestPrediction = predictions.get(0);
+                    if (bestPrediction.score >= MIN_PREDICTION_SCORE) {
+                        if (DEBUG) {
+                            Slog.i(LOG_TAG, "gesture: " + bestPrediction.name + " score: "
+                                    + bestPrediction.score);
+                        }
+                        try {
+                            final int gestureId = Integer.parseInt(bestPrediction.name);
+                            mGestureListener.onGesture(gestureId);
+                        } catch (NumberFormatException nfe) {
+                            Slog.w(LOG_TAG, "Non numeric gesture id:" + bestPrediction.name);
+                        }
+                    }
+                }
+
+                mStrokeBuffer.clear();
+                mCurrentState = STATE_TOUCH_EXPLORING;
+            } break;
+            case MotionEvent.ACTION_CANCEL: {
+                mStrokeBuffer.clear();
+                mCurrentState = STATE_TOUCH_EXPLORING;
+            } break;
+        }
+    }
+
     /**
      * Sends down events to the view hierarchy for all active pointers which are
      * not already being delivered i.e. pointers that are not yet injected.
@@ -553,14 +675,15 @@
      * @param policyFlags The policy flags associated with the event.
      */
     private void sendDownForAllActiveNotInjectedPointers(MotionEvent prototype, int policyFlags) {
-        final PointerTracker pointerTracker = mPointerTracker;
+        ReceivedPointerTracker receivedPointers = mReceivedPointerTracker;
+        InjectedPointerTracker injectedPointers = mInjectedPointerTracker;
         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 (pointerTracker.isInjectedPointerDown(pointerId)) {
+            if (injectedPointers.isInjectedPointerDown(pointerId)) {
                 pointerIdBits |= (1 << pointerId);
             }
         }
@@ -569,11 +692,11 @@
         for (int i = 0; i < pointerCount; i++) {
             final int pointerId = prototype.getPointerId(i);
             // Skip inactive pointers.
-            if (!pointerTracker.isActivePointer(pointerId)) {
+            if (!receivedPointers.isActivePointer(pointerId)) {
                 continue;
             }
             // Do not send event for already delivered pointers.
-            if (pointerTracker.isInjectedPointerDown(pointerId)) {
+            if (injectedPointers.isInjectedPointerDown(pointerId)) {
                 continue;
             }
             pointerIdBits |= (1 << pointerId);
@@ -590,7 +713,7 @@
      * @param policyFlags The policy flags associated with the event.
      */
     private void ensureHoverExitSent(MotionEvent prototype, int pointerIdBits, int policyFlags) {
-        final int lastAction = mPointerTracker.getLastInjectedHoverAction();
+        final int lastAction = mInjectedPointerTracker.getLastInjectedHoverAction();
         if (lastAction != MotionEvent.ACTION_HOVER_EXIT) {
             sendMotionEvent(prototype, MotionEvent.ACTION_HOVER_EXIT, pointerIdBits,
                     policyFlags);
@@ -605,13 +728,13 @@
      * @param policyFlags The policy flags associated with the event.
      */
     private void sendUpForInjectedDownPointers(MotionEvent prototype, int policyFlags) {
-        final PointerTracker pointerTracker = mPointerTracker;
+        final InjectedPointerTracker injectedTracked = mInjectedPointerTracker;
         int pointerIdBits = 0;
         final int pointerCount = prototype.getPointerCount();
         for (int i = 0; i < pointerCount; i++) {
             final int pointerId = prototype.getPointerId(i);
             // Skip non injected down pointers.
-            if (!pointerTracker.isInjectedPointerDown(pointerId)) {
+            if (!injectedTracked.isInjectedPointerDown(pointerId)) {
                 continue;
             }
             pointerIdBits |= (1 << pointerId);
@@ -627,18 +750,18 @@
      * @param policyFlags The policy flags associated with the event.
      */
     private void sendMotionEventStripInactivePointers(MotionEvent prototype, int policyFlags) {
-        PointerTracker pointerTracker = mPointerTracker;
+        ReceivedPointerTracker receivedTracker = mReceivedPointerTracker;
 
         // All pointers active therefore we just inject the event as is.
-        if (prototype.getPointerCount() == pointerTracker.getActivePointerCount()) {
+        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 (pointerTracker.getActivePointerCount() == 0
-                && !pointerTracker.wasLastReceivedUpPointerActive()) {
+        if (receivedTracker.getActivePointerCount() == 0
+                && !receivedTracker.wasLastReceivedUpPointerActive()) {
             return;
         }
 
@@ -647,7 +770,7 @@
         final int actionMasked = prototype.getActionMasked();
         final int actionPointerId = prototype.getPointerId(prototype.getActionIndex());
         if (actionMasked != MotionEvent.ACTION_MOVE) {
-            if (!pointerTracker.isActiveOrWasLastActiveUpPointer(actionPointerId)) {
+            if (!receivedTracker.isActiveOrWasLastActiveUpPointer(actionPointerId)) {
                 return;
             }
         }
@@ -658,7 +781,7 @@
         final int pointerCount = prototype.getPointerCount();
         for (int pointerIndex = 0; pointerIndex < pointerCount; pointerIndex++) {
             final int pointerId = prototype.getPointerId(pointerIndex);
-            if (pointerTracker.isActiveOrWasLastActiveUpPointer(pointerId)) {
+            if (receivedTracker.isActiveOrWasLastActiveUpPointer(pointerId)) {
                 pointerIdBits |= (1 << pointerId);
             }
         }
@@ -700,19 +823,20 @@
         if (action == MotionEvent.ACTION_DOWN) {
             event.setDownTime(event.getEventTime());
         } else {
-            event.setDownTime(mPointerTracker.getLastInjectedDownEventTime());
+            event.setDownTime(mInjectedPointerTracker.getLastInjectedDownEventTime());
         }
 
         if (DEBUG) {
-            Slog.d(LOG_TAG_INJECTED, "Injecting event: " + event + ", policyFlags=0x"
+            Slog.d(LOG_TAG, "Injecting event: " + event + ", policyFlags=0x"
                     + Integer.toHexString(policyFlags));
         }
 
         // Make sure that the user will see the event.
         policyFlags |= WindowManagerPolicy.FLAG_PASS_TO_USER;
-        mPointerTracker.onInjectedMotionEvent(event);
         mInputFilter.sendInputEvent(event, policyFlags);
 
+        mInjectedPointerTracker.onMotionEvent(event);
+
         if (event != prototype) {
             event.recycle();
         }
@@ -730,9 +854,9 @@
         switch (actionMasked) {
             case MotionEvent.ACTION_DOWN:
             case MotionEvent.ACTION_POINTER_DOWN: {
-                PointerTracker pointerTracker = mPointerTracker;
+                InjectedPointerTracker injectedTracker = mInjectedPointerTracker;
                 // Compute the action based on how many down pointers are injected.
-                if (pointerTracker.getInjectedPointerDownCount() == 0) {
+                if (injectedTracker.getInjectedPointerDownCount() == 0) {
                     return MotionEvent.ACTION_DOWN;
                 } else {
                     return (pointerIndex << MotionEvent.ACTION_POINTER_INDEX_SHIFT)
@@ -740,9 +864,9 @@
                 }
             }
             case MotionEvent.ACTION_POINTER_UP: {
-                PointerTracker pointerTracker = mPointerTracker;
+                InjectedPointerTracker injectedTracker = mInjectedPointerTracker;
                 // Compute the action based on how many down pointers are injected.
-                if (pointerTracker.getInjectedPointerDownCount() == 1) {
+                if (injectedTracker.getInjectedPointerDownCount() == 1) {
                     return MotionEvent.ACTION_UP;
                 } else {
                     return (pointerIndex << MotionEvent.ACTION_POINTER_INDEX_SHIFT)
@@ -761,9 +885,9 @@
      * @return True if the gesture is a dragging one.
      */
     private boolean isDraggingGesture(MotionEvent event) {
-        PointerTracker pointerTracker = mPointerTracker;
+        ReceivedPointerTracker receivedTracker = mReceivedPointerTracker;
         int[] pointerIds = mTempPointerIds;
-        pointerTracker.populateActivePointerIds(pointerIds);
+        receivedTracker.populateActivePointerIds(pointerIds);
 
         final int firstPtrIndex = event.findPointerIndex(pointerIds[0]);
         final int secondPtrIndex = event.findPointerIndex(pointerIds[1]);
@@ -775,9 +899,9 @@
 
         // Check if the pointers are moving in the same direction.
         final float firstDeltaX =
-            firstPtrX - pointerTracker.getReceivedPointerDownX(firstPtrIndex);
+            firstPtrX - receivedTracker.getReceivedPointerDownX(firstPtrIndex);
         final float firstDeltaY =
-            firstPtrY - pointerTracker.getReceivedPointerDownY(firstPtrIndex);
+            firstPtrY - receivedTracker.getReceivedPointerDownY(firstPtrIndex);
 
         if (firstDeltaX == 0 && firstDeltaY == 0) {
             return true;
@@ -791,9 +915,9 @@
             (firstMagnitude > 0) ? firstDeltaY / firstMagnitude : firstDeltaY;
 
         final float secondDeltaX =
-            secondPtrX - pointerTracker.getReceivedPointerDownX(secondPtrIndex);
+            secondPtrX - receivedTracker.getReceivedPointerDownX(secondPtrIndex);
         final float secondDeltaY =
-            secondPtrY - pointerTracker.getReceivedPointerDownY(secondPtrIndex);
+            secondPtrY - receivedTracker.getReceivedPointerDownY(secondPtrIndex);
 
         if (secondDeltaX == 0 && secondDeltaY == 0) {
             return true;
@@ -832,7 +956,8 @@
     public void clear() {
         mSendHoverDelayed.remove();
         mPerformLongPressDelayed.remove();
-        mPointerTracker.clear();
+        mReceivedPointerTracker.clear();
+        mInjectedPointerTracker.clear();
         mLastTouchExploreEvent = null;
         mCurrentState = STATE_TOUCH_EXPLORING;
         mTouchExploreGestureInProgress = false;
@@ -853,27 +978,253 @@
                 return "STATE_DRAGGING";
             case STATE_DELEGATING:
                 return "STATE_DELEGATING";
+            case STATE_GESTURE_DETECTING:
+                return "STATE_GESTURE_DETECTING";
             default:
                 throw new IllegalArgumentException("Unknown state: " + state);
         }
     }
 
     /**
-     * Helper class for tracking pointers and more specifically which of
-     * them are currently down, which are active, and which are delivered
-     * to the view hierarchy. The enclosing {@link TouchExplorer} uses the
-     * pointer state reported by this class to perform touch exploration.
-     * <p>
-     * The main purpose of this class is to allow the touch explorer to
-     * disregard pointers put down by accident by the user and not being
-     * involved in the interaction. For example, a blind user grabs the
-     * device with her left hand such that she touches the screen and she
-     * uses her right hand's index finger to explore the screen content.
-     * In this scenario the touches generated by the left hand are to be
-     * ignored.
+     * @return The number of non injected active pointers.
      */
-    class PointerTracker {
-        private static final String LOG_TAG = "PointerTracker";
+    private int getNotInjectedActivePointerCount(ReceivedPointerTracker receivedTracker,
+            InjectedPointerTracker injectedTracker) {
+        final int pointerState = receivedTracker.getActivePointers()
+                & ~injectedTracker.getInjectedPointersDown();
+        return Integer.bitCount(pointerState);
+    }
+
+    /**
+     * Class for delayed sending of long press.
+     */
+    private final class PerformLongPressDelayed implements Runnable {
+        private MotionEvent mEvent;
+        private int mPolicyFlags;
+
+        public void post(MotionEvent prototype, int policyFlags, long delay) {
+            mEvent = MotionEvent.obtain(prototype);
+            mPolicyFlags = policyFlags;
+            mHandler.postDelayed(this, delay);
+        }
+
+        public void remove() {
+            if (isPenidng()) {
+                mHandler.removeCallbacks(this);
+                clear();
+            }
+        }
+
+        private boolean isPenidng() {
+            return (mEvent != null);
+        }
+
+        @Override
+        public void run() {
+            mCurrentState = STATE_DELEGATING;
+            // Make sure the scheduled hover exit is delivered.
+            mSendHoverDelayed.remove();
+            final int pointerId = mReceivedPointerTracker.getPrimaryActivePointerId();
+            final int pointerIdBits = (1 << pointerId);
+            ensureHoverExitSent(mEvent, pointerIdBits, mPolicyFlags);
+
+            sendDownForAllActiveNotInjectedPointers(mEvent, mPolicyFlags);
+            mTouchExploreGestureInProgress = false;
+            mLastTouchExploreEvent = null;
+            clear();
+        }
+
+        private void clear() {
+            if (!isPenidng()) {
+                return;
+            }
+            mEvent.recycle();
+            mEvent = null;
+            mPolicyFlags = 0;
+        }
+    }
+
+    /**
+     * Class for delayed sending of hover events.
+     */
+    private final class SendHoverDelayed implements Runnable {
+        private MotionEvent mEvent;
+        private int mAction;
+        private int mPointerIdBits;
+        private int mPolicyFlags;
+
+        public void post(MotionEvent prototype, int action, int pointerIdBits, int policyFlags,
+                long delay) {
+            remove();
+            mEvent = MotionEvent.obtain(prototype);
+            mAction = action;
+            mPointerIdBits = pointerIdBits;
+            mPolicyFlags = policyFlags;
+            mHandler.postDelayed(this, delay);
+        }
+
+        public void remove() {
+            mHandler.removeCallbacks(this);
+            clear();
+        }
+
+        private boolean isPenidng() {
+            return (mEvent != null);
+        }
+
+        private void clear() {
+            if (!isPenidng()) {
+                return;
+            }
+            mEvent.recycle();
+            mEvent = null;
+            mAction = 0;
+            mPointerIdBits = -1;
+            mPolicyFlags = 0;
+        }
+
+        public void forceSendAndRemove() {
+            if (isPenidng()) {
+                run();
+                remove();
+            }
+        }
+
+        public void run() {
+            if (DEBUG) {
+                if (mAction == MotionEvent.ACTION_HOVER_ENTER) {
+                    Slog.d(LOG_TAG, "Injecting: " + MotionEvent.ACTION_HOVER_ENTER);
+                } else if (mAction == MotionEvent.ACTION_HOVER_MOVE) {
+                    Slog.d(LOG_TAG, "Injecting: MotionEvent.ACTION_HOVER_MOVE");
+                } else if (mAction == MotionEvent.ACTION_HOVER_EXIT) {
+                    Slog.d(LOG_TAG, "Injecting: MotionEvent.ACTION_HOVER_EXIT");
+                }
+            }
+
+            sendMotionEvent(mEvent, mAction, mPointerIdBits, mPolicyFlags);
+            clear();
+        }
+    }
+
+    @Override
+    public String toString() {
+        return LOG_TAG;
+    }
+
+    class InjectedPointerTracker {
+        private static final String LOG_TAG_INJECTED_POINTER_TRACKER = "InjectedPointerTracker";
+
+        // Keep track of which pointers sent to the system are down.
+        private int mInjectedPointersDown;
+
+        // The time of the last injected down.
+        private long mLastInjectedDownEventTime;
+
+        // The action of the last injected hover event.
+        private int mLastInjectedHoverEventAction = MotionEvent.ACTION_HOVER_EXIT;
+
+        /**
+         * Processes an injected {@link MotionEvent} event.
+         *
+         * @param event The event to process.
+         */
+        public void onMotionEvent(MotionEvent event) {
+            final int action = event.getActionMasked();
+            switch (action) {
+                case MotionEvent.ACTION_DOWN:
+                case MotionEvent.ACTION_POINTER_DOWN: {
+                    final int pointerId = event.getPointerId(event.getActionIndex());
+                    final int pointerFlag = (1 << pointerId);
+                    mInjectedPointersDown |= pointerFlag;
+                    mLastInjectedDownEventTime = event.getDownTime();
+                } break;
+                case MotionEvent.ACTION_UP:
+                case MotionEvent.ACTION_POINTER_UP: {
+                    final int pointerId = event.getPointerId(event.getActionIndex());
+                    final int pointerFlag = (1 << pointerId);
+                    mInjectedPointersDown &= ~pointerFlag;
+                    if (mInjectedPointersDown == 0) {
+                        mLastInjectedDownEventTime = 0;
+                    }
+                } break;
+                case MotionEvent.ACTION_HOVER_ENTER:
+                case MotionEvent.ACTION_HOVER_MOVE:
+                case MotionEvent.ACTION_HOVER_EXIT: {
+                    mLastInjectedHoverEventAction = event.getActionMasked();
+                } break;
+            }
+            if (DEBUG) {
+                Slog.i(LOG_TAG_INJECTED_POINTER_TRACKER, "Injected pointer: " + toString());
+            }
+        }
+
+        /**
+         * Clears the internals state.
+         */
+        public void clear() {
+            mInjectedPointersDown = 0;
+        }
+
+        /**
+         * @return The time of the last injected down event.
+         */
+        public long getLastInjectedDownEventTime() {
+            return mLastInjectedDownEventTime;
+        }
+
+        /**
+         * @return The number of down pointers injected to the view hierarchy.
+         */
+        public int getInjectedPointerDownCount() {
+            return Integer.bitCount(mInjectedPointersDown);
+        }
+
+        /**
+         * @return The bits of the injected pointers that are down.
+         */
+        public int getInjectedPointersDown() {
+            return mInjectedPointersDown;
+        }
+
+        /**
+         * Whether an injected pointer is down.
+         *
+         * @param pointerId The unique pointer id.
+         * @return True if the pointer is down.
+         */
+        public boolean isInjectedPointerDown(int pointerId) {
+            final int pointerFlag = (1 << pointerId);
+            return (mInjectedPointersDown & pointerFlag) != 0;
+        }
+
+        /**
+         * @return The action of the last injected hover event.
+         */
+        public int getLastInjectedHoverAction() {
+            return mLastInjectedHoverEventAction;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder builder = new StringBuilder();
+            builder.append("=========================");
+            builder.append("\nDown pointers #");
+            builder.append(Integer.bitCount(mInjectedPointersDown));
+            builder.append(" [ ");
+            for (int i = 0; i < MAX_POINTER_COUNT; i++) {
+                if ((mInjectedPointersDown & i) != 0) {
+                    builder.append(i);
+                    builder.append(" ");
+                }
+            }
+            builder.append("]");
+            builder.append("\n=========================");
+            return builder.toString();
+        }
+    }
+
+    class ReceivedPointerTracker {
+        private static final String LOG_TAG_RECEIVED_POINTER_TRACKER = "ReceivedPointerTracker";
 
         // The coefficient by which to multiply
         // ViewConfiguration.#getScaledTouchSlop()
@@ -902,26 +1253,19 @@
         // Flag indicating that there is at least one active pointer moving.
         private boolean mHasMovingActivePointer;
 
-        // Keep track of which pointers sent to the system are down.
-        private int mInjectedPointersDown;
-
         // Keep track of the last up pointer data.
         private long mLastReceivedUpPointerDownTime;
         private int mLastReceivedUpPointerId;
         private boolean mLastReceivedUpPointerActive;
-
-        // The time of the last injected down.
-        private long mLastInjectedDownEventTime;
-
-        // The action of the last injected hover event.
-        private int mLastInjectedHoverEventAction = MotionEvent.ACTION_HOVER_EXIT;
+        private float mLastReceivedUpPointerDownX;
+        private float mLastReceivedUpPointerDownY;
 
         /**
          * Creates a new instance.
          *
          * @param context Context for looking up resources.
          */
-        public PointerTracker(Context context) {
+        public ReceivedPointerTracker(Context context) {
             mThresholdActivePointer =
                 ViewConfiguration.get(context).getScaledTouchSlop() * COEFFICIENT_ACTIVE_POINTER;
         }
@@ -937,10 +1281,11 @@
             mActivePointers = 0;
             mPrimaryActivePointerId = 0;
             mHasMovingActivePointer = false;
-            mInjectedPointersDown = 0;
             mLastReceivedUpPointerDownTime = 0;
             mLastReceivedUpPointerId = 0;
             mLastReceivedUpPointerActive = false;
+            mLastReceivedUpPointerDownX = 0;
+            mLastReceivedUpPointerDownY = 0;
         }
 
         /**
@@ -948,12 +1293,10 @@
          *
          * @param event The event to process.
          */
-        public void onReceivedMotionEvent(MotionEvent event) {
+        public void onMotionEvent(MotionEvent event) {
             final int action = event.getActionMasked();
             switch (action) {
                 case MotionEvent.ACTION_DOWN: {
-                    // New gesture so restart tracking injected down pointers.
-                    mInjectedPointersDown = 0;
                     handleReceivedPointerDown(event.getActionIndex(), event);
                 } break;
                 case MotionEvent.ACTION_POINTER_DOWN: {
@@ -970,39 +1313,7 @@
                 } break;
             }
             if (DEBUG) {
-                Slog.i(LOG_TAG, "Received pointer: " + toString());
-            }
-        }
-
-        /**
-         * Processes an injected {@link MotionEvent} event.
-         *
-         * @param event The event to process.
-         */
-        public void onInjectedMotionEvent(MotionEvent event) {
-            final int action = event.getActionMasked();
-            switch (action) {
-                case MotionEvent.ACTION_DOWN: {
-                    handleInjectedPointerDown(event.getActionIndex(), event);
-                    mLastInjectedDownEventTime = event.getDownTime();
-                } break;
-                case MotionEvent.ACTION_POINTER_DOWN: {
-                    handleInjectedPointerDown(event.getActionIndex(), event);
-                } break;
-                case MotionEvent.ACTION_UP: {
-                    handleInjectedPointerUp(event.getActionIndex(), event);
-                } break;
-                case MotionEvent.ACTION_POINTER_UP: {
-                    handleInjectedPointerUp(event.getActionIndex(), event);
-                } break;
-                case MotionEvent.ACTION_HOVER_ENTER:
-                case MotionEvent.ACTION_HOVER_MOVE:
-                case MotionEvent.ACTION_HOVER_EXIT: {
-                    mLastInjectedHoverEventAction = event.getActionMasked();
-                } break;
-            }
-            if (DEBUG) {
-                Slog.i(LOG_TAG, "Injected pointer: " + toString());
+                Slog.i(LOG_TAG_RECEIVED_POINTER_TRACKER, "Received pointer: " + toString());
             }
         }
 
@@ -1014,6 +1325,13 @@
         }
 
         /**
+         * @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() {
@@ -1032,24 +1350,6 @@
         }
 
         /**
-         * Whether an injected pointer is down.
-         *
-         * @param pointerId The unique pointer id.
-         * @return True if the pointer is down.
-         */
-        public boolean isInjectedPointerDown(int pointerId) {
-            final int pointerFlag = (1 << pointerId);
-            return (mInjectedPointersDown & pointerFlag) != 0;
-        }
-
-        /**
-         * @return The number of down pointers injected to the view hierarchy.
-         */
-        public int getInjectedPointerDownCount() {
-            return Integer.bitCount(mInjectedPointersDown);
-        }
-
-        /**
          * Whether an input pointer is active.
          *
          * @param pointerId The unique pointer id.
@@ -1108,27 +1408,27 @@
             return mLastReceivedUpPointerId;
         }
 
+
+        /**
+         * @return The down X of the last received pointer that went up.
+         */
+        public float getLastReceivedUpPointerDownX() {
+            return mLastReceivedUpPointerDownX;
+        }
+
+        /**
+         * @return The down Y of the last received pointer that went up.
+         */
+        public float getLastReceivedUpPointerDownY() {
+            return mLastReceivedUpPointerDownY;
+        }
+
         /**
          * @return Whether the last received pointer that went up was active.
          */
         public boolean wasLastReceivedUpPointerActive() {
             return mLastReceivedUpPointerActive;
         }
-
-        /**
-         * @return The time of the last injected down event.
-         */
-        public long getLastInjectedDownEventTime() {
-            return mLastInjectedDownEventTime;
-        }
-
-        /**
-         * @return The action of the last injected hover event.
-         */
-        public int getLastInjectedHoverAction() {
-            return mLastInjectedHoverEventAction;
-        }
-
         /**
          * Populates the active pointer IDs to the given array.
          * <p>
@@ -1147,18 +1447,10 @@
         }
 
         /**
-         * @return The number of non injected active pointers.
-         */
-        public int getNotInjectedActivePointerCount() {
-            final int pointerState = mActivePointers & ~mInjectedPointersDown;
-            return Integer.bitCount(pointerState);
-        }
-
-        /**
          * @param pointerId The unique pointer id.
          * @return Whether the pointer is active or was the last active than went up.
          */
-        private boolean isActiveOrWasLastActiveUpPointer(int pointerId) {
+        public boolean isActiveOrWasLastActiveUpPointer(int pointerId) {
             return (isActivePointer(pointerId)
                     || (mLastReceivedUpPointerId == pointerId
                             && mLastReceivedUpPointerActive));
@@ -1177,6 +1469,8 @@
             mLastReceivedUpPointerId = 0;
             mLastReceivedUpPointerDownTime = 0;
             mLastReceivedUpPointerActive = false;
+            mLastReceivedUpPointerDownX = 0;
+            mLastReceivedUpPointerDownX = 0;
 
             mReceivedPointersDown |= pointerFlag;
             mReceivedPointerDownX[pointerId] = event.getX(pointerIndex);
@@ -1217,6 +1511,8 @@
             mLastReceivedUpPointerId = pointerId;
             mLastReceivedUpPointerDownTime = getReceivedPointerDownTime(pointerId);
             mLastReceivedUpPointerActive = isActivePointer(pointerId);
+            mLastReceivedUpPointerDownX = mReceivedPointerDownX[pointerId];
+            mLastReceivedUpPointerDownY = mReceivedPointerDownY[pointerId];
 
             mReceivedPointersDown &= ~pointerFlag;
             mActivePointers &= ~pointerFlag;
@@ -1233,33 +1529,6 @@
         }
 
         /**
-         * Handles a injected pointer down event.
-         *
-         * @param pointerIndex The index of the pointer that has changed.
-         * @param event The event to be handled.
-         */
-        private void handleInjectedPointerDown(int pointerIndex, MotionEvent event) {
-            final int pointerId = event.getPointerId(pointerIndex);
-            final int pointerFlag = (1 << pointerId);
-            mInjectedPointersDown |= pointerFlag;
-        }
-
-        /**
-         * Handles a injected pointer up event.
-         *
-         * @param pointerIndex The index of the pointer that has changed.
-         * @param event The event to be handled.
-         */
-        private void handleInjectedPointerUp(int pointerIndex, MotionEvent event) {
-            final int pointerId = event.getPointerId(pointerIndex);
-            final int pointerFlag = (1 << pointerId);
-            mInjectedPointersDown &= ~pointerFlag;
-            if (mInjectedPointersDown == 0) {
-                mLastInjectedDownEventTime = 0;
-            }
-        }
-
-        /**
          * Detects the active pointers in an event.
          *
          * @param event The event to examine.
@@ -1348,117 +1617,4 @@
             return builder.toString();
         }
     }
-
-    /**
-     * Class for delayed sending of long press.
-     */
-    private final class PerformLongPressDelayed implements Runnable {
-        private MotionEvent mEvent;
-        private int mPolicyFlags;
-
-        public void post(MotionEvent prototype, int policyFlags, long delay) {
-            mEvent = MotionEvent.obtain(prototype);
-            mPolicyFlags = policyFlags;
-            mHandler.postDelayed(this, delay);
-        }
-
-        public void remove() {
-            if (isPenidng()) {
-                mHandler.removeCallbacks(this);
-                clear();
-            }
-        }
-
-        private boolean isPenidng() {
-            return (mEvent != null);
-        }
-
-        @Override
-        public void run() {
-            mCurrentState = STATE_DELEGATING;
-            // Make sure the scheduled hover exit is delivered.
-            mSendHoverDelayed.remove();
-            final int pointerId = mPointerTracker.getPrimaryActivePointerId();
-            final int pointerIdBits = (1 << pointerId);
-            ensureHoverExitSent(mEvent, pointerIdBits, mPolicyFlags);
-
-            sendDownForAllActiveNotInjectedPointers(mEvent, mPolicyFlags);
-            mTouchExploreGestureInProgress = false;
-            mLastTouchExploreEvent = null;
-            clear();
-        }
-
-        private void clear() {
-            if (!isPenidng()) {
-                return;
-            }
-            mEvent.recycle();
-            mEvent = null;
-            mPolicyFlags = 0;
-        }
-    }
-
-    /**
-     * Class for delayed sending of hover events.
-     */
-    private final class SendHoverDelayed implements Runnable {
-        private static final String LOG_TAG = "SendHoverEnterOrExitDelayed";
-
-        private MotionEvent mEvent;
-        private int mAction;
-        private int mPointerIdBits;
-        private int mPolicyFlags;
-
-        public void post(MotionEvent prototype, int action, int pointerIdBits, int policyFlags,
-                long delay) {
-            remove();
-            mEvent = MotionEvent.obtain(prototype);
-            mAction = action;
-            mPointerIdBits = pointerIdBits;
-            mPolicyFlags = policyFlags;
-            mHandler.postDelayed(this, delay);
-        }
-
-        public void remove() {
-            mHandler.removeCallbacks(this);
-            clear();
-        }
-
-        private boolean isPenidng() {
-            return (mEvent != null);
-        }
-
-        private void clear() {
-            if (!isPenidng()) {
-                return;
-            }
-            mEvent.recycle();
-            mEvent = null;
-            mAction = 0;
-            mPointerIdBits = -1;
-            mPolicyFlags = 0;
-        }
-
-        public void forceSendAndRemove() {
-            if (isPenidng()) {
-                run();
-                remove();
-            }
-        }
-
-        public void run() {
-            if (DEBUG) {
-                if (mAction == MotionEvent.ACTION_HOVER_ENTER) {
-                    Slog.d(LOG_TAG, "Injecting: " + MotionEvent.ACTION_HOVER_ENTER);
-                } else if (mAction == MotionEvent.ACTION_HOVER_MOVE) {
-                    Slog.d(LOG_TAG, "Injecting: MotionEvent.ACTION_HOVER_MOVE");
-                } else if (mAction == MotionEvent.ACTION_HOVER_EXIT) {
-                    Slog.d(LOG_TAG, "Injecting: MotionEvent.ACTION_HOVER_EXIT");
-                }
-            }
-
-            sendMotionEvent(mEvent, mAction, mPointerIdBits, mPolicyFlags);
-            clear();
-        }
-    }
 }
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index e37adc7..77bec41 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1808,16 +1808,18 @@
 
     final ProcessRecord getProcessRecordLocked(
             String processName, int uid) {
-        // Temporary hack to make Settings run per user
-        if (uid == Process.SYSTEM_UID && !processName.equals("com.android.settings")) {
+        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);
-            return procs != null ? procs.valueAt(0) : null;
+            if (procs == null) return null;
+            final int N = procs.size();
+            for (int i = 0; i < N; i++) {
+                if (UserId.isSameUser(procs.keyAt(i), uid)) return procs.valueAt(i);
+            }
         }
-        // uid = applyUserId(uid);
         ProcessRecord proc = mProcessNames.get(processName, uid);
         return proc;
     }
@@ -6183,7 +6185,9 @@
                 if (cpi == null) {
                     return null;
                 }
-
+                if (isSingleton(cpi.processName, cpi.applicationInfo)) {
+                    userId = 0;
+                }
                 cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
 
                 String msg;
@@ -10923,6 +10927,9 @@
                     return null;
                 }
                 if (userId > 0) {
+                    if (isSingleton(sInfo.processName, sInfo.applicationInfo)) {
+                        userId = 0;
+                    }
                     sInfo.applicationInfo = getAppInfoForUser(sInfo.applicationInfo, userId);
                 }
                 ComponentName name = new ComponentName(
@@ -11740,7 +11747,22 @@
             }
         }
     }
-    
+
+    boolean isSingleton(String componentProcessName, ApplicationInfo aInfo) {
+        boolean result = false;
+        if (UserId.getAppId(aInfo.uid) >= Process.FIRST_APPLICATION_UID) {
+            result = false;
+        } else if (componentProcessName == aInfo.packageName) {
+            result = (aInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0;
+        } else if ("system".equals(componentProcessName)) {
+            result = true;
+        }
+        if (DEBUG_MU) {
+            Slog.v(TAG, "isSingleton(" + componentProcessName + ", " + aInfo + ") = " + result);
+        }
+        return result;
+    }
+
     public int bindService(IApplicationThread caller, IBinder token,
             Intent service, String resolvedType,
             IServiceConnection connection, int flags, int userId) {
@@ -11808,6 +11830,11 @@
             if (res.record == null) {
                 return -1;
             }
+            if (isSingleton(res.record.processName, res.record.appInfo)) {
+                userId = 0;
+                res = retrieveServiceLocked(service, resolvedType, Binder.getCallingPid(),
+                        Binder.getCallingUid(), 0);
+            }
             ServiceRecord s = res.record;
 
             final long origId = Binder.clearCallingIdentity();
@@ -12740,7 +12767,11 @@
                 if (ai != null) {
                     receivers = new ArrayList();
                     ResolveInfo ri = new ResolveInfo();
-                    ri.activityInfo = getActivityInfoForUser(ai, userId);
+                    if (isSingleton(ai.processName, ai.applicationInfo)) {
+                        ri.activityInfo = getActivityInfoForUser(ai, 0);
+                    } else {
+                        ri.activityInfo = getActivityInfoForUser(ai, userId);
+                    }
                     receivers.add(ri);
                 }
             } else {
@@ -14894,16 +14925,14 @@
         if (info == null) return null;
         ApplicationInfo newInfo = new ApplicationInfo(info);
         newInfo.uid = applyUserId(info.uid, userId);
-        if (newInfo.uid >= Process.FIRST_APPLICATION_UID) {
-            newInfo.dataDir = USER_DATA_DIR + userId + "/"
-                    + info.packageName;
-        }
+        newInfo.dataDir = USER_DATA_DIR + userId + "/"
+                + info.packageName;
         return newInfo;
     }
 
     ActivityInfo getActivityInfoForUser(ActivityInfo aInfo, int userId) {
-        if (aInfo == null || aInfo.applicationInfo.uid < Process.FIRST_APPLICATION_UID
-                || userId < 1) {
+        if (aInfo == null
+                || (userId < 1 && aInfo.applicationInfo.uid < UserId.PER_USER_RANGE)) {
             return aInfo;
         }
 
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index a098f18..cce8e7a 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -558,6 +558,11 @@
                             pendingOptions.getCustomEnterResId(),
                             pendingOptions.getCustomExitResId());
                     break;
+                case ActivityOptions.ANIM_SCALE_UP:
+                    service.mWindowManager.overridePendingAppTransitionScaleUp(
+                            pendingOptions.getStartX(), pendingOptions.getStartY(),
+                            pendingOptions.getStartWidth(), pendingOptions.getStartHeight());
+                    break;
                 case ActivityOptions.ANIM_THUMBNAIL:
                     service.mWindowManager.overridePendingAppTransitionThumb(
                             pendingOptions.getThumbnail(),
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 6596e1f..2c53186 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -2345,8 +2345,9 @@
         }
 
         if (err == ActivityManager.START_SUCCESS) {
+            final int userId = aInfo != null ? UserId.getUserId(aInfo.applicationInfo.uid) : 0;
             Slog.i(TAG, "START {" + intent.toShortString(true, true, true, false)
-                    + "} from pid " + (callerApp != null ? callerApp.pid : callingPid));
+                    + " u=" + userId + "} from pid " + (callerApp != null ? callerApp.pid : callingPid));
         }
 
         ActivityRecord sourceRecord = null;
@@ -2943,6 +2944,9 @@
         // Collect information about the target of the Intent.
         ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags,
                 profileFile, profileFd, userId);
+        if (mService.isSingleton(aInfo.processName, aInfo.applicationInfo)) {
+            userId = 0;
+        }
         aInfo = mService.getActivityInfoForUser(aInfo, userId);
 
         synchronized (mService) {
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java
index 1b83e0b..47b8c0a 100644
--- a/services/java/com/android/server/am/BroadcastQueue.java
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -719,8 +719,10 @@
                     info.activityInfo.applicationInfo.packageName,
                     info.activityInfo.name);
             if (r.callingUid != Process.SYSTEM_UID) {
-                info.activityInfo = mService.getActivityInfoForUser(info.activityInfo, UserId
-                        .getUserId(r.callingUid));
+                boolean isSingleton = mService.isSingleton(info.activityInfo.processName,
+                        info.activityInfo.applicationInfo);
+                int targetUserId = isSingleton ? 0 : UserId.getUserId(r.callingUid);
+                info.activityInfo = mService.getActivityInfoForUser(info.activityInfo,targetUserId);
             }
             r.curReceiver = info.activityInfo;
             if (DEBUG_MU && r.callingUid > UserId.PER_USER_RANGE) {
diff --git a/services/java/com/android/server/input/InputManagerService.java b/services/java/com/android/server/input/InputManagerService.java
index ce7671f..a4ed31c 100644
--- a/services/java/com/android/server/input/InputManagerService.java
+++ b/services/java/com/android/server/input/InputManagerService.java
@@ -16,20 +16,28 @@
 
 package com.android.server.input;
 
+import com.android.internal.os.AtomicFile;
+import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.XmlUtils;
 import com.android.server.Watchdog;
 
 import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
 
+import android.Manifest;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.database.ContentObserver;
@@ -55,30 +63,37 @@
 import android.view.InputChannel;
 import android.view.InputDevice;
 import android.view.InputEvent;
-import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.PointerIcon;
 import android.view.Surface;
 import android.view.ViewConfiguration;
 import android.view.WindowManagerPolicy;
-import android.view.KeyCharacterMap.UnavailableException;
 
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
 import java.io.FileReader;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.List;
+import java.util.Map;
+
+import libcore.io.IoUtils;
+import libcore.io.Streams;
+import libcore.util.Objects;
 
 /*
  * Wraps the C++ InputManager and provides its callbacks.
  */
 public class InputManagerService extends IInputManager.Stub implements Watchdog.Monitor {
     static final String TAG = "InputManager";
-    static final boolean DEBUG = false;
+    static final boolean DEBUG = true;
 
     private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
 
@@ -90,10 +105,10 @@
     private final Context mContext;
     private final Callbacks mCallbacks;
     private final InputManagerHandler mHandler;
+    private boolean mSystemReady;
 
-    // Used to simulate a persistent data store for keyboard layouts.
-    // TODO: Replace with the real thing.
-    private final HashMap<String, String> mFakeRegistry = new HashMap<String, String>();
+    // Persistent data store.  Must be locked each time during use.
+    private final PersistentDataStore mDataStore = new PersistentDataStore();
 
     // List of currently registered input devices changed listeners by process id.
     private Object mInputDevicesLock = new Object();
@@ -105,6 +120,12 @@
             mTempInputDevicesChangedListenersToNotify =
                     new ArrayList<InputDevicesChangedListenerRecord>(); // handler thread only
 
+    // State for vibrator tokens.
+    private Object mVibratorLock = new Object();
+    private HashMap<IBinder, VibratorToken> mVibratorTokens =
+            new HashMap<IBinder, VibratorToken>();
+    private int mNextVibratorTokenValue;
+
     // State for the currently installed input filter.
     final Object mInputFilterLock = new Object();
     InputFilter mInputFilter; // guarded by mInputFilterLock
@@ -142,6 +163,10 @@
             InputChannel fromChannel, InputChannel toChannel);
     private static native void nativeSetPointerSpeed(int ptr, int speed);
     private static native void nativeSetShowTouches(int ptr, boolean enabled);
+    private static native void nativeVibrate(int ptr, int deviceId, long[] pattern,
+            int repeat, int token);
+    private static native void nativeCancelVibrate(int ptr, int deviceId, int token);
+    private static native void nativeReloadKeyboardLayouts(int ptr);
     private static native String nativeDump(int ptr);
     private static native void nativeMonitor(int ptr);
 
@@ -191,7 +216,33 @@
         updatePointerSpeedFromSettings();
         updateShowTouchesFromSettings();
     }
-    
+
+    public void systemReady() {
+        if (DEBUG) {
+            Slog.d(TAG, "System ready.");
+        }
+        mSystemReady = true;
+        reloadKeyboardLayouts();
+
+        IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        filter.addDataScheme("package");
+        mContext.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Packages changed, reloading keyboard layouts.");
+                }
+                reloadKeyboardLayouts();
+            }
+        }, filter, null, mHandler);
+    }
+
+    private void reloadKeyboardLayouts() {
+        nativeReloadKeyboardLayouts(mPtr);
+    }
+
     public void setDisplaySize(int displayId, int width, int height,
             int externalWidth, int externalHeight) {
         if (width <= 0 || height <= 0 || externalWidth <= 0 || externalHeight <= 0) {
@@ -507,14 +558,14 @@
 
     @Override // Binder call
     public KeyboardLayout[] getKeyboardLayouts() {
-        ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>();
-
-        final PackageManager pm = mContext.getPackageManager();
-        Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS);
-        for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent,
-                PackageManager.GET_META_DATA)) {
-            loadKeyboardLayouts(pm, resolveInfo.activityInfo, list, null);
-        }
+        final ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>();
+        visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
+            @Override
+            public void visitKeyboardLayout(Resources resources,
+                    String descriptor, String label, int kcmResId) {
+                list.add(new KeyboardLayout(descriptor, label));
+            }
+        });
         return list.toArray(new KeyboardLayout[list.size()]);
     }
 
@@ -524,37 +575,57 @@
             throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
         }
 
-        KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor);
-        if (d == null) {
-            return null;
+        final KeyboardLayout[] result = new KeyboardLayout[1];
+        visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
+            @Override
+            public void visitKeyboardLayout(Resources resources,
+                    String descriptor, String label, int kcmResId) {
+                result[0] = new KeyboardLayout(descriptor, label);
+            }
+        });
+        if (result[0] == null) {
+            Log.w(TAG, "Could not get keyboard layout with descriptor '"
+                    + keyboardLayoutDescriptor + "'.");
         }
+        return result[0];
+    }
 
+    private void visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor) {
         final PackageManager pm = mContext.getPackageManager();
-        try {
-            ActivityInfo receiver = pm.getReceiverInfo(
-                    new ComponentName(d.packageName, d.receiverName),
-                    PackageManager.GET_META_DATA);
-            return loadKeyboardLayouts(pm, receiver, null, d.keyboardLayoutName);
-        } catch (NameNotFoundException ex) {
-            Log.w(TAG, "Could not load keyboard layout '" + d.keyboardLayoutName
-                    + "' from receiver " + d.packageName + "/" + d.receiverName, ex);
-            return null;
+        Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS);
+        for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent,
+                PackageManager.GET_META_DATA)) {
+            visitKeyboardLayoutsInPackage(pm, resolveInfo.activityInfo, null, visitor);
         }
     }
 
-    private KeyboardLayout loadKeyboardLayouts(
-            PackageManager pm, ActivityInfo receiver,
-            List<KeyboardLayout> list, String keyboardName) {
+    private void visitKeyboardLayout(String keyboardLayoutDescriptor,
+            KeyboardLayoutVisitor visitor) {
+        KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor);
+        if (d != null) {
+            final PackageManager pm = mContext.getPackageManager();
+            try {
+                ActivityInfo receiver = pm.getReceiverInfo(
+                        new ComponentName(d.packageName, d.receiverName),
+                        PackageManager.GET_META_DATA);
+                visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, visitor);
+            } catch (NameNotFoundException ex) {
+            }
+        }
+    }
+
+    private void visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver,
+            String keyboardName, KeyboardLayoutVisitor visitor) {
         Bundle metaData = receiver.metaData;
         if (metaData == null) {
-            return null;
+            return;
         }
 
         int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS);
         if (configResId == 0) {
             Log.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS
                     + "' on receiver " + receiver.packageName + "/" + receiver.name);
-            return null;
+            return;
         }
 
         try {
@@ -587,12 +658,9 @@
                             } else {
                                 String descriptor = KeyboardLayoutDescriptor.format(
                                         receiver.packageName, receiver.name, name);
-                                KeyboardLayout c = new KeyboardLayout(descriptor, label);
-                                if (keyboardName != null && name.equals(keyboardName)) {
-                                    return c;
-                                }
-                                if (list != null) {
-                                    list.add(c);
+                                if (keyboardName == null || name.equals(keyboardName)) {
+                                    visitor.visitKeyboardLayout(resources, descriptor,
+                                            label, kcmResId);
                                 }
                             }
                         } finally {
@@ -608,16 +676,9 @@
                 parser.close();
             }
         } catch (Exception ex) {
-            Log.w(TAG, "Could not load keyboard layout resource from receiver "
+            Log.w(TAG, "Could not parse keyboard layout resource from receiver "
                     + receiver.packageName + "/" + receiver.name, ex);
-            return null;
         }
-        if (keyboardName != null) {
-            Log.w(TAG, "Could not load keyboard layout '" + keyboardName
-                    + "' from receiver " + receiver.packageName + "/" + receiver.name
-                    + " because it was not declared in the keyboard layout resource.");
-        }
-        return null;
     }
 
     @Override // Binder call
@@ -626,7 +687,9 @@
             throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
         }
 
-        return mFakeRegistry.get(inputDeviceDescriptor);
+        synchronized (mDataStore) {
+            return mDataStore.getKeyboardLayout(inputDeviceDescriptor);
+        }
     }
 
     @Override // Binder call
@@ -641,45 +704,23 @@
             throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
         }
 
-        mFakeRegistry.put(inputDeviceDescriptor, keyboardLayoutDescriptor);
-    }
-
-    /**
-     * Loads the key character map associated with the keyboard layout.
-     *
-     * @param pm The package manager.
-     * @return The key character map, or null if it could not be loaded for any reason.
-     *
-    public KeyCharacterMap loadKeyCharacterMap(PackageManager pm) {
-        if (pm == null) {
-            throw new IllegalArgumentException("pm must not be null");
-        }
-
-        if (mKeyCharacterMap == null) {
-            KeyboardLayoutDescriptor d = InputManager.parseKeyboardLayoutDescriptor(mDescriptor);
-            if (d == null) {
-                Log.e(InputManager.TAG, "Could not load key character map '" + mDescriptor
-                        + "' because the descriptor could not be parsed.");
-                return null;
-            }
-
-            CharSequence cs = pm.getText(d.packageName, mKeyCharacterMapResId, null);
-            if (cs == null) {
-                Log.e(InputManager.TAG, "Could not load key character map '" + mDescriptor
-                        + "' because its associated resource could not be loaded.");
-                return null;
-            }
-
+        final boolean changed;
+        synchronized (mDataStore) {
             try {
-                mKeyCharacterMap = KeyCharacterMap.load(cs);
-            } catch (UnavailableException ex) {
-                Log.e(InputManager.TAG, "Could not load key character map '" + mDescriptor
-                        + "' due to an error while parsing.", ex);
-                return null;
+                changed = mDataStore.setKeyboardLayout(
+                        inputDeviceDescriptor, keyboardLayoutDescriptor);
+            } finally {
+                mDataStore.saveIfNeeded();
             }
         }
-        return mKeyCharacterMap;
-    }*/
+
+        if (changed) {
+            if (DEBUG) {
+                Slog.d(TAG, "Keyboard layout changed, reloading keyboard layouts.");
+            }
+            reloadKeyboardLayouts();
+        }
+    }
 
     public void setInputWindows(InputWindowHandle[] windowHandles) {
         nativeSetInputWindows(mPtr, windowHandles);
@@ -792,9 +833,68 @@
         return result;
     }
 
+    // Binder call
+    @Override
+    public void vibrate(int deviceId, long[] pattern, int repeat, IBinder token) {
+        if (repeat >= pattern.length) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+
+        VibratorToken v;
+        synchronized (mVibratorLock) {
+            v = mVibratorTokens.get(token);
+            if (v == null) {
+                v = new VibratorToken(deviceId, token, mNextVibratorTokenValue++);
+                try {
+                    token.linkToDeath(v, 0);
+                } catch (RemoteException ex) {
+                    // give up
+                    throw new RuntimeException(ex);
+                }
+                mVibratorTokens.put(token, v);
+            }
+        }
+
+        synchronized (v) {
+            v.mVibrating = true;
+            nativeVibrate(mPtr, deviceId, pattern, repeat, v.mTokenValue);
+        }
+    }
+
+    // Binder call
+    @Override
+    public void cancelVibrate(int deviceId, IBinder token) {
+        VibratorToken v;
+        synchronized (mVibratorLock) {
+            v = mVibratorTokens.get(token);
+            if (v == null || v.mDeviceId != deviceId) {
+                return; // nothing to cancel
+            }
+        }
+
+        cancelVibrateIfNeeded(v);
+    }
+
+    void onVibratorTokenDied(VibratorToken v) {
+        synchronized (mVibratorLock) {
+            mVibratorTokens.remove(v.mToken);
+        }
+
+        cancelVibrateIfNeeded(v);
+    }
+
+    private void cancelVibrateIfNeeded(VibratorToken v) {
+        synchronized (v) {
+            if (v.mVibrating) {
+                nativeCancelVibrate(mPtr, v.mDeviceId, v.mTokenValue);
+                v.mVibrating = false;
+            }
+        }
+    }
+
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
+        if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
                 != PackageManager.PERMISSION_GRANTED) {
             pw.println("Permission Denial: can't dump InputManager from from pid="
                     + Binder.getCallingPid()
@@ -988,6 +1088,40 @@
         return PointerIcon.getDefaultIcon(mContext);
     }
 
+    // Native callback.
+    private String[] getKeyboardLayoutOverlay(String inputDeviceDescriptor) {
+        if (!mSystemReady) {
+            return null;
+        }
+
+        String keyboardLayoutDescriptor = getKeyboardLayoutForInputDevice(inputDeviceDescriptor);
+        if (keyboardLayoutDescriptor == null) {
+            return null;
+        }
+
+        final String[] result = new String[2];
+        visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
+            @Override
+            public void visitKeyboardLayout(Resources resources,
+                    String descriptor, String label, int kcmResId) {
+                try {
+                    result[0] = descriptor;
+                    result[1] = Streams.readFully(new InputStreamReader(
+                            resources.openRawResource(kcmResId)));
+                } catch (IOException ex) {
+                } catch (NotFoundException ex) {
+                }
+            }
+        });
+        if (result[0] == null) {
+            Log.w(TAG, "Could not get keyboard layout with descriptor '"
+                    + keyboardLayoutDescriptor + "'.");
+            return null;
+        }
+        return result;
+    }
+
+
     /**
      * Callback interface implemented by the Window Manager.
      */
@@ -1081,6 +1215,11 @@
         }
     }
 
+    private interface KeyboardLayoutVisitor {
+        void visitKeyboardLayout(Resources resources,
+                String descriptor, String label, int kcmResId);
+    }
+
     private final class InputDevicesChangedListenerRecord implements DeathRecipient {
         private final int mPid;
         private final IInputDevicesChangedListener mListener;
@@ -1108,4 +1247,208 @@
             }
         }
     }
+
+    private final class VibratorToken implements DeathRecipient {
+        public final int mDeviceId;
+        public final IBinder mToken;
+        public final int mTokenValue;
+
+        public boolean mVibrating;
+
+        public VibratorToken(int deviceId, IBinder token, int tokenValue) {
+            mDeviceId = deviceId;
+            mToken = token;
+            mTokenValue = tokenValue;
+        }
+
+        @Override
+        public void binderDied() {
+            if (DEBUG) {
+                Slog.d(TAG, "Vibrator token died.");
+            }
+            onVibratorTokenDied(this);
+        }
+    }
+
+    /**
+     * Manages persistent state recorded by the input manager service as an XML file.
+     * Caller must acquire lock on the data store before accessing it.
+     *
+     * File format:
+     * <code>
+     * &lt;input-mananger-state>
+     *   &lt;input-devices>
+     *     &lt;input-device descriptor="xxxxx" keyboard-layout="yyyyy" />
+     *   &gt;input-devices>
+     * &gt;/input-manager-state>
+     * </code>
+     */
+    private static final class PersistentDataStore {
+        // Input device state by descriptor.
+        private final HashMap<String, InputDeviceState> mInputDevices =
+                new HashMap<String, InputDeviceState>();
+        private final AtomicFile mAtomicFile;
+
+        // True if the data has been loaded.
+        private boolean mLoaded;
+
+        // True if there are changes to be saved.
+        private boolean mDirty;
+
+        public PersistentDataStore() {
+            mAtomicFile = new AtomicFile(new File("/data/system/input-manager-state.xml"));
+        }
+
+        public void saveIfNeeded() {
+            if (mDirty) {
+                save();
+                mDirty = false;
+            }
+        }
+
+        public String getKeyboardLayout(String inputDeviceDescriptor) {
+            InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, false);
+            return state != null ? state.keyboardLayoutDescriptor : null;
+        }
+
+        public boolean setKeyboardLayout(String inputDeviceDescriptor,
+                String keyboardLayoutDescriptor) {
+            InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, true);
+            if (!Objects.equal(state.keyboardLayoutDescriptor, keyboardLayoutDescriptor)) {
+                state.keyboardLayoutDescriptor = keyboardLayoutDescriptor;
+                setDirty();
+                return true;
+            }
+            return false;
+        }
+
+        private InputDeviceState getInputDeviceState(String inputDeviceDescriptor,
+                boolean createIfAbsent) {
+            loadIfNeeded();
+            InputDeviceState state = mInputDevices.get(inputDeviceDescriptor);
+            if (state == null && createIfAbsent) {
+                state = new InputDeviceState();
+                mInputDevices.put(inputDeviceDescriptor, state);
+                setDirty();
+            }
+            return state;
+        }
+
+        private void loadIfNeeded() {
+            if (!mLoaded) {
+                load();
+                mLoaded = true;
+            }
+        }
+
+        private void setDirty() {
+            mDirty = true;
+        }
+
+        private void clearState() {
+            mInputDevices.clear();
+        }
+
+        private void load() {
+            clearState();
+
+            final InputStream is;
+            try {
+                is = mAtomicFile.openRead();
+            } catch (FileNotFoundException ex) {
+                return;
+            }
+
+            XmlPullParser parser;
+            try {
+                parser = Xml.newPullParser();
+                parser.setInput(new BufferedInputStream(is), null);
+                loadFromXml(parser);
+            } catch (IOException ex) {
+                Slog.w(TAG, "Failed to load input manager persistent store data.", ex);
+                clearState();
+            } catch (XmlPullParserException ex) {
+                Slog.w(TAG, "Failed to load input manager persistent store data.", ex);
+                clearState();
+            } finally {
+                IoUtils.closeQuietly(is);
+            }
+        }
+
+        private void save() {
+            final FileOutputStream os;
+            try {
+                os = mAtomicFile.startWrite();
+                boolean success = false;
+                try {
+                    XmlSerializer serializer = new FastXmlSerializer();
+                    serializer.setOutput(new BufferedOutputStream(os), "utf-8");
+                    saveToXml(serializer);
+                    serializer.flush();
+                    success = true;
+                } finally {
+                    if (success) {
+                        mAtomicFile.finishWrite(os);
+                    } else {
+                        mAtomicFile.failWrite(os);
+                    }
+                }
+            } catch (IOException ex) {
+                Slog.w(TAG, "Failed to save input manager persistent store data.", ex);
+            }
+        }
+
+        private void loadFromXml(XmlPullParser parser)
+                throws IOException, XmlPullParserException {
+            XmlUtils.beginDocument(parser, "input-manager-state");
+            final int outerDepth = parser.getDepth();
+            while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+                if (parser.getName().equals("input-devices")) {
+                    loadInputDevicesFromXml(parser);
+                }
+            }
+        }
+
+        private void loadInputDevicesFromXml(XmlPullParser parser)
+                throws IOException, XmlPullParserException {
+            final int outerDepth = parser.getDepth();
+            while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+                if (parser.getName().equals("input-device")) {
+                    String descriptor = parser.getAttributeValue(null, "descriptor");
+                    if (descriptor == null) {
+                        throw new XmlPullParserException(
+                                "Missing descriptor attribute on input-device");
+                    }
+                    InputDeviceState state = new InputDeviceState();
+                    state.keyboardLayoutDescriptor =
+                            parser.getAttributeValue(null, "keyboard-layout");
+                    mInputDevices.put(descriptor, state);
+                }
+            }
+        }
+
+        private void saveToXml(XmlSerializer serializer) throws IOException {
+            serializer.startDocument(null, true);
+            serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+            serializer.startTag(null, "input-manager-state");
+            serializer.startTag(null, "input-devices");
+            for (Map.Entry<String, InputDeviceState> entry : mInputDevices.entrySet()) {
+                final String descriptor = entry.getKey();
+                final InputDeviceState state = entry.getValue();
+                serializer.startTag(null, "input-device");
+                serializer.attribute(null, "descriptor", descriptor);
+                if (state.keyboardLayoutDescriptor != null) {
+                    serializer.attribute(null, "keyboard-layout", state.keyboardLayoutDescriptor);
+                }
+                serializer.endTag(null, "input-device");
+            }
+            serializer.endTag(null, "input-devices");
+            serializer.endTag(null, "input-manager-state");
+            serializer.endDocument();
+        }
+    }
+
+    private static final class InputDeviceState {
+        public String keyboardLayoutDescriptor;
+    }
 }
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index fa62e497..1e17067 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -50,6 +50,7 @@
 import static android.net.TrafficStats.MB_IN_BYTES;
 import static android.telephony.TelephonyManager.SIM_STATE_READY;
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
+import static com.android.internal.util.ArrayUtils.appendInt;
 import static com.android.internal.util.Preconditions.checkNotNull;
 import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
 import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.readBooleanAttribute;
@@ -1216,6 +1217,23 @@
     }
 
     @Override
+    public int[] getAppsWithPolicy(int policy) {
+        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+
+        int[] appIds = new int[0];
+        synchronized (mRulesLock) {
+            for (int i = 0; i < mAppPolicy.size(); i++) {
+                final int appId = mAppPolicy.keyAt(i);
+                final int appPolicy = mAppPolicy.valueAt(i);
+                if (appPolicy == policy) {
+                    appIds = appendInt(appIds, appId);
+                }
+            }
+        }
+        return appIds;
+    }
+
+    @Override
     public void registerListener(INetworkPolicyListener listener) {
         // TODO: create permission for observing network policy
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
@@ -1373,6 +1391,22 @@
     }
 
     @Override
+    public boolean isNetworkMetered(NetworkState state) {
+        final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
+
+        final NetworkPolicy policy;
+        synchronized (mRulesLock) {
+            policy = findPolicyForNetworkLocked(ident);
+        }
+
+        if (policy != null) {
+            return policy.metered;
+        } else {
+            return false;
+        }
+    }
+
+    @Override
     protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
         mContext.enforceCallingOrSelfPermission(DUMP, TAG);
 
@@ -1796,11 +1830,6 @@
         mHandler.getLooper().getQueue().addIdleHandler(handler);
     }
 
-    public static boolean isAirplaneModeOn(Context context) {
-        return Settings.System.getInt(
-                context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) != 0;
-    }
-
     private static void collectKeys(SparseIntArray source, SparseBooleanArray target) {
         final int size = source.size();
         for (int i = 0; i < size; i++) {
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 4382a03..2a67e02 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -26,6 +26,7 @@
 import static android.content.Intent.EXTRA_UID;
 import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
+import static android.net.ConnectivityManager.isNetworkTypeMobile;
 import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED;
 import static android.net.NetworkStats.IFACE_ALL;
 import static android.net.NetworkStats.SET_ALL;
@@ -33,7 +34,7 @@
 import static android.net.NetworkStats.SET_FOREGROUND;
 import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkStats.UID_ALL;
-import static android.net.NetworkTemplate.buildTemplateMobileAll;
+import static android.net.NetworkTemplate.buildTemplateMobileWildcard;
 import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
 import static android.net.TrafficStats.MB_IN_BYTES;
 import static android.provider.Settings.Secure.NETSTATS_DEV_BUCKET_DURATION;
@@ -54,6 +55,8 @@
 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
 import static android.text.format.DateUtils.SECOND_IN_MILLIS;
+import static com.android.internal.util.ArrayUtils.appendElement;
+import static com.android.internal.util.ArrayUtils.contains;
 import static com.android.internal.util.Preconditions.checkNotNull;
 import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
 import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats;
@@ -194,6 +197,8 @@
     private HashMap<String, NetworkIdentitySet> mActiveIfaces = Maps.newHashMap();
     /** Current default active iface. */
     private String mActiveIface;
+    /** Set of any ifaces associated with mobile networks since boot. */
+    private String[] mMobileIfaces = new String[0];
 
     private final DropBoxNonMonotonicObserver mNonMonotonicObserver =
             new DropBoxNonMonotonicObserver();
@@ -517,6 +522,11 @@
     }
 
     @Override
+    public String[] getMobileIfaces() {
+        return mMobileIfaces;
+    }
+
+    @Override
     public void incrementOperationCount(int uid, int tag, int operationCount) {
         if (Binder.getCallingUid() != uid) {
             mContext.enforceCallingOrSelfPermission(MODIFY_NETWORK_ACCOUNTING, TAG);
@@ -735,6 +745,13 @@
                 }
 
                 ident.add(NetworkIdentity.buildNetworkIdentity(mContext, state));
+
+                // remember any ifaces associated with mobile networks
+                if (isNetworkTypeMobile(state.networkInfo.getType())) {
+                    if (!contains(mMobileIfaces, iface)) {
+                        mMobileIfaces = appendElement(String.class, mMobileIfaces, iface);
+                    }
+                }
             }
         }
     }
@@ -861,7 +878,7 @@
         NetworkStats.Entry uidTotal;
 
         // collect mobile sample
-        template = buildTemplateMobileAll(getActiveSubscriberId(mContext));
+        template = buildTemplateMobileWildcard();
         devTotal = mDevRecorder.getTotalSinceBootLocked(template);
         xtTotal = new NetworkStats.Entry();
         uidTotal = mUidRecorder.getTotalSinceBootLocked(template);
@@ -1022,12 +1039,6 @@
         }
     };
 
-    private static String getActiveSubscriberId(Context context) {
-        final TelephonyManager telephony = (TelephonyManager) context.getSystemService(
-                Context.TELEPHONY_SERVICE);
-        return telephony.getSubscriberId();
-    }
-
     private boolean isBandwidthControlEnabled() {
         try {
             return mNetworkManager.isBandwidthControlEnabled();
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 1d02b7a3..b97d7fd 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -16,12 +16,14 @@
 
 package com.android.server.pm;
 
+import static android.Manifest.permission.GRANT_REVOKE_PERMISSIONS;
+import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 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.Manifest.permission.GRANT_REVOKE_PERMISSIONS;
+import static com.android.internal.util.ArrayUtils.appendInt;
+import static com.android.internal.util.ArrayUtils.removeInt;
 import static libcore.io.OsConstants.S_ISLNK;
 
 import com.android.internal.app.IMediaContainerService;
@@ -139,6 +141,7 @@
 import java.util.zip.ZipOutputStream;
 
 import libcore.io.ErrnoException;
+import libcore.io.IoUtils;
 import libcore.io.Libcore;
 
 /**
@@ -1451,22 +1454,6 @@
         }
     }
 
-    static int[] appendInt(int[] cur, int val) {
-        if (cur == null) {
-            return new int[] { val };
-        }
-        final int N = cur.length;
-        for (int i=0; i<N; i++) {
-            if (cur[i] == val) {
-                return cur;
-            }
-        }
-        int[] ret = new int[N+1];
-        System.arraycopy(cur, 0, ret, 0, N);
-        ret[N] = val;
-        return ret;
-    }
-
     static int[] appendInts(int[] cur, int[] add) {
         if (add == null) return cur;
         if (cur == null) return add;
@@ -1477,26 +1464,6 @@
         return cur;
     }
 
-    static int[] removeInt(int[] cur, int val) {
-        if (cur == null) {
-            return null;
-        }
-        final int N = cur.length;
-        for (int i=0; i<N; i++) {
-            if (cur[i] == val) {
-                int[] ret = new int[N-1];
-                if (i > 0) {
-                    System.arraycopy(cur, 0, ret, 0, i);
-                }
-                if (i < (N-1)) {
-                    System.arraycopy(cur, i + 1, ret, i, N - i - 1);
-                }
-                return ret;
-            }
-        }
-        return cur;
-    }
-
     static int[] removeInts(int[] cur, int[] rem) {
         if (rem == null) return cur;
         if (cur == null) return cur;
@@ -6614,6 +6581,7 @@
             oldPackage = mPackages.get(pkgName);
             if (compareSignatures(oldPackage.mSignatures, pkg.mSignatures)
                     != PackageManager.SIGNATURE_MATCH) {
+                Slog.w(TAG, "New package has a different signature: " + pkgName);
                 res.returnCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
                 return;
             }
@@ -6979,9 +6947,8 @@
             } catch (IOException e) {
                 Slog.e(TAG, "Couldn't create a new zip file for the public parts of a" +
                            " forward-locked app.");
+                destResourceFile.delete();
                 return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
-            } finally {
-                //TODO clean up the extracted public files
             }
             retCode = mInstaller.setForwardLockPerm(getApkName(newPackage.mPath),
                     newPackage.applicationInfo.uid);
@@ -7023,38 +6990,34 @@
                                     File publicZipFile) throws IOException {
         final FileOutputStream fstr = new FileOutputStream(publicZipFile);
         final ZipOutputStream publicZipOutStream = new ZipOutputStream(fstr);
-        final ZipFile privateZip = new ZipFile(newPackage.mPath);
+        try {
+            final ZipFile privateZip = new ZipFile(newPackage.mPath);
+            try {
+                // Copy manifest, resources.arsc and res directory to public zip
 
-        // Copy manifest, resources.arsc and res directory to public zip
-
-        final Enumeration<? extends ZipEntry> privateZipEntries = privateZip.entries();
-        while (privateZipEntries.hasMoreElements()) {
-            final ZipEntry zipEntry = privateZipEntries.nextElement();
-            final String zipEntryName = zipEntry.getName();
-            if ("AndroidManifest.xml".equals(zipEntryName)
-                || "resources.arsc".equals(zipEntryName)
-                || zipEntryName.startsWith("res/")) {
-                try {
-                    copyZipEntry(zipEntry, privateZip, publicZipOutStream);
-                } catch (IOException e) {
-                    try {
-                        publicZipOutStream.close();
-                        throw e;
-                    } finally {
-                        publicZipFile.delete();
+                final Enumeration<? extends ZipEntry> privateZipEntries = privateZip.entries();
+                while (privateZipEntries.hasMoreElements()) {
+                    final ZipEntry zipEntry = privateZipEntries.nextElement();
+                    final String zipEntryName = zipEntry.getName();
+                    if ("AndroidManifest.xml".equals(zipEntryName)
+                            || "resources.arsc".equals(zipEntryName)
+                            || zipEntryName.startsWith("res/")) {
+                        copyZipEntry(zipEntry, privateZip, publicZipOutStream);
                     }
                 }
+            } finally {
+                try { privateZip.close(); } catch (IOException e) { }
             }
-        }
 
-        publicZipOutStream.finish();
-        publicZipOutStream.flush();
-        FileUtils.sync(fstr);
-        publicZipOutStream.close();
-        FileUtils.setPermissions(
-                publicZipFile.getAbsolutePath(),
-                FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP|FileUtils.S_IROTH,
-                -1, -1);
+            publicZipOutStream.finish();
+            publicZipOutStream.flush();
+            FileUtils.sync(fstr);
+            publicZipOutStream.close();
+            FileUtils.setPermissions(publicZipFile.getAbsolutePath(), FileUtils.S_IRUSR
+                    | FileUtils.S_IWUSR | FileUtils.S_IRGRP | FileUtils.S_IROTH, -1, -1);
+        } finally {
+            IoUtils.closeQuietly(publicZipOutStream);
+        }
     }
 
     private static void copyZipEntry(ZipEntry zipEntry,
@@ -7073,11 +7036,15 @@
         }
         outZipStream.putNextEntry(newEntry);
 
-        InputStream data = inZipFile.getInputStream(zipEntry);
-        while ((num = data.read(buffer)) > 0) {
-            outZipStream.write(buffer, 0, num);
+        final InputStream data = inZipFile.getInputStream(zipEntry);
+        try {
+            while ((num = data.read(buffer)) > 0) {
+                outZipStream.write(buffer, 0, num);
+            }
+            outZipStream.flush();
+        } finally {
+            IoUtils.closeQuietly(data);
         }
-        outZipStream.flush();
     }
 
     private void deleteTempPackageFiles() {
diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java
index 3dcfd3c..13013a8 100644
--- a/services/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -18,6 +18,8 @@
 
 import java.io.PrintWriter;
 
+import static com.android.server.wm.WindowStateAnimator.SurfaceTrace;
+
 import android.content.Context;
 import android.graphics.Matrix;
 import android.graphics.PixelFormat;
@@ -119,6 +121,7 @@
     private boolean mMoreStartEnter;
     private boolean mMoreStartExit;
     private boolean mMoreStartFrame;
+    long mHalfwayPoint;
 
     public void printTo(String prefix, PrintWriter pw) {
         pw.print(prefix); pw.print("mSurface="); pw.print(mSurface);
@@ -205,17 +208,23 @@
                     ">>> OPEN TRANSACTION ScreenRotationAnimation");
             Surface.openTransaction();
         }
-        
+
         try {
             try {
-                mSurface = new Surface(session, 0, "FreezeSurface",
-                        -1, mWidth, mHeight, PixelFormat.OPAQUE, Surface.FX_SURFACE_SCREENSHOT | Surface.HIDDEN);
+                if (WindowManagerService.DEBUG_SURFACE_TRACE) {
+                    mSurface = new SurfaceTrace(session, 0, "FreezeSurface", -1, mWidth, mHeight,
+                        PixelFormat.OPAQUE, Surface.FX_SURFACE_SCREENSHOT | Surface.HIDDEN);
+                } else {
+                    mSurface = new Surface(session, 0, "FreezeSurface", -1, mWidth, mHeight,
+                        PixelFormat.OPAQUE, Surface.FX_SURFACE_SCREENSHOT | Surface.HIDDEN);
+                }
                 if (!mSurface.isValid()) {
                     // Screenshot failed, punt.
                     mSurface = null;
                     return;
                 }
                 mSurface.setLayer(FREEZE_LAYER + 1);
+                mSurface.setAlpha(0);
                 mSurface.show();
             } catch (Surface.OutOfResourcesException e) {
                 Slog.w(TAG, "Unable to allocate freeze surface", e);
@@ -308,10 +317,10 @@
         if (TWO_PHASE_ANIMATION) {
             return startAnimation(session, maxAnimationDuration, animationScale,
                     finalWidth, finalHeight, false);
-        } else {
-            // Don't start animation yet.
-            return false;
         }
+
+        // Don't start animation yet.
+        return false;
     }
 
     /**
@@ -590,29 +599,37 @@
             mEnteringBlackFrame.kill();
             mEnteringBlackFrame = null;
         }
-        if (mStartExitAnimation != null) {
-            mStartExitAnimation.cancel();
-            mStartExitAnimation = null;
+        if (TWO_PHASE_ANIMATION) {
+            if (mStartExitAnimation != null) {
+                mStartExitAnimation.cancel();
+                mStartExitAnimation = null;
+            }
+            if (mStartEnterAnimation != null) {
+                mStartEnterAnimation.cancel();
+                mStartEnterAnimation = null;
+            }
+            if (mFinishExitAnimation != null) {
+                mFinishExitAnimation.cancel();
+                mFinishExitAnimation = null;
+            }
+            if (mFinishEnterAnimation != null) {
+                mFinishEnterAnimation.cancel();
+                mFinishEnterAnimation = null;
+            }
         }
-        if (mStartEnterAnimation != null) {
-            mStartEnterAnimation.cancel();
-            mStartEnterAnimation = null;
-        }
-        if (mStartFrameAnimation != null) {
-            mStartFrameAnimation.cancel();
-            mStartFrameAnimation = null;
-        }
-        if (mFinishExitAnimation != null) {
-            mFinishExitAnimation.cancel();
-            mFinishExitAnimation = null;
-        }
-        if (mFinishEnterAnimation != null) {
-            mFinishEnterAnimation.cancel();
-            mFinishEnterAnimation = null;
-        }
-        if (mFinishFrameAnimation != null) {
-            mFinishFrameAnimation.cancel();
-            mFinishFrameAnimation = null;
+        if (USE_CUSTOM_BLACK_FRAME) {
+            if (mStartFrameAnimation != null) {
+                mStartFrameAnimation.cancel();
+                mStartFrameAnimation = null;
+            }
+            if (mRotateFrameAnimation != null) {
+                mRotateFrameAnimation.cancel();
+                mRotateFrameAnimation = null;
+            }
+            if (mFinishFrameAnimation != null) {
+                mFinishFrameAnimation.cancel();
+                mFinishFrameAnimation = null;
+            }
         }
         if (mRotateExitAnimation != null) {
             mRotateExitAnimation.cancel();
@@ -622,72 +639,74 @@
             mRotateEnterAnimation.cancel();
             mRotateEnterAnimation = null;
         }
-        if (mRotateFrameAnimation != null) {
-            mRotateFrameAnimation.cancel();
-            mRotateFrameAnimation = null;
-        }
     }
 
     public boolean isAnimating() {
-        if (TWO_PHASE_ANIMATION) {
-            return hasAnimations() || mFinishAnimReady;
-        } else {
-            return hasAnimations();
-        }
+        return hasAnimations() || (TWO_PHASE_ANIMATION && mFinishAnimReady);
     }
 
     private boolean hasAnimations() {
-        return mStartEnterAnimation != null || mStartExitAnimation != null
-                || mStartFrameAnimation != null
-                || mFinishEnterAnimation != null || mFinishExitAnimation != null
-                || mFinishFrameAnimation != null
-                || mRotateEnterAnimation != null || mRotateExitAnimation != null
-                || mRotateFrameAnimation != null;
+        return (TWO_PHASE_ANIMATION &&
+                    (mStartEnterAnimation != null || mStartExitAnimation != null
+                    || mFinishEnterAnimation != null || mFinishExitAnimation != null))
+                || (USE_CUSTOM_BLACK_FRAME &&
+                        (mStartFrameAnimation != null || mRotateFrameAnimation != null
+                        || mFinishFrameAnimation != null))
+                || mRotateEnterAnimation != null || mRotateExitAnimation != null;
     }
 
     private boolean stepAnimation(long now) {
+        if (now > mHalfwayPoint) {
+            mHalfwayPoint = Long.MAX_VALUE;
+        }
         if (mFinishAnimReady && mFinishAnimStartTime < 0) {
             if (DEBUG_STATE) Slog.v(TAG, "Step: finish anim now ready");
             mFinishAnimStartTime = now;
         }
 
-        mMoreStartExit = false;
-        if (mStartExitAnimation != null) {
-            mMoreStartExit = mStartExitAnimation.getTransformation(now, mStartExitTransformation);
-            if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start exit: " + mStartExitTransformation);
-        }
+        if (TWO_PHASE_ANIMATION) {
+            mMoreStartExit = false;
+            if (mStartExitAnimation != null) {
+                mMoreStartExit = mStartExitAnimation.getTransformation(now, mStartExitTransformation);
+                if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start exit: " + mStartExitTransformation);
+            }
 
-        mMoreStartEnter = false;
-        if (mStartEnterAnimation != null) {
-            mMoreStartEnter = mStartEnterAnimation.getTransformation(now, mStartEnterTransformation);
-            if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start enter: " + mStartEnterTransformation);
+            mMoreStartEnter = false;
+            if (mStartEnterAnimation != null) {
+                mMoreStartEnter = mStartEnterAnimation.getTransformation(now, mStartEnterTransformation);
+                if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start enter: " + mStartEnterTransformation);
+            }
         }
-
-        mMoreStartFrame = false;
-        if (mStartFrameAnimation != null) {
-            mMoreStartFrame = mStartFrameAnimation.getTransformation(now, mStartFrameTransformation);
-            if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start frame: " + mStartFrameTransformation);
+        if (USE_CUSTOM_BLACK_FRAME) {
+            mMoreStartFrame = false;
+            if (mStartFrameAnimation != null) {
+                mMoreStartFrame = mStartFrameAnimation.getTransformation(now, mStartFrameTransformation);
+                if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start frame: " + mStartFrameTransformation);
+            }
         }
 
         long finishNow = mFinishAnimReady ? (now - mFinishAnimStartTime) : 0;
         if (DEBUG_STATE) Slog.v(TAG, "Step: finishNow=" + finishNow);
 
-        mMoreFinishExit = false;
-        if (mFinishExitAnimation != null) {
-            mMoreFinishExit = mFinishExitAnimation.getTransformation(finishNow, mFinishExitTransformation);
-            if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish exit: " + mFinishExitTransformation);
-        }
+        if (TWO_PHASE_ANIMATION) {
+            mMoreFinishExit = false;
+            if (mFinishExitAnimation != null) {
+                mMoreFinishExit = mFinishExitAnimation.getTransformation(finishNow, mFinishExitTransformation);
+                if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish exit: " + mFinishExitTransformation);
+            }
 
-        mMoreFinishEnter = false;
-        if (mFinishEnterAnimation != null) {
-            mMoreFinishEnter = mFinishEnterAnimation.getTransformation(finishNow, mFinishEnterTransformation);
-            if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish enter: " + mFinishEnterTransformation);
+            mMoreFinishEnter = false;
+            if (mFinishEnterAnimation != null) {
+                mMoreFinishEnter = mFinishEnterAnimation.getTransformation(finishNow, mFinishEnterTransformation);
+                if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish enter: " + mFinishEnterTransformation);
+            }
         }
-
-        mMoreFinishFrame = false;
-        if (mFinishFrameAnimation != null) {
-            mMoreFinishFrame = mFinishFrameAnimation.getTransformation(finishNow, mFinishFrameTransformation);
-            if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish frame: " + mFinishFrameTransformation);
+        if (USE_CUSTOM_BLACK_FRAME) {
+            mMoreFinishFrame = false;
+            if (mFinishFrameAnimation != null) {
+                mMoreFinishFrame = mFinishFrameAnimation.getTransformation(finishNow, mFinishFrameTransformation);
+                if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish frame: " + mFinishFrameTransformation);
+            }
         }
 
         mMoreRotateExit = false;
@@ -702,24 +721,28 @@
             if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate enter: " + mRotateEnterTransformation);
         }
 
-        mMoreRotateFrame = false;
-        if (mRotateFrameAnimation != null) {
-            mMoreRotateFrame = mRotateFrameAnimation.getTransformation(now, mRotateFrameTransformation);
-            if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate frame: " + mRotateFrameTransformation);
+        if (USE_CUSTOM_BLACK_FRAME) {
+            mMoreRotateFrame = false;
+            if (mRotateFrameAnimation != null) {
+                mMoreRotateFrame = mRotateFrameAnimation.getTransformation(now, mRotateFrameTransformation);
+                if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate frame: " + mRotateFrameTransformation);
+            }
         }
 
-        if (!mMoreStartExit && !mMoreRotateExit && !mMoreFinishExit) {
-            if (mStartExitAnimation != null) {
-                if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, clearing start exit anim!");
-                mStartExitAnimation.cancel();
-                mStartExitAnimation = null;
-                mStartExitTransformation.clear();
-            }
-            if (mFinishExitAnimation != null) {
-                if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, clearing finish exit anim!");
-                mFinishExitAnimation.cancel();
-                mFinishExitAnimation = null;
-                mFinishExitTransformation.clear();
+        if (!mMoreRotateExit && (!TWO_PHASE_ANIMATION || (!mMoreStartExit && !mMoreFinishExit))) {
+            if (TWO_PHASE_ANIMATION) {
+                if (mStartExitAnimation != null) {
+                    if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, clearing start exit anim!");
+                    mStartExitAnimation.cancel();
+                    mStartExitAnimation = null;
+                    mStartExitTransformation.clear();
+                }
+                if (mFinishExitAnimation != null) {
+                    if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, clearing finish exit anim!");
+                    mFinishExitAnimation.cancel();
+                    mFinishExitAnimation = null;
+                    mFinishExitTransformation.clear();
+                }
             }
             if (mRotateExitAnimation != null) {
                 if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, clearing rotate exit anim!");
@@ -729,18 +752,20 @@
             }
         }
 
-        if (!mMoreStartEnter && !mMoreRotateEnter && !mMoreFinishEnter) {
-            if (mStartEnterAnimation != null) {
-                if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, clearing start enter anim!");
-                mStartEnterAnimation.cancel();
-                mStartEnterAnimation = null;
-                mStartEnterTransformation.clear();
-            }
-            if (mFinishEnterAnimation != null) {
-                if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, clearing finish enter anim!");
-                mFinishEnterAnimation.cancel();
-                mFinishEnterAnimation = null;
-                mFinishEnterTransformation.clear();
+        if (!mMoreRotateEnter && (!TWO_PHASE_ANIMATION || (!mMoreStartEnter && !mMoreFinishEnter))) {
+            if (TWO_PHASE_ANIMATION) {
+                if (mStartEnterAnimation != null) {
+                    if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, clearing start enter anim!");
+                    mStartEnterAnimation.cancel();
+                    mStartEnterAnimation = null;
+                    mStartEnterTransformation.clear();
+                }
+                if (mFinishEnterAnimation != null) {
+                    if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, clearing finish enter anim!");
+                    mFinishEnterAnimation.cancel();
+                    mFinishEnterAnimation = null;
+                    mFinishEnterTransformation.clear();
+                }
             }
             if (mRotateEnterAnimation != null) {
                 if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, clearing rotate enter anim!");
@@ -772,12 +797,14 @@
         }
 
         mExitTransformation.set(mRotateExitTransformation);
-        mExitTransformation.compose(mStartExitTransformation);
-        mExitTransformation.compose(mFinishExitTransformation);
-
         mEnterTransformation.set(mRotateEnterTransformation);
-        mEnterTransformation.compose(mStartEnterTransformation);
-        mEnterTransformation.compose(mFinishEnterTransformation);
+        if (TWO_PHASE_ANIMATION) {
+            mExitTransformation.compose(mStartExitTransformation);
+            mExitTransformation.compose(mFinishExitTransformation);
+
+            mEnterTransformation.compose(mStartEnterTransformation);
+            mEnterTransformation.compose(mFinishEnterTransformation);
+        }
 
         if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final exit: " + mExitTransformation);
         if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final enter: " + mEnterTransformation);
@@ -793,9 +820,11 @@
             if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final frame: " + mFrameTransformation);
         }
 
-        final boolean more = mMoreStartEnter || mMoreStartExit || mMoreStartFrame
-                || mMoreFinishEnter || mMoreFinishExit || mMoreFinishFrame
-                || mMoreRotateEnter || mMoreRotateExit || mMoreRotateFrame
+        final boolean more = (TWO_PHASE_ANIMATION
+                    && (mMoreStartEnter || mMoreStartExit || mMoreFinishEnter || mMoreFinishExit))
+                || (USE_CUSTOM_BLACK_FRAME
+                        && (mMoreStartFrame || mMoreRotateFrame || mMoreFinishFrame))
+                || mMoreRotateEnter || mMoreRotateExit 
                 || !mFinishAnimReady;
 
         mSnapshotFinalMatrix.setConcat(mExitTransformation.getMatrix(), mSnapshotInitialMatrix);
@@ -848,7 +877,7 @@
 
         setSnapshotTransform(mSnapshotFinalMatrix, mExitTransformation.getAlpha());
     }
-    
+
     public boolean stepAnimationLocked(long now) {
         if (!hasAnimations()) {
             if (DEBUG_STATE) Slog.v(TAG, "Step: no animations running");
@@ -858,23 +887,30 @@
 
         if (!mAnimRunning) {
             if (DEBUG_STATE) Slog.v(TAG, "Step: starting start, finish, rotate");
-            if (mStartEnterAnimation != null) {
-                mStartEnterAnimation.setStartTime(now);
+            if (TWO_PHASE_ANIMATION) {
+                if (mStartEnterAnimation != null) {
+                    mStartEnterAnimation.setStartTime(now);
+                }
+                if (mStartExitAnimation != null) {
+                    mStartExitAnimation.setStartTime(now);
+                }
+                if (mFinishEnterAnimation != null) {
+                    mFinishEnterAnimation.setStartTime(0);
+                }
+                if (mFinishExitAnimation != null) {
+                    mFinishExitAnimation.setStartTime(0);
+                }
             }
-            if (mStartExitAnimation != null) {
-                mStartExitAnimation.setStartTime(now);
-            }
-            if (mStartFrameAnimation != null) {
-                mStartFrameAnimation.setStartTime(now);
-            }
-            if (mFinishEnterAnimation != null) {
-                mFinishEnterAnimation.setStartTime(0);
-            }
-            if (mFinishExitAnimation != null) {
-                mFinishExitAnimation.setStartTime(0);
-            }
-            if (mFinishFrameAnimation != null) {
-                mFinishFrameAnimation.setStartTime(0);
+            if (USE_CUSTOM_BLACK_FRAME) {
+                if (mStartFrameAnimation != null) {
+                    mStartFrameAnimation.setStartTime(now);
+                }
+                if (mFinishFrameAnimation != null) {
+                    mFinishFrameAnimation.setStartTime(0);
+                }
+                if (mRotateFrameAnimation != null) {
+                    mRotateFrameAnimation.setStartTime(now);
+                }
             }
             if (mRotateEnterAnimation != null) {
                 mRotateEnterAnimation.setStartTime(now);
@@ -882,10 +918,8 @@
             if (mRotateExitAnimation != null) {
                 mRotateExitAnimation.setStartTime(now);
             }
-            if (mRotateFrameAnimation != null) {
-                mRotateFrameAnimation.setStartTime(now);
-            }
             mAnimRunning = true;
+            mHalfwayPoint = now + mRotateEnterAnimation.getDuration() / 2;
         }
 
         return stepAnimation(now);
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index 00fd7d8..7611a0f 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -431,6 +431,10 @@
         mPendingLayoutChanges = 0;
         mCurrentTime = SystemClock.uptimeMillis();
         mBulkUpdateParams = 0;
+        mAnimating = false;
+        if (WindowManagerService.DEBUG_WINDOW_TRACE) {
+            Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime);
+        }
 
         // Update animations of all applications, including those
         // associated with exiting/removed apps
@@ -478,7 +482,16 @@
             Surface.closeTransaction();
         }
 
-        mService.bulkSetParameters(mBulkUpdateParams);
+        mService.bulkSetParameters(mBulkUpdateParams, mPendingLayoutChanges);
+
+        if (mAnimating) {
+            mService.scheduleAnimationLocked();
+        }
+        if (WindowManagerService.DEBUG_WINDOW_TRACE) {
+            Slog.i(TAG, "!!! animate: exit mAnimating=" + mAnimating
+                + " mBulkUpdateParams=" + Integer.toHexString(mBulkUpdateParams)
+                + " mPendingLayoutChanges=" + Integer.toHexString(mPendingLayoutChanges));
+        }
     }
 
     WindowState mCurrentFocus;
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 82018fe..966f4c1 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -50,6 +50,7 @@
 
 import android.Manifest;
 import android.app.ActivityManagerNative;
+import android.app.ActivityOptions;
 import android.app.IActivityManager;
 import android.app.StatusBarManager;
 import android.app.admin.DevicePolicyManager;
@@ -176,6 +177,7 @@
     static final boolean DEBUG_BOOT = false;
     static final boolean DEBUG_LAYOUT_REPEATS = true;
     static final boolean DEBUG_SURFACE_TRACE = false;
+    static final boolean DEBUG_WINDOW_TRACE = false;
     static final boolean SHOW_SURFACE_ALLOC = false;
     static final boolean SHOW_TRANSACTIONS = false;
     static final boolean SHOW_LIGHT_TRANSACTIONS = false || SHOW_TRANSACTIONS;
@@ -496,6 +498,7 @@
     // mOpeningApps and mClosingApps are the lists of tokens that will be
     // made visible or hidden at the next transition.
     int mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
+    int mNextAppTransitionType = ActivityOptions.ANIM_NONE;
     String mNextAppTransitionPackage;
     Bitmap mNextAppTransitionThumbnail;
     IRemoteCallback mNextAppTransitionCallback;
@@ -503,6 +506,8 @@
     int mNextAppTransitionExit;
     int mNextAppTransitionStartX;
     int mNextAppTransitionStartY;
+    int mNextAppTransitionStartWidth;
+    int mNextAppTransitionStartHeight;
     boolean mAppTransitionReady = false;
     boolean mAppTransitionRunning = false;
     boolean mAppTransitionTimeout = false;
@@ -593,6 +598,7 @@
         static final int SET_WALLPAPER_MAY_CHANGE           = 1 << 1;
         static final int SET_FORCE_HIDING_CHANGED           = 1 << 2;
         static final int CLEAR_ORIENTATION_CHANGE_COMPLETE  = 1 << 3;
+        static final int SET_TURN_ON_SCREEN                 = 1 << 4;
 
         boolean mWallpaperForceHidingChanged = false;
         boolean mWallpaperMayChange = false;
@@ -616,7 +622,20 @@
         public void run() {
             synchronized(mWindowMap) {
                 mAnimationScheduled = false;
-                performLayoutAndPlaceSurfacesLocked();
+                // Update animations of all applications, including those
+                // associated with exiting/removed apps
+                synchronized (mAnimator) {
+                    final ArrayList<WindowStateAnimator> winAnimators = mAnimator.mWinAnimators;
+                    winAnimators.clear();
+                    final int N = mWindows.size();
+                    for (int i = 0; i < N; i++) {
+                        final WindowStateAnimator winAnimator = mWindows.get(i).mWinAnimator;
+                        if (winAnimator.mSurface != null) {
+                            winAnimators.add(winAnimator);
+                        }
+                    }
+                    mAnimator.animate();
+                }
             }
         }
     }
@@ -3057,6 +3076,50 @@
         return null;
     }
 
+    private Animation createScaleUpAnimationLocked(int transit, boolean enter) {
+        Animation a;
+        // Pick the desired duration.  If this is an inter-activity transition,
+        // it  is the standard duration for that.  Otherwise we use the longer
+        // task transition duration.
+        int duration;
+        switch (transit) {
+            case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
+            case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
+                duration = mContext.getResources().getInteger(
+                        com.android.internal.R.integer.config_shortAnimTime);
+                break;
+            default:
+                duration = 500;
+                break;
+        }
+        if (enter) {
+            // Entering app zooms out from the center of the initial rect.
+            Animation scale = new ScaleAnimation(
+                    mNextAppTransitionStartWidth/mAppDisplayWidth, 1,
+                    mNextAppTransitionStartHeight/mAppDisplayHeight, 1,
+                    mNextAppTransitionStartX + mNextAppTransitionStartWidth/2,
+                    mNextAppTransitionStartY + mNextAppTransitionStartHeight/2);
+            AnimationSet set = new AnimationSet(true);
+            Animation alpha = new AlphaAnimation(0, 1);
+            scale.setDuration(duration);
+            set.addAnimation(scale);
+            alpha.setDuration(duration);
+            set.addAnimation(alpha);
+            a = set;
+        } else {
+            // Exiting app just holds in place.
+            a = new AlphaAnimation(1, 1);
+            a.setDuration(duration);
+        }
+        a.setFillAfter(true);
+        final Interpolator interpolator = AnimationUtils.loadInterpolator(mContext,
+                com.android.internal.R.interpolator.decelerate_quint);
+        a.setInterpolator(interpolator);
+        a.initialize(mAppDisplayWidth, mAppDisplayHeight,
+                mAppDisplayWidth, mAppDisplayHeight);
+        return a;
+    }
+
     private Animation createThumbnailAnimationLocked(int transit,
             boolean enter, boolean thumb) {
         Animation a;
@@ -3075,7 +3138,6 @@
             default:
                 duration = 500;
                 break;
-            
         }
         if (thumb) {
             // Animation for zooming thumbnail from its initial size to
@@ -3123,12 +3185,15 @@
         if (okToDisplay()) {
             Animation a;
             boolean initialized = false;
-            if (mNextAppTransitionThumbnail != null) {
-                a = createThumbnailAnimationLocked(transit, enter, false);
-                initialized = true;
-            } else if (mNextAppTransitionPackage != null) {
+            if (mNextAppTransitionType == ActivityOptions.ANIM_CUSTOM) {
                 a = loadAnimation(mNextAppTransitionPackage, enter ?
                         mNextAppTransitionEnter : mNextAppTransitionExit);
+            } else if (mNextAppTransitionType == ActivityOptions.ANIM_SCALE_UP) {
+                a = createScaleUpAnimationLocked(transit, enter);
+                initialized = true;
+            } else if (mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL) {
+                a = createThumbnailAnimationLocked(transit, enter, false);
+                initialized = true;
             } else {
                 int animAttr = 0;
                 switch (transit) {
@@ -3723,6 +3788,7 @@
     public void overridePendingAppTransition(String packageName,
             int enterAnim, int exitAnim) {
         if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
+            mNextAppTransitionType = ActivityOptions.ANIM_CUSTOM;
             mNextAppTransitionPackage = packageName;
             mNextAppTransitionThumbnail = null;
             mNextAppTransitionEnter = enterAnim;
@@ -3730,9 +3796,23 @@
         }
     }
 
+    public void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
+            int startHeight) {
+        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
+            mNextAppTransitionType = ActivityOptions.ANIM_SCALE_UP;
+            mNextAppTransitionPackage = null;
+            mNextAppTransitionThumbnail = null;
+            mNextAppTransitionStartX = startX;
+            mNextAppTransitionStartY = startY;
+            mNextAppTransitionStartWidth = startWidth;
+            mNextAppTransitionStartHeight = startHeight;
+        }
+    }
+
     public void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX,
             int startY, IRemoteCallback startedCallback) {
         if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
+            mNextAppTransitionType = ActivityOptions.ANIM_THUMBNAIL;
             mNextAppTransitionPackage = null;
             mNextAppTransitionThumbnail = srcThumb;
             mNextAppTransitionStartX = startX;
@@ -4165,6 +4245,7 @@
                     if (w.mHasSurface && !w.mOrientationChanging) {
                         if (DEBUG_ORIENTATION) Slog.v(TAG, "set mOrientationChanging of " + w);
                         w.mOrientationChanging = true;
+                        mInnerFields.mOrientationChangeComplete = false;
                     }
                     unfrozeWindows = true;
                 }
@@ -5470,6 +5551,7 @@
             if (w.mHasSurface) {
                 if (DEBUG_ORIENTATION) Slog.v(TAG, "Set mOrientationChanging of " + w);
                 w.mOrientationChanging = true;
+                mInnerFields.mOrientationChangeComplete = false;
             }
         }
         for (int i=mRotationWatchers.size()-1; i>=0; i--) {
@@ -6487,6 +6569,9 @@
 
         @Override
         public void handleMessage(Message msg) {
+            if (DEBUG_WINDOW_TRACE) {
+                Slog.v(TAG, "handleMessage: entry what=" + msg.what);
+            }
             switch (msg.what) {
                 case REPORT_FOCUS_CHANGE: {
                     WindowState lastFocus;
@@ -6918,6 +7003,14 @@
                                 doRequest = true;
                             }
                         }
+                        if ((msg.arg1 & LayoutFields.SET_TURN_ON_SCREEN) != 0) {
+                            mTurnOnScreen = true;
+                        }
+
+                        mPendingLayoutChanges |= msg.arg2;
+                        if (mPendingLayoutChanges != 0) {
+                            doRequest = true;
+                        }
 
                         if (doRequest) {
                             requestTraversalLocked();
@@ -6962,6 +7055,9 @@
                     break;
                 }
             }
+            if (DEBUG_WINDOW_TRACE) {
+                Slog.v(TAG, "handleMessage: exit");
+            }
         }
     }
 
@@ -6969,6 +7065,7 @@
     // IWindowManager API
     // -------------------------------------------------------------
 
+    @Override
     public IWindowSession openSession(IInputMethodClient client,
             IInputContext inputContext) {
         if (client == null) throw new IllegalArgumentException("null client");
@@ -6977,6 +7074,7 @@
         return session;
     }
 
+    @Override
     public boolean inputMethodClientHasFocus(IInputMethodClient client) {
         synchronized (mWindowMap) {
             // The focus for the client is the window immediately below
@@ -7410,12 +7508,6 @@
             } else {
                 mLayoutRepeatCount = 0;
             }
-            
-            if (mAnimator.mAnimating) {
-                // Do this even if requestTraversalLocked was called above so we get a frame drawn
-                // at the proper time as well as the one drawn early.
-                scheduleAnimationLocked();
-            }
 
             if (mWindowsChanged && !mWindowChangeListeners.isEmpty()) {
                 mH.removeMessages(H.REPORT_WINDOWS_CHANGE);
@@ -7564,6 +7656,7 @@
             if (DEBUG_ORIENTATION) Slog.v(TAG,
                     "Changing surface while display frozen: " + w);
             w.mOrientationChanging = true;
+            mInnerFields.mOrientationChangeComplete = false;
             if (!mWindowsFreezingScreen) {
                 mWindowsFreezingScreen = true;
                 // XXX should probably keep timeout from
@@ -7820,6 +7913,7 @@
                 }
             }
 
+            mNextAppTransitionType = ActivityOptions.ANIM_NONE;
             mNextAppTransitionPackage = null;
             mNextAppTransitionThumbnail = null;
             if (mNextAppTransitionCallback != null) {
@@ -7931,7 +8025,7 @@
                     Slog.v(TAG, "Resize reasons: "
                             + " contentInsetsChanged=" + w.mContentInsetsChanged
                             + " visibleInsetsChanged=" + w.mVisibleInsetsChanged
-                            + " surfaceResized=" + w.mWinAnimator.mSurfaceResized
+                            + " surfaceResized=" + winAnimator.mSurfaceResized
                             + " configChanged=" + configChanged);
                 }
 
@@ -7946,7 +8040,7 @@
                 if (w.mOrientationChanging) {
                     if (DEBUG_ORIENTATION) Slog.v(TAG,
                             "Orientation start waiting for draw in "
-                            + w + ", surface " + w.mWinAnimator.mSurface);
+                            + w + ", surface " + winAnimator.mSurface);
                     winAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
                     if (w.mAppToken != null) {
                         w.mAppToken.allDrawn = false;
@@ -7954,15 +8048,15 @@
                 }
                 if (!mResizingWindows.contains(w)) {
                     if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
-                            "Resizing window " + w + " to " + w.mWinAnimator.mSurfaceW
-                            + "x" + w.mWinAnimator.mSurfaceH);
+                            "Resizing window " + w + " to " + winAnimator.mSurfaceW
+                            + "x" + winAnimator.mSurfaceH);
                     mResizingWindows.add(w);
                 }
             } else if (w.mOrientationChanging) {
                 if (w.isDrawnLw()) {
                     if (DEBUG_ORIENTATION) Slog.v(TAG,
                             "Orientation not waiting for draw in "
-                            + w + ", surface " + w.mWinAnimator.mSurface);
+                            + w + ", surface " + winAnimator.mSurface);
                     w.mOrientationChanging = false;
                 }
             }
@@ -8033,6 +8127,10 @@
     // "Something has changed!  Let's make it correct now."
     private final void performLayoutAndPlaceSurfacesLockedInner(
             boolean recoveringMemory) {
+        if (DEBUG_WINDOW_TRACE) {
+            Slog.v(TAG, "performLayoutAndPlaceSurfacesLockedInner: entry. Called by "
+                    + Debug.getCallers(3));
+        }
         if (mDisplay == null) {
             Slog.i(TAG, "skipping performLayoutAndPlaceSurfacesLockedInner with no mDisplay");
             return;
@@ -8051,7 +8149,7 @@
             updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
                     false /*updateInputWindows*/);
         }
-        
+
         // Initialize state of exiting tokens.
         for (i=mExitingTokens.size()-1; i>=0; i--) {
             mExitingTokens.get(i).hasVisible = false;
@@ -8065,7 +8163,6 @@
         mInnerFields.mHoldScreen = null;
         mInnerFields.mScreenBrightness = -1;
         mInnerFields.mButtonBrightness = -1;
-        mAnimator.mAnimating = false;
 
         if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                 ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
@@ -8081,7 +8178,7 @@
 
         try {
             int repeats = 0;
-            
+
             do {
                 repeats++;
                 if (repeats > 6) {
@@ -8141,7 +8238,7 @@
             mInnerFields.mObscured = false;
             mInnerFields.mDimming = false;
             mInnerFields.mSyswin = false;
-            
+
             boolean focusDisplayed = false;
             final int N = mWindows.size();
             for (i=N-1; i>=0; i--) {
@@ -8165,7 +8262,52 @@
                     // has been updated accordingly.
                     updateWallpaperVisibilityLocked();
                 }
+
+                final WindowStateAnimator winAnimator = w.mWinAnimator;
+
+                // If the window has moved due to its containing
+                // content frame changing, then we'd like to animate
+                // it.
+                if (w.mHasSurface && w.shouldAnimateMove()) {
+                    // Frame has moved, containing content frame
+                    // has also moved, and we're not currently animating...
+                    // let's do something.
+                    Animation a = AnimationUtils.loadAnimation(mContext,
+                            com.android.internal.R.anim.window_move_from_decor);
+                    winAnimator.setAnimation(a);
+                    winAnimator.mAnimDw = w.mLastFrame.left - w.mFrame.left;
+                    winAnimator.mAnimDh = w.mLastFrame.top - w.mFrame.top;
+                } else {
+                    winAnimator.mAnimDw = innerDw;
+                    winAnimator.mAnimDh = innerDh;
+                }
+
+                //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
+                w.mContentChanged = false;
+
+                // Moved from updateWindowsAndWallpaperLocked().
+                if (w.mHasSurface) {
+                    // Take care of the window being ready to display.
+                    if (winAnimator.commitFinishDrawingLocked(currentTime)) {
+                        if ((w.mAttrs.flags
+                                & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
+                            if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG,
+                                    "First draw done in potential wallpaper target " + w);
+                            mInnerFields.mWallpaperMayChange = true;
+                            mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+                            if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
+                                debugLayoutRepeats("updateWindowsAndWallpaperLocked 1",
+                                    mPendingLayoutChanges);
+                            }
+                        }
+                    }
+
+                    winAnimator.setSurfaceBoundaries(recoveringMemory);
+                }
+
+                updateResizingWindows(w);
             }
+
             if (focusDisplayed) {
                 mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
             }
@@ -8247,84 +8389,10 @@
             if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("mLayoutNeeded", mPendingLayoutChanges);
         }
 
-        final int N = mWindows.size();
-        for (i=N-1; i>=0; i--) {
-            final WindowState w = mWindows.get(i);
-            final WindowStateAnimator winAnimator = w.mWinAnimator; 
-            
-            // If the window has moved due to its containing
-            // content frame changing, then we'd like to animate
-            // it.
-            if (w.mHasSurface && w.shouldAnimateMove()) {
-                // Frame has moved, containing content frame
-                // has also moved, and we're not currently animating...
-                // let's do something.
-                Animation a = AnimationUtils.loadAnimation(mContext,
-                        com.android.internal.R.anim.window_move_from_decor);
-                winAnimator.setAnimation(a);
-                winAnimator.mAnimDw = w.mLastFrame.left - w.mFrame.left;
-                winAnimator.mAnimDh = w.mLastFrame.top - w.mFrame.top;
-            } else {
-                winAnimator.mAnimDw = innerDw;
-                winAnimator.mAnimDh = innerDh;
-            }
-
-            //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
-            w.mContentChanged = false;
-            
-            // TODO(cmautner): Can this move up to the loop at the end of try/catch above?
-            updateResizingWindows(w);
-
-            // Moved from updateWindowsAndWallpaperLocked().
-            if (w.mHasSurface) {
-                // Take care of the window being ready to display.
-                if (winAnimator.commitFinishDrawingLocked(currentTime)) {
-                    if ((w.mAttrs.flags
-                            & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
-                        if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG,
-                                "First draw done in potential wallpaper target " + w);
-                        mInnerFields.mWallpaperMayChange = true;
-                        mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-                        if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
-                            debugLayoutRepeats("updateWindowsAndWallpaperLocked 1",
-                                mPendingLayoutChanges);
-                        }
-                    }
-                }
-            }
-        }
-
-        // Update animations of all applications, including those
-        // associated with exiting/removed apps
-        synchronized (mAnimator) {
-            final ArrayList<WindowStateAnimator> winAnimators = mAnimator.mWinAnimators;
-            winAnimators.clear();
-            for (i = 0; i < N; i++) {
-                final WindowStateAnimator winAnimator = mWindows.get(i).mWinAnimator;
-                if (winAnimator.mSurface != null) {
-                    winAnimators.add(winAnimator);
-                }
-            }
-            mAnimator.animate();
-            mPendingLayoutChanges |= mAnimator.mPendingLayoutChanges;
-            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after animate()", mPendingLayoutChanges);
-        }
-
-        if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG,
-                "With display frozen, orientationChangeComplete="
-                + mInnerFields.mOrientationChangeComplete);
-        if (mInnerFields.mOrientationChangeComplete) {
-            if (mWindowsFreezingScreen) {
-                mWindowsFreezingScreen = false;
-                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
-            }
-            stopFreezingDisplayLocked();
-        }
-
         if (!mResizingWindows.isEmpty()) {
             for (i = mResizingWindows.size() - 1; i >= 0; i--) {
                 WindowState win = mResizingWindows.get(i);
-                final WindowStateAnimator winAnimator = win.mWinAnimator; 
+                final WindowStateAnimator winAnimator = win.mWinAnimator;
                 try {
                     if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
                             "Reporting new frame to " + win + ": " + win.mCompatFrame);
@@ -8343,7 +8411,7 @@
                     win.mConfiguration = mCurConfiguration;
                     if (DEBUG_ORIENTATION &&
                             winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i(
-                            TAG, "Resizing " + win + " WITH DRAW PENDING"); 
+                            TAG, "Resizing " + win + " WITH DRAW PENDING");
                     win.mClient.resized((int)winAnimator.mSurfaceW,
                             (int)winAnimator.mSurfaceH,
                             win.mLastContentInsets, win.mLastVisibleInsets,
@@ -8359,6 +8427,17 @@
             mResizingWindows.clear();
         }
 
+        if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG,
+                "With display frozen, orientationChangeComplete="
+                + mInnerFields.mOrientationChangeComplete);
+        if (mInnerFields.mOrientationChangeComplete) {
+            if (mWindowsFreezingScreen) {
+                mWindowsFreezingScreen = false;
+                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
+            }
+            stopFreezingDisplayLocked();
+        }
+
         // Destroy the surface of any windows that are no longer visible.
         boolean wallpaperDestroyed = false;
         i = mDestroySurface.size();
@@ -8475,9 +8554,14 @@
         // Check to see if we are now in a state where the screen should
         // be enabled, because the window obscured flags have changed.
         enableScreenIfNeededLocked();
-//        Slog.e(TAG, "performLayoutAndPlaceSurfacesLockedInner exit: mPendingLayoutChanges="
-//                + Integer.toHexString(mPendingLayoutChanges) + " mLayoutNeeded=" + mLayoutNeeded
-//                + " animating=" + mAnimator.mAnimating);
+
+        scheduleAnimationLocked();
+
+        if (DEBUG_WINDOW_TRACE) {
+            Slog.e(TAG, "performLayoutAndPlaceSurfacesLockedInner exit: mPendingLayoutChanges="
+                + Integer.toHexString(mPendingLayoutChanges) + " mLayoutNeeded=" + mLayoutNeeded
+                + " animating=" + mAnimator.mAnimating);
+        }
     }
 
     void checkDrawnWindowsLocked() {
@@ -8789,11 +8873,12 @@
         mScreenFrozenLock.acquire();
 
         mDisplayFrozen = true;
-        
+
         mInputMonitor.freezeInputDispatchingLw();
-        
+
         if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
             mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
+            mNextAppTransitionType = ActivityOptions.ANIM_NONE;
             mNextAppTransitionPackage = null;
             mNextAppTransitionThumbnail = null;
             mAppTransitionReady = true;
@@ -8850,6 +8935,7 @@
                     mTransitionAnimationScale, mCurDisplayWidth, mCurDisplayHeight)) {
                 scheduleAnimationLocked();
             } else {
+                mAnimator.mScreenRotationAnimation.kill();
                 mAnimator.mScreenRotationAnimation = null;
                 updateRotation = true;
             }
@@ -9333,20 +9419,34 @@
                     pw.print(Integer.toHexString(mNextAppTransition));
                     pw.print(" mAppTransitionReady="); pw.println(mAppTransitionReady);
             pw.print("  mAppTransitionRunning="); pw.print(mAppTransitionRunning);
-                    pw.print(" mAppTransitionTimeout="); pw.println( mAppTransitionTimeout);
-            if (mNextAppTransitionPackage != null) {
-                pw.print("  mNextAppTransitionPackage=");
-                    pw.print(mNextAppTransitionPackage);
-                    pw.print(" mNextAppTransitionEnter=0x");
-                    pw.print(Integer.toHexString(mNextAppTransitionEnter));
-                    pw.print(" mNextAppTransitionExit=0x");
-                    pw.print(Integer.toHexString(mNextAppTransitionExit));
+                    pw.print(" mAppTransitionTimeout="); pw.println(mAppTransitionTimeout);
+            if (mNextAppTransitionType != ActivityOptions.ANIM_NONE) {
+                pw.print("  mNextAppTransitionType="); pw.println(mNextAppTransitionType);
             }
-            if (mNextAppTransitionThumbnail != null) {
-                pw.print("  mNextAppTransitionThumbnail=");
-                    pw.print(mNextAppTransitionThumbnail);
-                    pw.print(" mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX);
-                    pw.print(" mNextAppTransitionStartY="); pw.println(mNextAppTransitionStartY);
+            switch (mNextAppTransitionType) {
+                case ActivityOptions.ANIM_CUSTOM:
+                    pw.print("  mNextAppTransitionPackage=");
+                            pw.print(mNextAppTransitionPackage);
+                            pw.print(" mNextAppTransitionEnter=0x");
+                            pw.print(Integer.toHexString(mNextAppTransitionEnter));
+                            pw.print(" mNextAppTransitionExit=0x");
+                            pw.print(Integer.toHexString(mNextAppTransitionExit));
+                    break;
+                case ActivityOptions.ANIM_SCALE_UP:
+                    pw.print("  mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX);
+                            pw.print(" mNextAppTransitionStartY=");
+                            pw.println(mNextAppTransitionStartY);
+                    pw.print("  mNextAppTransitionStartWidth=");
+                            pw.print(mNextAppTransitionStartWidth);
+                            pw.print(" mNextAppTransitionStartHeight=");
+                            pw.println(mNextAppTransitionStartHeight);
+                    break;
+                case ActivityOptions.ANIM_THUMBNAIL:
+                    pw.print("  mNextAppTransitionThumbnail=");
+                            pw.print(mNextAppTransitionThumbnail);
+                            pw.print(" mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX);
+                            pw.print(" mNextAppTransitionStartY="); pw.println(mNextAppTransitionStartY);
+                    break;
             }
             pw.print("  mStartingIconInTransition="); pw.print(mStartingIconInTransition);
                     pw.print(", mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
@@ -9517,12 +9617,8 @@
         }
     }
 
-    void bulkSetParameters(final int bulkUpdateParams) {
-        mH.sendMessage(mH.obtainMessage(H.BULK_UPDATE_PARAMETERS, bulkUpdateParams, 0));
-    }
-
-    static String getCaller() {
-        StackTraceElement caller = Thread.currentThread().getStackTrace()[4];
-        return caller.getClassName() + "." + caller.getMethodName() + ":" + caller.getLineNumber();
+    void bulkSetParameters(final int bulkUpdateParams, int pendingLayoutChanges) {
+        mH.sendMessage(mH.obtainMessage(H.BULK_UPDATE_PARAMETERS, bulkUpdateParams,
+                pendingLayoutChanges));
     }
 }
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 164325b..0a7e7fd 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -6,6 +6,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 
 import static com.android.server.wm.WindowManagerService.LayoutFields.CLEAR_ORIENTATION_CHANGE_COMPLETE;
+import static com.android.server.wm.WindowManagerService.LayoutFields.SET_TURN_ON_SCREEN;
 
 import android.content.Context;
 import android.graphics.Matrix;
@@ -14,6 +15,7 @@
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.Region;
+import android.os.Debug;
 import android.os.RemoteException;
 import android.util.Slog;
 import android.view.Surface;
@@ -84,9 +86,9 @@
      */
     boolean mSurfaceDestroyDeferred;
 
-    float mShownAlpha = 1;
-    float mAlpha = 1;
-    float mLastAlpha = 1;
+    float mShownAlpha = 0;
+    float mAlpha = 0;
+    float mLastAlpha = 0;
 
     // Used to save animation distances between the time they are calculated and when they are
     // used.
@@ -403,50 +405,55 @@
         return true;
     }
 
-    static class MySurface extends Surface {
-        final static ArrayList<MySurface> sSurfaces = new ArrayList<MySurface>();
+    static class SurfaceTrace extends Surface {
+        private final static String SURFACE_TAG = "SurfaceTrace";
+        final static ArrayList<SurfaceTrace> sSurfaces = new ArrayList<SurfaceTrace>();
 
-        private float mMySurfaceAlpha = 0xff;
+        private float mSurfaceTraceAlpha = 0;
         private int mLayer;
         private PointF mPosition = new PointF();
-        private Point mSize = new Point();
+        private Point mSize;
         private boolean mShown = false;
         private String mName = "Not named";
 
-        public MySurface(SurfaceSession s,
+        public SurfaceTrace(SurfaceSession s,
                        int pid, int display, int w, int h, int format, int flags) throws
                        OutOfResourcesException {
             super(s, pid, display, w, h, format, flags);
             mSize = new Point(w, h);
-            Slog.v("SurfaceTrace", "ctor: " + this);
+            Slog.v(SURFACE_TAG, "ctor: " + this + ". Called by "
+                    + Debug.getCallers(3));
         }
 
-        public MySurface(SurfaceSession s,
+        public SurfaceTrace(SurfaceSession s,
                        int pid, String name, int display, int w, int h, int format, int flags)
                    throws OutOfResourcesException {
             super(s, pid, name, display, w, h, format, flags);
             mName = name;
             mSize = new Point(w, h);
-            Slog.v("SurfaceTrace", "ctor: " + this);
+            Slog.v(SURFACE_TAG, "ctor: " + this + ". Called by "
+                    + Debug.getCallers(3));
         }
 
         @Override
         public void setAlpha(float alpha) {
             super.setAlpha(alpha);
-            mMySurfaceAlpha = alpha;
-            Slog.v("SurfaceTrace", "setAlpha: " + this);
+            mSurfaceTraceAlpha = alpha;
+            Slog.v(SURFACE_TAG, "setAlpha: " + this + ". Called by "
+                    + Debug.getCallers(3));
         }
 
         @Override
         public void setLayer(int zorder) {
             super.setLayer(zorder);
             mLayer = zorder;
-            Slog.v("SurfaceTrace", "setLayer: " + this);
+            Slog.v(SURFACE_TAG, "setLayer: " + this + ". Called by "
+                    + Debug.getCallers(3));
 
             sSurfaces.remove(this);
             int i;
             for (i = sSurfaces.size() - 1; i >= 0; i--) {
-                MySurface s = sSurfaces.get(i);
+                SurfaceTrace s = sSurfaces.get(i);
                 if (s.mLayer < zorder) {
                     break;
                 }
@@ -458,32 +465,46 @@
         public void setPosition(float x, float y) {
             super.setPosition(x, y);
             mPosition = new PointF(x, y);
+            Slog.v(SURFACE_TAG, "setPosition: " + this + ". Called by "
+                    + Debug.getCallers(3));
         }
 
         @Override
         public void setSize(int w, int h) {
             super.setSize(w, h);
             mSize = new Point(w, h);
+            Slog.v(SURFACE_TAG, "setSize: " + this + ". Called by "
+                    + Debug.getCallers(3));
         }
 
         @Override
         public void hide() {
             super.hide();
             mShown = false;
-            Slog.v("SurfaceTrace", "hide: " + this);
+            Slog.v(SURFACE_TAG, "hide: " + this + ". Called by "
+                    + Debug.getCallers(3));
         }
         @Override
         public void show() {
             super.show();
             mShown = true;
-            Slog.v("SurfaceTrace", "show: " + this);
+            Slog.v(SURFACE_TAG, "show: " + this + ". Called by "
+                    + Debug.getCallers(3));
         }
 
         @Override
         public void destroy() {
             super.destroy();
-            Slog.v("SurfaceTrace", "destroy: " + this + ". Called by "
-                    + WindowManagerService.getCaller());
+            Slog.v(SURFACE_TAG, "destroy: " + this + ". Called by "
+                    + Debug.getCallers(3));
+            sSurfaces.remove(this);
+        }
+
+        @Override
+        public void release() {
+            super.release();
+            Slog.v(SURFACE_TAG, "release: " + this + ". Called by "
+                    + Debug.getCallers(3));
             sSurfaces.remove(this);
         }
 
@@ -497,7 +518,7 @@
         @Override
         public String toString() {
             return "Surface " + mName + ": shown=" + mShown + " layer=" + mLayer
-                    + " alpha=" + mMySurfaceAlpha + " " + mPosition.x + "," + mPosition.y
+                    + " alpha=" + mSurfaceTraceAlpha + " " + mPosition.x + "," + mPosition.y
                     + " " + mSize.x + "x" + mSize.y;
         }
     }
@@ -544,7 +565,7 @@
 
             mSurfaceShown = false;
             mSurfaceLayer = 0;
-            mSurfaceAlpha = 1;
+            mSurfaceAlpha = 0;
             mSurfaceX = 0;
             mSurfaceY = 0;
             mSurfaceW = w;
@@ -557,7 +578,7 @@
                     flags |= Surface.OPAQUE;
                 }
                 if (DEBUG_SURFACE_TRACE) {
-                    mSurface = new MySurface(
+                    mSurface = new SurfaceTrace(
                             mSession.mSurfaceSession, mSession.mPid,
                             attrs.getTitle().toString(),
                             0, w, h, format, flags);
@@ -608,6 +629,7 @@
                     mSurface.setPosition(mSurfaceX, mSurfaceY);
                     mSurfaceLayer = mAnimLayer;
                     mSurface.setLayer(mAnimLayer);
+                    mSurface.setAlpha(0);
                     mSurfaceShown = false;
                     mSurface.hide();
                     if ((mWin.mAttrs.flags&WindowManager.LayoutParams.FLAG_DITHER) != 0) {
@@ -873,22 +895,8 @@
         mDtDy = mWin.mGlobalScale;
     }
 
-    public void prepareSurfaceLocked(final boolean recoveringMemory) {
+    void setSurfaceBoundaries(final boolean recoveringMemory) {
         final WindowState w = mWin;
-        if (mSurface == null) {
-            if (w.mOrientationChanging) {
-                if (DEBUG_ORIENTATION) {
-                    Slog.v(TAG, "Orientation change skips hidden " + w);
-                }
-                w.mOrientationChanging = false;
-            }
-            return;
-        }
-
-        boolean displayed = false;
-
-        computeShownFrameLocked();
-
         int width, height;
         if ((w.mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) {
             // for a scaled surface, we just want to use
@@ -937,6 +945,8 @@
                         "SIZE " + width + "x" + height, null);
                 mSurfaceResized = true;
                 mSurface.setSize(width, height);
+                mAnimator.mPendingLayoutChanges |=
+                        WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
             } catch (RuntimeException e) {
                 // If something goes wrong with the surface (such
                 // as running out of memory), don't take down the
@@ -948,6 +958,25 @@
                 }
             }
         }
+    }
+
+    public void prepareSurfaceLocked(final boolean recoveringMemory) {
+        final WindowState w = mWin;
+        if (mSurface == null) {
+            if (w.mOrientationChanging) {
+                if (DEBUG_ORIENTATION) {
+                    Slog.v(TAG, "Orientation change skips hidden " + w);
+                }
+                w.mOrientationChanging = false;
+            }
+            return;
+        }
+
+        boolean displayed = false;
+
+        computeShownFrameLocked();
+
+        setSurfaceBoundaries(recoveringMemory);
 
         if (w.mAttachedHidden || !w.isReadyForDisplay()) {
             if (!mLastHidden) {
@@ -1185,7 +1214,7 @@
                     if (DEBUG_VISIBILITY) Slog.v(TAG,
                             "Show surface turning screen on: " + mWin);
                     mWin.mTurnOnScreen = false;
-                    mService.mTurnOnScreen = true;
+                    mAnimator.mBulkUpdateParams |= SET_TURN_ON_SCREEN;
                 }
             }
             return true;
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
index ac4fd15..e2bd622 100644
--- a/services/jni/Android.mk
+++ b/services/jni/Android.mk
@@ -22,7 +22,8 @@
     $(JNI_H_INCLUDE) \
     frameworks/base/services \
     frameworks/base/core/jni \
-    external/skia/include/core
+    external/skia/include/core \
+    libcore/include
 
 LOCAL_SHARED_LIBRARIES := \
     libandroid_runtime \
diff --git a/services/jni/com_android_server_input_InputManagerService.cpp b/services/jni/com_android_server_input_InputManagerService.cpp
index f1536fd..b361a26 100644
--- a/services/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/jni/com_android_server_input_InputManagerService.cpp
@@ -46,6 +46,9 @@
 #include <android_view_PointerIcon.h>
 #include <android/graphics/GraphicsJNI.h>
 
+#include <ScopedLocalRef.h>
+#include <ScopedUtfChars.h>
+
 #include "com_android_server_PowerManagerService.h"
 #include "com_android_server_input_InputApplicationHandle.h"
 #include "com_android_server_input_InputWindowHandle.h"
@@ -79,6 +82,7 @@
     jmethodID getLongPressTimeout;
     jmethodID getPointerLayer;
     jmethodID getPointerIcon;
+    jmethodID getKeyboardLayoutOverlay;
 } gServiceClassInfo;
 
 static struct {
@@ -179,12 +183,14 @@
     void setSystemUiVisibility(int32_t visibility);
     void setPointerSpeed(int32_t speed);
     void setShowTouches(bool enabled);
+    void reloadKeyboardLayouts();
 
     /* --- InputReaderPolicyInterface implementation --- */
 
     virtual void getReaderConfiguration(InputReaderConfiguration* outConfig);
     virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId);
     virtual void notifyInputDevicesChanged(const Vector<InputDeviceInfo>& inputDevices);
+    virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const String8& inputDeviceDescriptor);
 
     /* --- InputDispatcherPolicyInterface implementation --- */
 
@@ -522,6 +528,29 @@
     checkAndClearExceptionFromCallback(env, "notifyInputDevicesChanged");
 }
 
+sp<KeyCharacterMap> NativeInputManager::getKeyboardLayoutOverlay(
+        const String8& inputDeviceDescriptor) {
+    JNIEnv* env = jniEnv();
+
+    sp<KeyCharacterMap> result;
+    ScopedLocalRef<jstring> descriptorObj(env, env->NewStringUTF(inputDeviceDescriptor.string()));
+    ScopedLocalRef<jobjectArray> arrayObj(env, jobjectArray(env->CallObjectMethod(mServiceObj,
+                gServiceClassInfo.getKeyboardLayoutOverlay, descriptorObj.get())));
+    if (arrayObj.get()) {
+        ScopedLocalRef<jstring> filenameObj(env,
+                jstring(env->GetObjectArrayElement(arrayObj.get(), 0)));
+        ScopedLocalRef<jstring> contentsObj(env,
+                jstring(env->GetObjectArrayElement(arrayObj.get(), 1)));
+        ScopedUtfChars filenameChars(env, filenameObj.get());
+        ScopedUtfChars contentsChars(env, contentsObj.get());
+
+        KeyCharacterMap::loadContents(String8(filenameChars.c_str()),
+                String8(contentsChars.c_str()), KeyCharacterMap::FORMAT_OVERLAY, &result);
+    }
+    checkAndClearExceptionFromCallback(env, "getKeyboardLayoutOverlay");
+    return result;
+}
+
 void NativeInputManager::notifySwitch(nsecs_t when, int32_t switchCode,
         int32_t switchValue, uint32_t policyFlags) {
 #if DEBUG_INPUT_DISPATCHER_POLICY
@@ -728,6 +757,11 @@
             InputReaderConfiguration::CHANGE_SHOW_TOUCHES);
 }
 
+void NativeInputManager::reloadKeyboardLayouts() {
+    mInputManager->getReader()->requestRefreshConfiguration(
+            InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUTS);
+}
+
 bool NativeInputManager::isScreenOn() {
     return android_server_PowerManagerService_isScreenOn();
 }
@@ -1226,6 +1260,45 @@
     im->setShowTouches(enabled);
 }
 
+static void nativeVibrate(JNIEnv* env,
+        jclass clazz, jint ptr, jint deviceId, jlongArray patternObj,
+        jint repeat, jint token) {
+    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+    size_t patternSize = env->GetArrayLength(patternObj);
+    if (patternSize > MAX_VIBRATE_PATTERN_SIZE) {
+        ALOGI("Skipped requested vibration because the pattern size is %d "
+                "which is more than the maximum supported size of %d.",
+                patternSize, MAX_VIBRATE_PATTERN_SIZE);
+        return; // limit to reasonable size
+    }
+
+    jlong* patternMillis = static_cast<jlong*>(env->GetPrimitiveArrayCritical(
+            patternObj, NULL));
+    nsecs_t pattern[patternSize];
+    for (size_t i = 0; i < patternSize; i++) {
+        pattern[i] = max(jlong(0), min(patternMillis[i],
+                MAX_VIBRATE_PATTERN_DELAY_NSECS / 1000000LL)) * 1000000LL;
+    }
+    env->ReleasePrimitiveArrayCritical(patternObj, patternMillis, JNI_ABORT);
+
+    im->getInputManager()->getReader()->vibrate(deviceId, pattern, patternSize, repeat, token);
+}
+
+static void nativeCancelVibrate(JNIEnv* env,
+        jclass clazz, jint ptr, jint deviceId, jint token) {
+    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+    im->getInputManager()->getReader()->cancelVibrate(deviceId, token);
+}
+
+static void nativeReloadKeyboardLayouts(JNIEnv* env,
+        jclass clazz, jint ptr) {
+    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+    im->reloadKeyboardLayouts();
+}
+
 static jstring nativeDump(JNIEnv* env, jclass clazz, jint ptr) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
@@ -1287,6 +1360,12 @@
             (void*) nativeSetPointerSpeed },
     { "nativeSetShowTouches", "(IZ)V",
             (void*) nativeSetShowTouches },
+    { "nativeVibrate", "(II[JII)V",
+            (void*) nativeVibrate },
+    { "nativeCancelVibrate", "(III)V",
+            (void*) nativeCancelVibrate },
+    { "nativeReloadKeyboardLayouts", "(I)V",
+            (void*) nativeReloadKeyboardLayouts },
     { "nativeDump", "(I)Ljava/lang/String;",
             (void*) nativeDump },
     { "nativeMonitor", "(I)V",
@@ -1382,6 +1461,9 @@
     GET_METHOD_ID(gServiceClassInfo.getPointerIcon, clazz,
             "getPointerIcon", "()Landroid/view/PointerIcon;");
 
+    GET_METHOD_ID(gServiceClassInfo.getKeyboardLayoutOverlay, clazz,
+            "getKeyboardLayoutOverlay", "(Ljava/lang/String;)[Ljava/lang/String;");
+
     // InputDevice
 
     FIND_CLASS(gInputDeviceClassInfo.clazz, "android/view/InputDevice");
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 8cfdb79..183beb1 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -64,8 +64,8 @@
     /*
      * Calling Line Identification Restriction (CLIR)
      */
-    private static final String CLIR_ON = "*31#+";
-    private static final String CLIR_OFF = "#31#+";
+    private static final String CLIR_ON = "*31#";
+    private static final String CLIR_OFF = "#31#";
 
     /*
      * TOA = TON + NPI
@@ -213,23 +213,26 @@
 
         int len = phoneNumber.length();
         StringBuilder ret = new StringBuilder(len);
-        boolean firstCharAdded = false;
 
         for (int i = 0; i < len; i++) {
             char c = phoneNumber.charAt(i);
-            if (isDialable(c) && (c != '+' || !firstCharAdded)) {
-                firstCharAdded = true;
+            // Character.digit() supports ASCII and Unicode digits (fullwidth, Arabic-Indic, etc.)
+            int digit = Character.digit(c, 10);
+            if (digit != -1) {
+                ret.append(digit);
+            } else if (c == '+') {
+                // Allow '+' as first character or after CLIR MMI prefix
+                String prefix = ret.toString();
+                if (prefix.length() == 0 || prefix.equals(CLIR_ON) || prefix.equals(CLIR_OFF)) {
+                    ret.append(c);
+                }
+            } else if (isDialable(c)) {
                 ret.append(c);
             } else if (isStartsPostDial (c)) {
                 break;
             }
         }
 
-        int pos = addPlusChar(phoneNumber);
-        if (pos >= 0 && ret.length() > pos) {
-            ret.insert(pos, '+');
-        }
-
         return ret.toString();
     }
 
@@ -283,7 +286,11 @@
 
         for (int i = 0; i < len; i++) {
             char c = phoneNumber.charAt(i);
-            if (isNonSeparator(c)) {
+            // Character.digit() supports ASCII and Unicode digits (fullwidth, Arabic-Indic, etc.)
+            int digit = Character.digit(c, 10);
+            if (digit != -1) {
+                ret.append(digit);
+            } else if (isNonSeparator(c)) {
                 ret.append(c);
             }
         }
@@ -371,28 +378,6 @@
         }
     }
 
-    /** GSM codes
-     *  Finds if a GSM code includes the international prefix (+).
-     *
-     * @param number the number to dial.
-     *
-     * @return the position where the + char will be inserted, -1 if the GSM code was not found.
-     */
-    private static int
-    addPlusChar(String number) {
-        int pos = -1;
-
-        if (number.startsWith(CLIR_OFF)) {
-            pos = CLIR_OFF.length() - 1;
-        }
-
-        if (number.startsWith(CLIR_ON)) {
-            pos = CLIR_ON.length() - 1;
-        }
-
-        return pos;
-    }
-
     /**
      * Extracts the post-dial sequence of DTMF control digits, pauses, and
      * waits. Strips separators. This string may be empty, but will not be null
@@ -1504,7 +1489,11 @@
         int len = phoneNumber.length();
         for (int i = 0; i < len; i++) {
             char c = phoneNumber.charAt(i);
-            if ((i == 0 && c == '+') || PhoneNumberUtils.isISODigit(c)) {
+            // Character.digit() supports ASCII and Unicode digits (fullwidth, Arabic-Indic, etc.)
+            int digit = Character.digit(c, 10);
+            if (digit != -1) {
+                sb.append(digit);
+            } else if (i == 0 && c == '+') {
                 sb.append(c);
             } else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
                 return normalizeNumber(PhoneNumberUtils.convertKeypadLettersToDigits(phoneNumber));
@@ -1513,6 +1502,27 @@
         return sb.toString();
     }
 
+    /**
+     * Replace arabic/unicode digits with decimal digits.
+     * @param number
+     *            the number to be normalized.
+     * @return the replaced number.
+     *
+     * @hide
+     */
+    public static String replaceUnicodeDigits(String number) {
+        StringBuilder normalizedDigits = new StringBuilder(number.length());
+        for (char c : number.toCharArray()) {
+            int digit = Character.digit(c, 10);
+            if (digit != -1) {
+                normalizedDigits.append(digit);
+            } else {
+                normalizedDigits.append(c);
+            }
+        }
+        return normalizedDigits.toString();
+    }
+
     // Three and four digit phone numbers for either special services,
     // or 3-6 digit addresses from the network (eg carrier-originated SMS messages) should
     // not match.
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index 5d1f758..b1a5872 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.database.Cursor;
+import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
 import android.location.CountryDetector;
 import android.net.Uri;
@@ -107,10 +108,33 @@
     /**
      * Drawable representing the caller image.  This is essentially
      * a cache for the image data tied into the connection /
-     * callerinfo object.  The isCachedPhotoCurrent flag indicates
-     * if the image data needs to be reloaded.
+     * callerinfo object.
+     *
+     * This might be a high resolution picture which is more suitable
+     * for full-screen image view than for smaller icons used in some
+     * kinds of notifications.
+     *
+     * The {@link #isCachedPhotoCurrent} flag indicates if the image
+     * data needs to be reloaded.
      */
     public Drawable cachedPhoto;
+    /**
+     * Bitmap representing the caller image which has possibly lower
+     * resolution than {@link #cachedPhoto} and thus more suitable for
+     * icons (like notification icons).
+     *
+     * In usual cases this is just down-scaled image of {@link #cachedPhoto}.
+     * If the down-scaling fails, this will just become null.
+     *
+     * The {@link #isCachedPhotoCurrent} flag indicates if the image
+     * data needs to be reloaded.
+     */
+    public Bitmap cachedPhotoIcon;
+    /**
+     * Boolean which indicates if {@link #cachedPhoto} and
+     * {@link #cachedPhotoIcon} is fresh enough. If it is false,
+     * those images aren't pointing to valid objects.
+     */
     public boolean isCachedPhotoCurrent;
 
     private boolean mIsEmergency;
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 486a924..a124c7f 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -35,6 +35,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Calendar;
 import java.util.HashMap;
 import java.util.List;
 
@@ -208,6 +209,27 @@
     protected static final int EVENT_RIL_CONNECTED = BASE + 5;
     protected static final int EVENT_DISCONNECT_ALL = BASE + 6;
 
+    private static final int CMD_TO_STRING_COUNT = EVENT_DISCONNECT_ALL + 1;
+    private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
+    static {
+        sCmdToString[EVENT_CONNECT - BASE] = "EVENT_CONNECT";
+        sCmdToString[EVENT_SETUP_DATA_CONNECTION_DONE - BASE] =
+                "EVENT_SETUP_DATA_CONNECTION_DONE";
+        sCmdToString[EVENT_GET_LAST_FAIL_DONE - BASE] = "EVENT_GET_LAST_FAIL_DONE";
+        sCmdToString[EVENT_DEACTIVATE_DONE - BASE] = "EVENT_DEACTIVATE_DONE";
+        sCmdToString[EVENT_DISCONNECT - BASE] = "EVENT_DISCONNECT";
+        sCmdToString[EVENT_RIL_CONNECTED - BASE] = "EVENT_RIL_CONNECTED";
+        sCmdToString[EVENT_DISCONNECT_ALL - BASE] = "EVENT_DISCONNECT_ALL";
+    }
+    protected static String cmdToString(int cmd) {
+        cmd -= BASE;
+        if ((cmd >= 0) && (cmd < sCmdToString.length)) {
+            return sCmdToString[cmd];
+        } else {
+            return null;
+        }
+    }
+
     //***** Tag IDs for EventLog
     protected static final int EVENT_LOG_BAD_DNS_ADDRESS = 50100;
 
@@ -242,6 +264,7 @@
     protected DataConnection(PhoneBase phone, String name, int id, RetryManager rm,
             DataConnectionTracker dct) {
         super(name);
+        setProcessedMessagesSize(100);
         if (DBG) log("DataConnection constructor E");
         this.phone = phone;
         this.mDataConnectionTracker = dct;
@@ -1188,26 +1211,65 @@
                 new DisconnectParams(reason, onCompletedMsg)));
     }
 
+    /**
+     * @return the string for msg.what as our info.
+     */
+    @Override
+    protected String getMessageInfo(Message msg) {
+        String info = null;
+        info = cmdToString(msg.what);
+        if (info == null) {
+            info = DataConnectionAc.cmdToString(msg.what);
+        }
+        return info;
+    }
+
+    /**
+     * Convert a System.currentTimeMillis() value to a time of day value.
+     *
+     * @param millis since the epoch (1/1/1970)
+     * @return String representation of the time.
+     */
+    private String timeMillisToTimeOfDay(long millis) {
+        Calendar c = Calendar.getInstance();
+        if (millis >= 0) {
+            c.setTimeInMillis(millis);
+            return String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c);
+        } else {
+            return Long.toString(millis);
+        }
+    }
+    /**
+     * Dump the current state.
+     *
+     * @param fd
+     * @param pw
+     * @param args
+     */
+    @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        pw.println("DataConnection name=" + getName() + ":");
+        pw.print("DataConnection ");
+        super.dump(fd, pw, args);
         pw.println(" mApnList=" + mApnList);
+        pw.flush();
         pw.println(" mDataConnectionTracker=" + mDataConnectionTracker);
         pw.println(" mApn=" + mApn);
         pw.println(" mTag=" + mTag);
+        pw.flush();
         pw.println(" phone=" + phone);
         pw.println(" mRilVersion=" + mRilVersion);
         pw.println(" cid=" + cid);
+        pw.flush();
         pw.println(" mLinkProperties=" + mLinkProperties);
+        pw.flush();
         pw.println(" mCapabilities=" + mCapabilities);
-        pw.println(" createTime=" + createTime);
-        pw.println(" lastFailTime=" + lastFailTime);
+        pw.println(" createTime=" + timeMillisToTimeOfDay(createTime));
+        pw.println(" lastFailTime=" + timeMillisToTimeOfDay(lastFailTime));
         pw.println(" lastFailCause=" + lastFailCause);
+        pw.flush();
         pw.println(" mRetryOverride=" + mRetryOverride);
         pw.println(" mRefCount=" + mRefCount);
         pw.println(" userData=" + userData);
-        pw.println(" total messages=" + getProcessedMessagesCount());
-        for (int i=0; i < getProcessedMessagesSize(); i++) {
-            pw.printf("  msg[%d]=%s\n", i, getProcessedMessageInfo(i));
-        }
+        pw.flush();
     }
 }
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionAc.java b/telephony/java/com/android/internal/telephony/DataConnectionAc.java
index a9f2cd1..4744ff0 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionAc.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionAc.java
@@ -82,6 +82,51 @@
     public static final int REQ_GET_RECONNECT_INTENT = BASE + 26;
     public static final int RSP_GET_RECONNECT_INTENT = BASE + 27;
 
+    private static final int CMD_TO_STRING_COUNT = RSP_GET_RECONNECT_INTENT + 1;
+    private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
+    static {
+        sCmdToString[REQ_IS_INACTIVE - BASE] = "REQ_IS_INACTIVE";
+        sCmdToString[RSP_IS_INACTIVE - BASE] = "RSP_IS_INACTIVE";
+        sCmdToString[REQ_GET_CID - BASE] = "REQ_GET_CID";
+        sCmdToString[RSP_GET_CID - BASE] = "RSP_GET_CID";
+        sCmdToString[REQ_GET_APNSETTING - BASE] = "REQ_GET_APNSETTING";
+        sCmdToString[RSP_GET_APNSETTING - BASE] = "RSP_GET_APNSETTING";
+        sCmdToString[REQ_GET_LINK_PROPERTIES - BASE] = "REQ_GET_LINK_PROPERTIES";
+        sCmdToString[RSP_GET_LINK_PROPERTIES - BASE] = "RSP_GET_LINK_PROPERTIES";
+        sCmdToString[REQ_SET_LINK_PROPERTIES_HTTP_PROXY - BASE] =
+                "REQ_SET_LINK_PROPERTIES_HTTP_PROXY";
+        sCmdToString[RSP_SET_LINK_PROPERTIES_HTTP_PROXY - BASE] =
+                "RSP_SET_LINK_PROPERTIES_HTTP_PROXY";
+        sCmdToString[REQ_GET_LINK_CAPABILITIES - BASE] = "REQ_GET_LINK_CAPABILITIES";
+        sCmdToString[RSP_GET_LINK_CAPABILITIES - BASE] = "RSP_GET_LINK_CAPABILITIES";
+        sCmdToString[REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE - BASE] =
+                "REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE";
+        sCmdToString[RSP_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE - BASE] =
+                "RSP_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE";
+        sCmdToString[REQ_RESET - BASE] = "REQ_RESET";
+        sCmdToString[RSP_RESET - BASE] = "RSP_RESET";
+        sCmdToString[REQ_GET_REFCOUNT - BASE] = "REQ_GET_REFCOUNT";
+        sCmdToString[RSP_GET_REFCOUNT - BASE] = "RSP_GET_REFCOUNT";
+        sCmdToString[REQ_ADD_APNCONTEXT - BASE] = "REQ_ADD_APNCONTEXT";
+        sCmdToString[RSP_ADD_APNCONTEXT - BASE] = "RSP_ADD_APNCONTEXT";
+        sCmdToString[REQ_REMOVE_APNCONTEXT - BASE] = "REQ_REMOVE_APNCONTEXT";
+        sCmdToString[RSP_REMOVE_APNCONTEXT - BASE] = "RSP_REMOVE_APNCONTEXT";
+        sCmdToString[REQ_GET_APNCONTEXT_LIST - BASE] = "REQ_GET_APNCONTEXT_LIST";
+        sCmdToString[RSP_GET_APNCONTEXT_LIST - BASE] = "RSP_GET_APNCONTEXT_LIST";
+        sCmdToString[REQ_SET_RECONNECT_INTENT - BASE] = "REQ_SET_RECONNECT_INTENT";
+        sCmdToString[RSP_SET_RECONNECT_INTENT - BASE] = "RSP_SET_RECONNECT_INTENT";
+        sCmdToString[REQ_GET_RECONNECT_INTENT - BASE] = "REQ_GET_RECONNECT_INTENT";
+        sCmdToString[RSP_GET_RECONNECT_INTENT - BASE] = "RSP_GET_RECONNECT_INTENT";
+    }
+    protected static String cmdToString(int cmd) {
+        cmd -= BASE;
+        if ((cmd >= 0) && (cmd < sCmdToString.length)) {
+            return sCmdToString[cmd];
+        } else {
+            return AsyncChannel.cmdToString(cmd + BASE);
+        }
+    }
+
     /**
      * enum used to notify action taken or necessary to be
      * taken after the link property is changed.
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index 55f2ca3..214627d 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -46,6 +46,7 @@
 
 import com.android.internal.R;
 import com.android.internal.telephony.DataConnection.FailCause;
+import com.android.internal.telephony.uicc.UiccController;
 import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.Protocol;
 
@@ -57,6 +58,7 @@
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * {@hide}
@@ -138,6 +140,7 @@
     public static final int EVENT_CLEAN_UP_ALL_CONNECTIONS = BASE + 30;
     public static final int CMD_SET_DEPENDENCY_MET = BASE + 31;
     public static final int CMD_SET_POLICY_DATA_ENABLE = BASE + 32;
+    protected static final int EVENT_ICC_CHANGED = BASE + 33;
 
     /***** Constants *****/
 
@@ -250,6 +253,8 @@
 
     // member variables
     protected PhoneBase mPhone;
+    protected UiccController mUiccController;
+    protected AtomicReference<IccRecords> mIccRecords = new AtomicReference<IccRecords>();
     protected Activity mActivity = Activity.NONE;
     protected State mState = State.IDLE;
     protected Handler mDataConnectionTracker = null;
@@ -500,6 +505,8 @@
     protected DataConnectionTracker(PhoneBase phone) {
         super();
         mPhone = phone;
+        mUiccController = UiccController.getInstance();
+        mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);
 
         IntentFilter filter = new IntentFilter();
         filter.addAction(getActionIntentReconnectAlarm());
@@ -541,6 +548,7 @@
         mIsDisposed = true;
         mPhone.getContext().unregisterReceiver(this.mIntentReceiver);
         mDataRoamingSettingObserver.unregister(mPhone.getContext());
+        mUiccController.unregisterForIccChanged(this);
     }
 
     protected void broadcastMessenger() {
@@ -663,6 +671,7 @@
     protected abstract void onCleanUpConnection(boolean tearDown, int apnId, String reason);
     protected abstract void onCleanUpAllConnections(String cause);
     protected abstract boolean isDataPossible(String apnType);
+    protected abstract void onUpdateIcc();
 
     protected void onDataStallAlarm(int tag) {
         loge("onDataStallAlarm: not impleted tag=" + tag);
@@ -773,6 +782,10 @@
                 onSetPolicyDataEnabled(enabled);
                 break;
             }
+            case EVENT_ICC_CHANGED:
+                onUpdateIcc();
+                break;
+
             default:
                 Log.e("DATA", "Unidentified event msg=" + msg);
                 break;
diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java
index 92024cd..140b7c6 100644
--- a/telephony/java/com/android/internal/telephony/IccCard.java
+++ b/telephony/java/com/android/internal/telephony/IccCard.java
@@ -35,10 +35,12 @@
 
 import com.android.internal.telephony.PhoneBase;
 import com.android.internal.telephony.CommandsInterface.RadioState;
+import com.android.internal.telephony.gsm.GSMPhone;
 import com.android.internal.telephony.gsm.SIMFileHandler;
 import com.android.internal.telephony.gsm.SIMRecords;
 import com.android.internal.telephony.cat.CatService;
 import com.android.internal.telephony.cdma.CDMALTEPhone;
+import com.android.internal.telephony.cdma.CDMAPhone;
 import com.android.internal.telephony.cdma.CdmaLteUiccFileHandler;
 import com.android.internal.telephony.cdma.CdmaLteUiccRecords;
 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
@@ -114,8 +116,6 @@
     protected static final int EVENT_ICC_LOCKED = 1;
     private static final int EVENT_GET_ICC_STATUS_DONE = 2;
     protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 3;
-    private static final int EVENT_PINPUK_DONE = 4;
-    private static final int EVENT_REPOLL_STATUS_DONE = 5;
     protected static final int EVENT_ICC_READY = 6;
     private static final int EVENT_QUERY_FACILITY_LOCK_DONE = 7;
     private static final int EVENT_CHANGE_FACILITY_LOCK_DONE = 8;
@@ -178,34 +178,19 @@
         return State.UNKNOWN;
     }
 
-    public IccCard(PhoneBase phone, String logTag, Boolean is3gpp, Boolean dbg) {
+    public IccCard(PhoneBase phone, IccCardStatus ics, String logTag, boolean dbg) {
         mLogTag = logTag;
         mDbg = dbg;
-        if (mDbg) log("[IccCard] Creating card type " + (is3gpp ? "3gpp" : "3gpp2"));
-        mPhone = phone;
-        this.is3gpp = is3gpp;
+        if (mDbg) log("Creating");
+        update(phone, ics);
         mCdmaSSM = CdmaSubscriptionSourceManager.getInstance(mPhone.getContext(),
                 mPhone.mCM, mHandler, EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null);
-        if (phone.mCM.getLteOnCdmaMode() == Phone.LTE_ON_CDMA_TRUE
-                && phone instanceof CDMALTEPhone) {
-            mIccFileHandler = new CdmaLteUiccFileHandler(this, "", mPhone.mCM);
-            mIccRecords = new CdmaLteUiccRecords(this, mPhone.mContext, mPhone.mCM);
-        } else {
-            // Correct aid will be set later (when GET_SIM_STATUS returns)
-            mIccFileHandler = is3gpp ? new SIMFileHandler(this, "", mPhone.mCM) :
-                                       new RuimFileHandler(this, "", mPhone.mCM);
-            mIccRecords = is3gpp ? new SIMRecords(this, mPhone.mContext, mPhone.mCM) :
-                                   new RuimRecords(this, mPhone.mContext, mPhone.mCM);
-        }
-        mCatService = CatService.getInstance(mPhone.mCM, mIccRecords,
-                mPhone.mContext, mIccFileHandler, this);
         mPhone.mCM.registerForOffOrNotAvailable(mHandler, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
         mPhone.mCM.registerForOn(mHandler, EVENT_RADIO_ON, null);
-        mPhone.mCM.registerForIccStatusChanged(mHandler, EVENT_ICC_STATUS_CHANGED, null);
     }
 
     public void dispose() {
-        if (mDbg) log("[IccCard] Disposing card type " + (is3gpp ? "3gpp" : "3gpp2"));
+        if (mDbg) log("Disposing card type " + (is3gpp ? "3gpp" : "3gpp2"));
         mPhone.mCM.unregisterForIccStatusChanged(mHandler);
         mPhone.mCM.unregisterForOffOrNotAvailable(mHandler);
         mPhone.mCM.unregisterForOn(mHandler);
@@ -215,6 +200,40 @@
         mIccFileHandler.dispose();
     }
 
+    public void update(PhoneBase phone, IccCardStatus ics) {
+        if (phone != mPhone) {
+            PhoneBase oldPhone = mPhone;
+            mPhone = phone;
+            log("Update");
+            if (phone instanceof GSMPhone) {
+                is3gpp = true;
+            } else if (phone instanceof CDMALTEPhone){
+                is3gpp = true;
+            } else if (phone instanceof CDMAPhone){
+                is3gpp = false;
+            } else {
+                throw new RuntimeException("Update: Unhandled phone type. Critical error!" +
+                        phone.getPhoneName());
+            }
+
+
+            if (phone.mCM.getLteOnCdmaMode() == Phone.LTE_ON_CDMA_TRUE
+                    && phone instanceof CDMALTEPhone) {
+                mIccFileHandler = new CdmaLteUiccFileHandler(this, "", mPhone.mCM);
+                mIccRecords = new CdmaLteUiccRecords(this, mPhone.mContext, mPhone.mCM);
+            } else {
+                // Correct aid will be set later (when GET_SIM_STATUS returns)
+                mIccFileHandler = is3gpp ? new SIMFileHandler(this, "", mPhone.mCM) :
+                                           new RuimFileHandler(this, "", mPhone.mCM);
+                mIccRecords = is3gpp ? new SIMRecords(this, mPhone.mContext, mPhone.mCM) :
+                                       new RuimRecords(this, mPhone.mContext, mPhone.mCM);
+            }
+            mCatService = CatService.getInstance(mPhone.mCM, mIccRecords, mPhone.mContext,
+                    mIccFileHandler, this);
+        }
+        mHandler.sendMessage(mHandler.obtainMessage(EVENT_GET_ICC_STATUS_DONE, ics));
+    }
+
     protected void finalize() {
         if (mDbg) log("[IccCard] Finalized card type " + (is3gpp ? "3gpp" : "3gpp2"));
     }
@@ -344,27 +363,23 @@
      */
 
     public void supplyPin (String pin, Message onComplete) {
-        mPhone.mCM.supplyIccPin(pin, mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete));
+        mPhone.mCM.supplyIccPin(pin, onComplete);
     }
 
     public void supplyPuk (String puk, String newPin, Message onComplete) {
-        mPhone.mCM.supplyIccPuk(puk, newPin,
-                mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete));
+        mPhone.mCM.supplyIccPuk(puk, newPin, onComplete);
     }
 
     public void supplyPin2 (String pin2, Message onComplete) {
-        mPhone.mCM.supplyIccPin2(pin2,
-                mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete));
+        mPhone.mCM.supplyIccPin2(pin2, onComplete);
     }
 
     public void supplyPuk2 (String puk2, String newPin2, Message onComplete) {
-        mPhone.mCM.supplyIccPuk2(puk2, newPin2,
-                mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete));
+        mPhone.mCM.supplyIccPuk2(puk2, newPin2, onComplete);
     }
 
     public void supplyNetworkDepersonalization (String pin, Message onComplete) {
-        mPhone.mCM.supplyNetworkDepersonalization(pin,
-                mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete));
+        mPhone.mCM.supplyNetworkDepersonalization(pin, onComplete);
     }
 
     /**
@@ -494,21 +509,15 @@
      *
      */
     public String getServiceProviderName () {
-        return mPhone.mIccRecords.getServiceProviderName();
+        return mIccRecords.getServiceProviderName();
     }
 
     protected void updateStateProperty() {
         mPhone.setSystemProperty(TelephonyProperties.PROPERTY_SIM_STATE, getState().toString());
     }
 
-    private void getIccCardStatusDone(AsyncResult ar) {
-        if (ar.exception != null) {
-            Log.e(mLogTag,"Error getting ICC status. "
-                    + "RIL_REQUEST_GET_ICC_STATUS should "
-                    + "never return an error", ar.exception);
-            return;
-        }
-        handleIccCardStatus((IccCardStatus) ar.result);
+    private void getIccCardStatusDone(IccCardStatus ics) {
+        handleIccCardStatus(ics);
     }
 
     private void handleIccCardStatus(IccCardStatus newCardStatus) {
@@ -584,6 +593,7 @@
         if (oldState != State.READY && newState == State.READY &&
                 (is3gpp || isSubscriptionFromIccCard)) {
             mIccFileHandler.setAid(getAid());
+            broadcastIccStateChangedIntent(INTENT_VALUE_ICC_READY, null);
             mIccRecords.onReady();
         }
     }
@@ -704,7 +714,6 @@
                     if (!is3gpp) {
                         handleCdmaSubscriptionSource();
                     }
-                    mPhone.mCM.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE));
                     break;
                 case EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED:
                     handleCdmaSubscriptionSource();
@@ -725,30 +734,9 @@
                              obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE));
                      break;
                 case EVENT_GET_ICC_STATUS_DONE:
-                    ar = (AsyncResult)msg.obj;
+                    IccCardStatus cs = (IccCardStatus)msg.obj;
 
-                    getIccCardStatusDone(ar);
-                    break;
-                case EVENT_PINPUK_DONE:
-                    // a PIN/PUK/PIN2/PUK2/Network Personalization
-                    // request has completed. ar.userObj is the response Message
-                    // Repoll before returning
-                    ar = (AsyncResult)msg.obj;
-                    // TODO should abstract these exceptions
-                    AsyncResult.forMessage(((Message)ar.userObj)).exception
-                                                        = ar.exception;
-                    mPhone.mCM.getIccCardStatus(
-                        obtainMessage(EVENT_REPOLL_STATUS_DONE, ar.userObj));
-                    break;
-                case EVENT_REPOLL_STATUS_DONE:
-                    // Finished repolling status after PIN operation
-                    // ar.userObj is the response messaeg
-                    // ar.userObj.obj is already an AsyncResult with an
-                    // appropriate exception filled in if applicable
-
-                    ar = (AsyncResult)msg.obj;
-                    getIccCardStatusDone(ar);
-                    ((Message)ar.userObj).sendToTarget();
+                    getIccCardStatusDone(cs);
                     break;
                 case EVENT_QUERY_FACILITY_LOCK_DONE:
                     ar = (AsyncResult)msg.obj;
@@ -797,10 +785,6 @@
                                                         = ar.exception;
                     ((Message)ar.userObj).sendToTarget();
                     break;
-                case EVENT_ICC_STATUS_CHANGED:
-                    Log.d(mLogTag, "Received Event EVENT_ICC_STATUS_CHANGED");
-                    mPhone.mCM.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE));
-                    break;
                 case EVENT_CARD_REMOVED:
                     onIccSwap(false);
                     break;
@@ -967,6 +951,10 @@
         Log.d(mLogTag, "[IccCard] " + msg);
     }
 
+    private void loge(String msg) {
+        Log.e(mLogTag, "[IccCard] " + msg);
+    }
+
     protected int getCurrentApplicationIndex() {
         if (is3gpp) {
             return mIccCardStatus.getGsmUmtsSubscriptionAppIndex();
diff --git a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
index 45562ca..0e5f2da 100644
--- a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
+++ b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
@@ -103,11 +103,23 @@
 
     public IccPhoneBookInterfaceManager(PhoneBase phone) {
         this.phone = phone;
+        IccRecords r = phone.mIccRecords.get();
+        if (r != null) {
+            adnCache = r.getAdnCache();
+        }
     }
 
     public void dispose() {
     }
 
+    public void updateIccRecords(IccRecords iccRecords) {
+        if (iccRecords != null) {
+            adnCache = iccRecords.getAdnCache();
+        } else {
+            adnCache = null;
+        }
+    }
+
     protected void publish() {
         //NOTE service "simphonebook" added by IccSmsInterfaceManagerProxy
         ServiceManager.addService("simphonebook", this);
diff --git a/telephony/java/com/android/internal/telephony/IccRecords.java b/telephony/java/com/android/internal/telephony/IccRecords.java
index 41c9d5a..3c906471a 100644
--- a/telephony/java/com/android/internal/telephony/IccRecords.java
+++ b/telephony/java/com/android/internal/telephony/IccRecords.java
@@ -26,6 +26,8 @@
 import com.android.internal.telephony.gsm.UsimServiceTable;
 import com.android.internal.telephony.ims.IsimRecords;
 
+import java.util.concurrent.atomic.AtomicBoolean;
+
 /**
  * {@hide}
  */
@@ -33,7 +35,7 @@
 
     protected static final boolean DBG = true;
     // ***** Instance Variables
-    protected boolean mDestroyed = false; // set to true once this object needs to be disposed of
+    protected AtomicBoolean mDestroyed = new AtomicBoolean(false);
     protected Context mContext;
     protected CommandsInterface mCi;
     protected IccFileHandler mFh;
@@ -79,9 +81,9 @@
 
     // ***** Event Constants
     protected static final int EVENT_SET_MSISDN_DONE = 30;
-    public static final int EVENT_MWI = 0;
-    public static final int EVENT_CFI = 1;
-    public static final int EVENT_SPN = 2;
+    public static final int EVENT_MWI = 0; // Message Waiting indication
+    public static final int EVENT_CFI = 1; // Call Forwarding indication
+    public static final int EVENT_SPN = 2; // Service Provider Name
 
     public static final int EVENT_GET_ICC_RECORD_DONE = 100;
 
@@ -113,7 +115,7 @@
      * Call when the IccRecords object is no longer going to be used.
      */
     public void dispose() {
-        mDestroyed = true;
+        mDestroyed.set(true);
         mParentCard = null;
         mFh = null;
         mCi = null;
@@ -128,12 +130,8 @@
         return adnCache;
     }
 
-    public IccCard getIccCard() {
-        return mParentCard;
-    }
-
     public void registerForRecordsLoaded(Handler h, int what, Object obj) {
-        if (mDestroyed) {
+        if (mDestroyed.get()) {
             return;
         }
 
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index 2ac9365..0c2f234 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -40,6 +40,7 @@
 import com.android.internal.telephony.gsm.UsimServiceTable;
 import com.android.internal.telephony.ims.IsimRecords;
 import com.android.internal.telephony.test.SimulatedRadioControl;
+import com.android.internal.telephony.uicc.UiccController;
 import com.android.internal.telephony.gsm.SIMRecords;
 
 import java.io.FileDescriptor;
@@ -110,6 +111,7 @@
     protected static final int EVENT_SET_NETWORK_AUTOMATIC          = 28;
     protected static final int EVENT_NEW_ICC_SMS                    = 29;
     protected static final int EVENT_ICC_RECORD_EVENTS              = 30;
+    protected static final int EVENT_ICC_CHANGED                    = 31;
 
     // Key used to read/write current CLIR setting
     public static final String CLIR_KEY = "clir_key";
@@ -126,7 +128,8 @@
     int mCallRingDelay;
     public boolean mIsTheCurrentActivePhone = true;
     boolean mIsVoiceCapable = true;
-    public IccRecords mIccRecords;
+    protected UiccController mUiccController = null;
+    public AtomicReference<IccRecords> mIccRecords = new AtomicReference<IccRecords>();
     protected AtomicReference<IccCard> mIccCard = new AtomicReference<IccCard>();
     public SmsStorageMonitor mSmsStorageMonitor;
     public SmsUsageMonitor mSmsUsageMonitor;
@@ -251,6 +254,8 @@
         // Initialize device storage and outgoing SMS usage monitors for SMSDispatchers.
         mSmsStorageMonitor = new SmsStorageMonitor(this);
         mSmsUsageMonitor = new SmsUsageMonitor(context);
+        mUiccController = UiccController.getInstance(this);
+        mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);
     }
 
     public void dispose() {
@@ -262,6 +267,7 @@
             // Dispose the SMS usage and storage monitors
             mSmsStorageMonitor.dispose();
             mSmsUsageMonitor.dispose();
+            mUiccController.unregisterForIccChanged(this);
         }
     }
 
@@ -269,9 +275,10 @@
         mSmsStorageMonitor = null;
         mSmsUsageMonitor = null;
         mSMS = null;
-        mIccRecords = null;
+        mIccRecords.set(null);
         mIccCard.set(null);
         mDataConnectionTracker = null;
+        mUiccController = null;
     }
 
     /**
@@ -308,6 +315,10 @@
                 }
                 break;
 
+            case EVENT_ICC_CHANGED:
+                onUpdateIccAvailability();
+                break;
+
             default:
                 throw new RuntimeException("unexpected event not handled");
         }
@@ -318,6 +329,9 @@
         return mContext;
     }
 
+    // Will be called when icc changed
+    protected abstract void onUpdateIccAvailability();
+
     /**
      * Disables the DNS check (i.e., allows "0.0.0.0").
      * Useful for lab testing environment.
@@ -666,22 +680,26 @@
 
     @Override
     public String getIccSerialNumber() {
-        return mIccRecords.iccid;
+        IccRecords r = mIccRecords.get();
+        return (r != null) ? r.iccid : "";
     }
 
     @Override
     public boolean getIccRecordsLoaded() {
-        return mIccRecords.getRecordsLoaded();
+        IccRecords r = mIccRecords.get();
+        return (r != null) ? r.getRecordsLoaded() : false;
     }
 
     @Override
     public boolean getMessageWaitingIndicator() {
-        return mIccRecords.getVoiceMessageWaiting();
+        IccRecords r = mIccRecords.get();
+        return (r != null) ? r.getVoiceMessageWaiting() : false;
     }
 
     @Override
     public boolean getCallForwardingIndicator() {
-        return mIccRecords.getVoiceCallForwardingFlag();
+        IccRecords r = mIccRecords.get();
+        return (r != null) ? r.getVoiceCallForwardingFlag() : false;
     }
 
     /**
@@ -1135,7 +1153,10 @@
      */
     @Override
     public void setVoiceMessageWaiting(int line, int countWaiting) {
-        mIccRecords.setVoiceMessageWaiting(line, countWaiting);
+        IccRecords r = mIccRecords.get();
+        if (r != null) {
+            r.setVoiceMessageWaiting(line, countWaiting);
+        }
     }
 
     /**
@@ -1144,7 +1165,8 @@
      */
     @Override
     public UsimServiceTable getUsimServiceTable() {
-        return mIccRecords.getUsimServiceTable();
+        IccRecords r = mIccRecords.get();
+        return (r != null) ? r.getUsimServiceTable() : null;
     }
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
diff --git a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
index 75eb226..a86b68b 100644
--- a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -18,12 +18,15 @@
 
 import android.os.AsyncResult;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Message;
 import android.os.Registrant;
 import android.os.RegistrantList;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 
+import com.android.internal.telephony.uicc.UiccController;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
@@ -33,6 +36,9 @@
 public abstract class ServiceStateTracker extends Handler {
 
     protected CommandsInterface cm;
+    protected UiccController mUiccController = null;
+    protected IccCard mIccCard = null;
+    protected IccRecords mIccRecords = null;
 
     public ServiceState ss;
     protected ServiceState newSS;
@@ -130,7 +136,7 @@
     protected static final int EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED  = 39;
     protected static final int EVENT_CDMA_PRL_VERSION_CHANGED          = 40;
     protected static final int EVENT_RADIO_ON                          = 41;
-
+    protected static final int EVENT_ICC_CHANGED                       = 42;
 
     protected static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
 
@@ -167,7 +173,10 @@
     protected static final String REGISTRATION_DENIED_GEN  = "General";
     protected static final String REGISTRATION_DENIED_AUTH = "Authentication Failure";
 
-    public ServiceStateTracker() {
+    public ServiceStateTracker(PhoneBase p, CommandsInterface ci) {
+        cm = ci;
+        mUiccController = UiccController.getInstance();
+        mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);
     }
 
     public boolean getDesiredPowerState() {
@@ -294,6 +303,10 @@
                 }
                 break;
 
+            case EVENT_ICC_CHANGED:
+                onUpdateIccAvailability();
+                break;
+
             default:
                 log("Unhandled message with number: " + msg.what);
                 break;
@@ -304,6 +317,7 @@
     protected abstract void handlePollStateResult(int what, AsyncResult ar);
     protected abstract void updateSpnDisplay();
     protected abstract void setPowerStateToDesired();
+    protected abstract void onUpdateIccAvailability();
     protected abstract void log(String s);
     protected abstract void loge(String s);
 
@@ -463,6 +477,21 @@
         pollingContext = new int[1];
     }
 
+    /**
+     * Verifies the current thread is the same as the thread originally
+     * used in the initialization of this instance. Throws RuntimeException
+     * if not.
+     *
+     * @exception RuntimeException if the current thread is not
+     * the thread that originally obtained this PhoneBase instance.
+     */
+    protected void checkCorrectThread() {
+        if (Thread.currentThread() != getLooper().getThread()) {
+            throw new RuntimeException(
+                    "ServiceStateTracker must be used from within one thread");
+        }
+    }
+
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("ServiceStateTracker:");
         pw.println(" ss=" + ss);
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
index d99a625..24bb814 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
@@ -29,6 +29,7 @@
 
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.IccCard;
+import com.android.internal.telephony.IccRecords;
 import com.android.internal.telephony.OperatorInfo;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneNotifier;
@@ -66,7 +67,6 @@
     public CDMALTEPhone(Context context, CommandsInterface ci, PhoneNotifier notifier) {
         super(context, ci, notifier, false);
         m3gppSMS = new GsmSMSDispatcher(this, mSmsStorageMonitor, mSmsUsageMonitor);
-        mIccRecords.registerForNewSms(this, EVENT_NEW_ICC_SMS, null);
     }
 
     @Override
@@ -88,10 +88,6 @@
 
     @Override
     protected void initSstIcc() {
-        mIccCard.set(UiccController.getInstance(this).getIccCard());
-        mIccRecords = mIccCard.get().getIccRecords();
-        // CdmaLteServiceStateTracker registers with IccCard to know
-        // when the card is ready. So create mIccCard before the ServiceStateTracker
         mSST = new CdmaLteServiceStateTracker(this);
     }
 
@@ -100,7 +96,6 @@
         synchronized(PhoneProxy.lockForRadioTechnologyChange) {
             super.dispose();
             m3gppSMS.dispose();
-            mIccRecords.unregisterForNewSms(this);
         }
     }
 
@@ -203,11 +198,12 @@
 
     @Override
     public boolean updateCurrentCarrierInProvider() {
-        if (mIccRecords != null) {
+        IccRecords r = mIccRecords.get();
+        if (r != null) {
             try {
                 Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current");
                 ContentValues map = new ContentValues();
-                String operatorNumeric = mIccRecords.getOperatorNumeric();
+                String operatorNumeric = r.getOperatorNumeric();
                 map.put(Telephony.Carriers.NUMERIC, operatorNumeric);
                 if (DBG) log("updateCurrentCarrierInProvider from UICC: numeric=" +
                         operatorNumeric);
@@ -225,7 +221,8 @@
     // return IMSI from USIM as subscriber ID.
     @Override
     public String getSubscriberId() {
-        return mIccRecords.getIMSI();
+        IccRecords r = mIccRecords.get();
+        return (r != null) ? r.getIMSI() : "";
     }
 
     @Override
@@ -240,12 +237,14 @@
 
     @Override
     public IsimRecords getIsimRecords() {
-        return mIccRecords.getIsimRecords();
+        IccRecords r = mIccRecords.get();
+        return (r != null) ? r.getIsimRecords() : null;
     }
 
     @Override
     public String getMsisdn() {
-        return mIccRecords.getMsisdnNumber();
+        IccRecords r = mIccRecords.get();
+        return (r != null) ? r.getMsisdnNumber() : null;
     }
 
     @Override
@@ -259,6 +258,26 @@
     }
 
     @Override
+    protected void registerForRuimRecordEvents() {
+        IccRecords r = mIccRecords.get();
+        if (r == null) {
+            return;
+        }
+        r.registerForNewSms(this, EVENT_NEW_ICC_SMS, null);
+        super.registerForRuimRecordEvents();
+    }
+
+    @Override
+    protected void unregisterForRuimRecordEvents() {
+        IccRecords r = mIccRecords.get();
+        if (r == null) {
+            return;
+        }
+        r.unregisterForNewSms(this);
+        super.unregisterForRuimRecordEvents();
+    }
+
+    @Override
     protected void log(String s) {
             Log.d(LOG_TAG, "[CDMALTEPhone] " + s);
     }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 9f6ec71..7922b3c 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -50,6 +50,7 @@
 import com.android.internal.telephony.IccException;
 import com.android.internal.telephony.IccFileHandler;
 import com.android.internal.telephony.IccPhoneBookInterfaceManager;
+import com.android.internal.telephony.IccRecords;
 import com.android.internal.telephony.IccSmsInterfaceManager;
 import com.android.internal.telephony.MccTable;
 import com.android.internal.telephony.MmiCode;
@@ -152,10 +153,6 @@
     }
 
     protected void initSstIcc() {
-        mIccCard.set(UiccController.getInstance(this).getIccCard());
-        mIccRecords = mIccCard.get().getIccRecords();
-        // CdmaServiceStateTracker registers with IccCard to know
-        // when the Ruim card is ready. So create mIccCard before the ServiceStateTracker
         mSST = new CdmaServiceStateTracker(this);
     }
 
@@ -172,7 +169,6 @@
         mEriManager = new EriManager(this, context, EriManager.ERI_FROM_XML);
 
         mCM.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
-        registerForRuimRecordEvents();
         mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
         mCM.registerForOn(this, EVENT_RADIO_ON, null);
         mCM.setOnSuppServiceNotification(this, EVENT_SSN, null);
@@ -727,7 +723,10 @@
         Message resp;
         mVmNumber = voiceMailNumber;
         resp = obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete);
-        mIccRecords.setVoiceMailNumber(alphaTag, mVmNumber, resp);
+        IccRecords r = mIccRecords.get();
+        if (r != null) {
+            r.setVoiceMailNumber(alphaTag, mVmNumber, resp);
+        }
     }
 
     public String getVoiceMailNumber() {
@@ -749,7 +748,8 @@
      * @hide
      */
     public int getVoiceMessageCount() {
-        int voicemailCount =  mIccRecords.getVoiceMessageCount();
+        IccRecords r = mIccRecords.get();
+        int voicemailCount =  (r != null) ? r.getVoiceMessageCount() : 0;
         // If mRuimRecords.getVoiceMessageCount returns zero, then there is possibility
         // that phone was power cycled and would have lost the voicemail count.
         // So get the count from preferences.
@@ -1064,6 +1064,39 @@
         }
     }
 
+    @Override
+    protected void onUpdateIccAvailability() {
+        if (mUiccController == null ) {
+            return;
+        }
+
+        IccCard newIccCard = mUiccController.getIccCard();
+
+        IccCard c = mIccCard.get();
+        if (c != newIccCard) {
+            if (c != null) {
+                log("Removing stale icc objects.");
+                if (mIccRecords.get() != null) {
+                    unregisterForRuimRecordEvents();
+                    if (mRuimPhoneBookInterfaceManager != null) {
+                        mRuimPhoneBookInterfaceManager.updateIccRecords(null);
+                    }
+                }
+                mIccRecords.set(null);
+                mIccCard.set(null);
+            }
+            if (newIccCard != null) {
+                log("New card found");
+                mIccCard.set(newIccCard);
+                mIccRecords.set(newIccCard.getIccRecords());
+                registerForRuimRecordEvents();
+                if (mRuimPhoneBookInterfaceManager != null) {
+                    mRuimPhoneBookInterfaceManager.updateIccRecords(mIccRecords.get());
+                }
+            }
+        }
+    }
+
     private void processIccRecordEvents(int eventCode) {
         switch (eventCode) {
             case RuimRecords.EVENT_MWI:
@@ -1462,14 +1495,22 @@
         return mEriManager.isEriFileLoaded();
     }
 
-    private void registerForRuimRecordEvents() {
-        mIccRecords.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
-        mIccRecords.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null);
+    protected void registerForRuimRecordEvents() {
+        IccRecords r = mIccRecords.get();
+        if (r == null) {
+            return;
+        }
+        r.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
+        r.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null);
     }
 
-    private void unregisterForRuimRecordEvents() {
-        mIccRecords.unregisterForRecordsEvents(this);
-        mIccRecords.unregisterForRecordsLoaded(this);
+    protected void unregisterForRuimRecordEvents() {
+        IccRecords r = mIccRecords.get();
+        if (r == null) {
+            return;
+        }
+        r.unregisterForRecordsEvents(this);
+        r.unregisterForRecordsLoaded(this);
     }
 
     protected void log(String s) {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index 7e5e707..d05ed624 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -40,6 +40,8 @@
 import com.android.internal.telephony.DataConnectionAc;
 import com.android.internal.telephony.DataConnectionTracker;
 import com.android.internal.telephony.EventLogTags;
+import com.android.internal.telephony.IccCard;
+import com.android.internal.telephony.IccRecords;
 import com.android.internal.telephony.RetryManager;
 import com.android.internal.telephony.RILConstants;
 import com.android.internal.telephony.Phone;
@@ -110,7 +112,6 @@
 
         p.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null);
         p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
-        p.mIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
         p.mCM.registerForDataNetworkStateChanged (this, EVENT_DATA_STATE_CHANGED, null);
         p.mCT.registerForVoiceCallEnded (this, EVENT_VOICE_CALL_ENDED, null);
         p.mCT.registerForVoiceCallStarted (this, EVENT_VOICE_CALL_STARTED, null);
@@ -152,7 +153,8 @@
         // Unregister from all events
         mPhone.mCM.unregisterForAvailable(this);
         mPhone.mCM.unregisterForOffOrNotAvailable(this);
-        mCdmaPhone.mIccRecords.unregisterForRecordsLoaded(this);
+        IccRecords r = mIccRecords.get();
+        if (r != null) { r.unregisterForRecordsLoaded(this);}
         mPhone.mCM.unregisterForDataNetworkStateChanged(this);
         mCdmaPhone.mCT.unregisterForVoiceCallEnded(this);
         mCdmaPhone.mCT.unregisterForVoiceCallStarted(this);
@@ -222,11 +224,12 @@
         boolean subscriptionFromNv = (mCdmaSSM.getCdmaSubscriptionSource()
                                        == CdmaSubscriptionSourceManager.SUBSCRIPTION_FROM_NV);
 
+        IccRecords r = mIccRecords.get();
         boolean allowed =
                     (psState == ServiceState.STATE_IN_SERVICE ||
                             mAutoAttachOnCreation) &&
                     (subscriptionFromNv ||
-                            mCdmaPhone.mIccRecords.getRecordsLoaded()) &&
+                            (r != null && r.getRecordsLoaded())) &&
                     (mCdmaPhone.mSST.isConcurrentVoiceAndDataAllowed() ||
                             mPhone.getState() == Phone.State.IDLE) &&
                     !roaming &&
@@ -241,7 +244,7 @@
                 reason += " - psState= " + psState;
             }
             if (!subscriptionFromNv &&
-                    !mCdmaPhone.mIccRecords.getRecordsLoaded()) {
+                    !(r != null && r.getRecordsLoaded())) {
                 reason += " - RUIM not loaded";
             }
             if (!(mCdmaPhone.mSST.isConcurrentVoiceAndDataAllowed() ||
@@ -1006,6 +1009,33 @@
     }
 
     @Override
+    protected void onUpdateIcc() {
+        if (mUiccController == null ) {
+            return;
+        }
+
+        IccCard newIccCard = mUiccController.getIccCard();
+        IccRecords newIccRecords = null;
+        if (newIccCard != null) {
+            newIccRecords = newIccCard.getIccRecords();
+        }
+
+        IccRecords r = mIccRecords.get();
+        if (r != newIccRecords) {
+            if (r != null) {
+                log("Removing stale icc objects.");
+                r.unregisterForRecordsLoaded(this);
+                mIccRecords.set(null);
+            }
+            if (newIccCard != null) {
+                log("New card found");
+                mIccRecords.set(newIccRecords);
+                newIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
+            }
+        }
+    }
+
+    @Override
     public boolean isDisconnected() {
         return ((mState == State.IDLE) || (mState == State.FAILED));
     }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
index ff7a0810..9a82f57 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
@@ -65,7 +65,7 @@
             handlePollStateResult(msg.what, ar);
             break;
         case EVENT_RUIM_RECORDS_LOADED:
-            CdmaLteUiccRecords sim = (CdmaLteUiccRecords)phone.mIccRecords;
+            CdmaLteUiccRecords sim = (CdmaLteUiccRecords)mIccRecords;
             if ((sim != null) && sim.isProvisioned()) {
                 mMdn = sim.getMdn();
                 mMin = sim.getMin();
@@ -353,16 +353,18 @@
                 ss.setOperatorAlphaLong(eriText);
             }
 
-            if (phone.getIccCard().getState() == IccCard.State.READY) {
+            if (mIccCard != null && mIccCard.getState() == IccCard.State.READY &&
+                    mIccRecords != null) {
                 // SIM is found on the device. If ERI roaming is OFF, and SID/NID matches
                 // one configfured in SIM, use operator name  from CSIM record.
                 boolean showSpn =
-                    ((CdmaLteUiccRecords)phone.mIccRecords).getCsimSpnDisplayCondition();
+                    ((CdmaLteUiccRecords)mIccRecords).getCsimSpnDisplayCondition();
                 int iconIndex = ss.getCdmaEriIconIndex();
 
                 if (showSpn && (iconIndex == EriInfo.ROAMING_INDICATOR_OFF) &&
-                    isInHomeSidNid(ss.getSystemId(), ss.getNetworkId())) {
-                    ss.setOperatorAlphaLong(phone.mIccRecords.getServiceProviderName());
+                    isInHomeSidNid(ss.getSystemId(), ss.getNetworkId()) &&
+                    mIccRecords != null) {
+                    ss.setOperatorAlphaLong(mIccRecords.getServiceProviderName());
                 }
             }
 
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index b694e0a..16ff70e 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -115,12 +115,6 @@
     long mSavedTime;
     long mSavedAtTime;
 
-    /**
-     * We can't register for SIM_RECORDS_LOADED immediately because the
-     * SIMRecords object may not be instantiated yet.
-     */
-    private boolean mNeedToRegForRuimLoaded = false;
-
     /** Wake lock used while setting time of day. */
     private PowerManager.WakeLock mWakeLock;
     private static final String WAKELOCK_TAG = "ServiceStateTracker";
@@ -162,11 +156,10 @@
     };
 
     public CdmaServiceStateTracker(CDMAPhone phone) {
-        super();
+        super(phone, phone.mCM);
 
         this.phone = phone;
         cr = phone.getContext().getContentResolver();
-        cm = phone.mCM;
         ss = new ServiceState();
         newSS = new ServiceState();
         cellLoc = new CdmaCellLocation();
@@ -203,18 +196,17 @@
             Settings.System.getUriFor(Settings.System.AUTO_TIME_ZONE), true,
             mAutoTimeZoneObserver);
         setSignalStrengthDefaultValues();
-
-        mNeedToRegForRuimLoaded = true;
     }
 
     public void dispose() {
+        checkCorrectThread();
         // Unregister for all events.
         cm.unregisterForRadioStateChanged(this);
         cm.unregisterForVoiceNetworkStateChanged(this);
-        phone.getIccCard().unregisterForReady(this);
         cm.unregisterForCdmaOtaProvision(this);
         phone.unregisterForEriFileLoaded(this);
-        phone.mIccRecords.unregisterForRecordsLoaded(this);
+        if (mIccCard != null) {mIccCard.unregisterForReady(this);}
+        if (mIccRecords != null) {mIccRecords.unregisterForRecordsLoaded(this);}
         cm.unSetOnSignalStrengthUpdate(this);
         cm.unSetOnNITZTime(this);
         cr.unregisterContentObserver(mAutoTimeObserver);
@@ -285,14 +277,6 @@
         case EVENT_RUIM_READY:
             // TODO: Consider calling setCurrentPreferredNetworkType as we do in GsmSST.
             // cm.setCurrentPreferredNetworkType();
-
-            // The RUIM is now ready i.e if it was locked it has been
-            // unlocked. At this stage, the radio is already powered on.
-            if (mNeedToRegForRuimLoaded) {
-                phone.mIccRecords.registerForRecordsLoaded(this,
-                        EVENT_RUIM_RECORDS_LOADED, null);
-                mNeedToRegForRuimLoaded = false;
-            }
             if (DBG) log("Receive EVENT_RUIM_READY and Send Request getCDMASubscription.");
             getSubscriptionInfoAndStartPollingThreads();
             phone.prepareEri();
@@ -405,8 +389,16 @@
                     mIsMinInfoReady = true;
 
                     updateOtaspState();
-                    phone.getIccCard().broadcastIccStateChangedIntent(IccCard.INTENT_VALUE_ICC_IMSI,
-                            null);
+                    if (mIccCard != null) {
+                        if (DBG) log("GET_CDMA_SUBSCRIPTION broadcast Icc state changed");
+                        mIccCard.broadcastIccStateChangedIntent(IccCard.INTENT_VALUE_ICC_IMSI,
+                                null);
+                    } else {
+                        if (DBG) {
+                            log("GET_CDMA_SUBSCRIPTION mIccCard is null (probably NV type device)" +
+                                    " can't broadcast Icc state changed");
+                        }
+                    }
                 } else {
                     if (DBG) {
                         log("GET_CDMA_SUBSCRIPTION: error parsing cdmaSubscription params num="
@@ -498,8 +490,6 @@
         if (!isSubscriptionFromRuim) {
             // NV is ready when subscription source is NV
             sendMessage(obtainMessage(EVENT_NV_READY));
-        } else {
-            phone.getIccCard().registerForReady(this, EVENT_RUIM_READY, null);
         }
     }
 
@@ -1695,6 +1685,38 @@
     }
 
     @Override
+    protected void onUpdateIccAvailability() {
+        if (mUiccController == null ) {
+            return;
+        }
+
+        IccCard newIccCard = mUiccController.getIccCard();
+
+        if (mIccCard != newIccCard) {
+            if (mIccCard != null) {
+                log("Removing stale icc objects.");
+                mIccCard.unregisterForReady(this);
+                if (mIccRecords != null) {
+                    mIccRecords.unregisterForRecordsLoaded(this);
+                }
+                mIccRecords = null;
+                mIccCard = null;
+            }
+            if (newIccCard != null) {
+                log("New card found");
+                mIccCard = newIccCard;
+                mIccRecords = mIccCard.getIccRecords();
+                if (isSubscriptionFromRuim) {
+                    mIccCard.registerForReady(this, EVENT_RUIM_READY, null);
+                    if (mIccRecords != null) {
+                        mIccRecords.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null);
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
     protected void log(String s) {
         Log.d(LOG_TAG, "[CdmaSST] " + s);
     }
@@ -1727,7 +1749,6 @@
         pw.println(" mSavedTimeZone=" + mSavedTimeZone);
         pw.println(" mSavedTime=" + mSavedTime);
         pw.println(" mSavedAtTime=" + mSavedAtTime);
-        pw.println(" mNeedToRegForRuimLoaded=" + mNeedToRegForRuimLoaded);
         pw.println(" mWakeLock=" + mWakeLock);
         pw.println(" mCurPlmn=" + mCurPlmn);
         pw.println(" mMdn=" + mMdn);
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java
index 04ee2dd8..e919245 100644
--- a/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java
@@ -21,6 +21,7 @@
 import android.os.Message;
 import android.util.Log;
 
+import com.android.internal.telephony.IccFileHandler;
 import com.android.internal.telephony.IccPhoneBookInterfaceManager;
 
 /**
@@ -34,7 +35,6 @@
 
     public RuimPhoneBookInterfaceManager(CDMAPhone phone) {
         super(phone);
-        adnCache = phone.mIccRecords.getAdnCache();
         //NOTE service "simphonebook" added by IccSmsInterfaceManagerProxy
     }
 
@@ -61,8 +61,12 @@
             AtomicBoolean status = new AtomicBoolean(false);
             Message response = mBaseHandler.obtainMessage(EVENT_GET_SIZE_DONE, status);
 
-            phone.getIccFileHandler().getEFLinearRecordSize(efid, response);
-            waitForResult(status);
+            IccFileHandler fh = phone.getIccFileHandler();
+            //IccFileHandler can be null if there is no icc card present.
+            if (fh != null) {
+                fh.getEFLinearRecordSize(efid, response);
+                waitForResult(status);
+            }
         }
 
         return recordSize;
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
index 2fefa3f..80183c6 100755
--- a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
@@ -199,7 +199,7 @@
 
         boolean isRecordLoadResponse = false;
 
-        if (mDestroyed) {
+        if (mDestroyed.get()) {
             loge("Received message " + msg +
                     "[" + msg.what + "] while being destroyed. Ignoring.");
             return;
@@ -317,18 +317,20 @@
         // One record loaded successfully or failed, In either case
         // we need to update the recordsToLoad count
         recordsToLoad -= 1;
-        if (DBG) log("RuimRecords:onRecordLoaded " + recordsToLoad + " requested: " + recordsRequested);
+        if (DBG) log("onRecordLoaded " + recordsToLoad + " requested: " + recordsRequested);
 
         if (recordsToLoad == 0 && recordsRequested == true) {
             onAllRecordsLoaded();
         } else if (recordsToLoad < 0) {
-            loge("RuimRecords: recordsToLoad <0, programmer error suspected");
+            loge("recordsToLoad <0, programmer error suspected");
             recordsToLoad = 0;
         }
     }
 
     @Override
     protected void onAllRecordsLoaded() {
+        if (DBG) log("record load complete");
+
         // Further records that can be inserted are Operator/OEM dependent
 
         String operator = getRUIMOperatorNumeric();
@@ -348,13 +350,6 @@
 
     @Override
     public void onReady() {
-        /* broadcast intent ICC_READY here so that we can make sure
-          READY is sent before IMSI ready
-        */
-
-        mParentCard.broadcastIccStateChangedIntent(
-                IccCard.INTENT_VALUE_ICC_READY, null);
-
         fetchRuimRecords();
 
         mCi.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE));
@@ -364,7 +359,7 @@
     private void fetchRuimRecords() {
         recordsRequested = true;
 
-        Log.v(LOG_TAG, "RuimRecords:fetchRuimRecords " + recordsToLoad);
+        if (DBG) log("fetchRuimRecords " + recordsToLoad);
 
         mCi.getIMSI(obtainMessage(EVENT_GET_IMSI_DONE));
         recordsToLoad++;
@@ -373,7 +368,7 @@
                 obtainMessage(EVENT_GET_ICCID_DONE));
         recordsToLoad++;
 
-        log("RuimRecords:fetchRuimRecords " + recordsToLoad + " requested: " + recordsRequested);
+        if (DBG) log("fetchRuimRecords " + recordsToLoad + " requested: " + recordsRequested);
         // Further records that can be inserted are Operator/OEM dependent
     }
 
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index 6e9cd51..8dda74b 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -59,6 +59,7 @@
 import com.android.internal.telephony.IccCard;
 import com.android.internal.telephony.IccFileHandler;
 import com.android.internal.telephony.IccPhoneBookInterfaceManager;
+import com.android.internal.telephony.IccRecords;
 import com.android.internal.telephony.IccSmsInterfaceManager;
 import com.android.internal.telephony.MmiCode;
 import com.android.internal.telephony.OperatorInfo;
@@ -137,13 +138,11 @@
         if (ci instanceof SimulatedRadioControl) {
             mSimulatedRadioControl = (SimulatedRadioControl) ci;
         }
-
         mCM.setPhoneType(Phone.PHONE_TYPE_GSM);
-        mIccCard.set(UiccController.getInstance(this).getIccCard());
-        mIccRecords = mIccCard.get().getIccRecords();
         mCT = new GsmCallTracker(this);
         mSST = new GsmServiceStateTracker (this);
         mSMS = new GsmSMSDispatcher(this, mSmsStorageMonitor, mSmsUsageMonitor);
+
         mDataConnectionTracker = new GsmDataConnectionTracker (this);
         if (!unitTestMode) {
             mSimPhoneBookIntManager = new SimPhoneBookInterfaceManager(this);
@@ -152,7 +151,6 @@
         }
 
         mCM.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
-        registerForSimRecordEvents();
         mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
         mCM.registerForOn(this, EVENT_RADIO_ON, null);
         mCM.setOnUSSD(this, EVENT_USSD, null);
@@ -796,7 +794,8 @@
 
     public String getVoiceMailNumber() {
         // Read from the SIM. If its null, try reading from the shared preference area.
-        String number = mIccRecords.getVoiceMailNumber();
+        IccRecords r = mIccRecords.get();
+        String number = (r != null) ? r.getVoiceMailNumber() : "";
         if (TextUtils.isEmpty(number)) {
             SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
             number = sp.getString(VM_NUMBER, null);
@@ -818,8 +817,9 @@
 
     public String getVoiceMailAlphaTag() {
         String ret;
+        IccRecords r = mIccRecords.get();
 
-        ret = mIccRecords.getVoiceMailAlphaTag();
+        ret = (r != null) ? r.getVoiceMailAlphaTag() : "";
 
         if (ret == null || ret.length() == 0) {
             return mContext.getText(
@@ -852,24 +852,31 @@
     }
 
     public String getSubscriberId() {
-        return mIccRecords.getIMSI();
+        IccRecords r = mIccRecords.get();
+        return (r != null) ? r.getIMSI() : "";
     }
 
     public String getLine1Number() {
-        return mIccRecords.getMsisdnNumber();
+        IccRecords r = mIccRecords.get();
+        return (r != null) ? r.getMsisdnNumber() : "";
     }
 
     @Override
     public String getMsisdn() {
-        return mIccRecords.getMsisdnNumber();
+        IccRecords r = mIccRecords.get();
+        return (r != null) ? r.getMsisdnNumber() : "";
     }
 
     public String getLine1AlphaTag() {
-        return mIccRecords.getMsisdnAlphaTag();
+        IccRecords r = mIccRecords.get();
+        return (r != null) ? r.getMsisdnAlphaTag() : "";
     }
 
     public void setLine1Number(String alphaTag, String number, Message onComplete) {
-        mIccRecords.setMsisdnNumber(alphaTag, number, onComplete);
+        IccRecords r = mIccRecords.get();
+        if (r != null) {
+            r.setMsisdnNumber(alphaTag, number, onComplete);
+        }
     }
 
     public void setVoiceMailNumber(String alphaTag,
@@ -879,7 +886,10 @@
         Message resp;
         mVmNumber = voiceMailNumber;
         resp = obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete);
-        mIccRecords.setVoiceMailNumber(alphaTag, mVmNumber, resp);
+        IccRecords r = mIccRecords.get();
+        if (r != null) {
+            r.setVoiceMailNumber(alphaTag, mVmNumber, resp);
+        }
     }
 
     private boolean isValidCommandInterfaceCFReason (int commandInterfaceCFReason) {
@@ -1247,8 +1257,9 @@
 
             case EVENT_SET_CALL_FORWARD_DONE:
                 ar = (AsyncResult)msg.obj;
-                if (ar.exception == null) {
-                    mIccRecords.setVoiceCallForwardingFlag(1, msg.arg1 == 1);
+                IccRecords r = mIccRecords.get();
+                if (ar.exception == null && r != null) {
+                    r.setVoiceCallForwardingFlag(1, msg.arg1 == 1);
                 }
                 onComplete = (Message) ar.userObj;
                 if (onComplete != null) {
@@ -1321,12 +1332,41 @@
         }
     }
 
+    @Override
+    protected void onUpdateIccAvailability() {
+        if (mUiccController == null ) {
+            return;
+        }
+
+        IccCard newIccCard = mUiccController.getIccCard();
+
+        IccCard c = mIccCard.get();
+        if (c != newIccCard) {
+            if (c != null) {
+                if (LOCAL_DEBUG) log("Removing stale icc objects.");
+                if (mIccRecords.get() != null) {
+                    unregisterForSimRecordEvents();
+                    mSimPhoneBookIntManager.updateIccRecords(null);
+                }
+                mIccRecords.set(null);
+                mIccCard.set(null);
+            }
+            if (newIccCard != null) {
+                if (LOCAL_DEBUG) log("New card found");
+                mIccCard.set(newIccCard);
+                mIccRecords.set(newIccCard.getIccRecords());
+                registerForSimRecordEvents();
+                mSimPhoneBookIntManager.updateIccRecords(mIccRecords.get());
+            }
+        }
+    }
+
     private void processIccRecordEvents(int eventCode) {
         switch (eventCode) {
-            case SIMRecords.EVENT_CFI:
+            case IccRecords.EVENT_CFI:
                 notifyCallForwardingIndicator();
                 break;
-            case SIMRecords.EVENT_MWI:
+            case IccRecords.EVENT_MWI:
                 notifyMessageWaitingIndicator();
                 break;
         }
@@ -1338,11 +1378,12 @@
      * @return true for success; false otherwise.
      */
     boolean updateCurrentCarrierInProvider() {
-        if (mIccRecords != null) {
+        IccRecords r = mIccRecords.get();
+        if (r != null) {
             try {
                 Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current");
                 ContentValues map = new ContentValues();
-                map.put(Telephony.Carriers.NUMERIC, mIccRecords.getOperatorNumeric());
+                map.put(Telephony.Carriers.NUMERIC, r.getOperatorNumeric());
                 mContext.getContentResolver().insert(uri, map);
                 return true;
             } catch (SQLException e) {
@@ -1404,16 +1445,19 @@
     }
 
     private void handleCfuQueryResult(CallForwardInfo[] infos) {
-        if (infos == null || infos.length == 0) {
-            // Assume the default is not active
-            // Set unconditional CFF in SIM to false
-            mIccRecords.setVoiceCallForwardingFlag(1, false);
-        } else {
-            for (int i = 0, s = infos.length; i < s; i++) {
-                if ((infos[i].serviceClass & SERVICE_CLASS_VOICE) != 0) {
-                    mIccRecords.setVoiceCallForwardingFlag(1, (infos[i].status == 1));
-                    // should only have the one
-                    break;
+        IccRecords r = mIccRecords.get();
+        if (r != null) {
+            if (infos == null || infos.length == 0) {
+                // Assume the default is not active
+                // Set unconditional CFF in SIM to false
+                r.setVoiceCallForwardingFlag(1, false);
+            } else {
+                for (int i = 0, s = infos.length; i < s; i++) {
+                    if ((infos[i].serviceClass & SERVICE_CLASS_VOICE) != 0) {
+                        r.setVoiceCallForwardingFlag(1, (infos[i].status == 1));
+                        // should only have the one
+                        break;
+                    }
                 }
             }
         }
@@ -1472,22 +1516,35 @@
     }
 
     public boolean isCspPlmnEnabled() {
-        return mIccRecords.isCspPlmnEnabled();
+        IccRecords r = mIccRecords.get();
+        return (r != null) ? r.isCspPlmnEnabled() : false;
     }
 
     private void registerForSimRecordEvents() {
-        mIccRecords.registerForNetworkSelectionModeAutomatic(
+        IccRecords r = mIccRecords.get();
+        if (r == null) {
+            return;
+        }
+        r.registerForNetworkSelectionModeAutomatic(
                 this, EVENT_SET_NETWORK_AUTOMATIC, null);
-        mIccRecords.registerForNewSms(this, EVENT_NEW_ICC_SMS, null);
-        mIccRecords.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
-        mIccRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
+        r.registerForNewSms(this, EVENT_NEW_ICC_SMS, null);
+        r.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
+        r.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
     }
 
     private void unregisterForSimRecordEvents() {
-        mIccRecords.unregisterForNetworkSelectionModeAutomatic(this);
-        mIccRecords.unregisterForNewSms(this);
-        mIccRecords.unregisterForRecordsEvents(this);
-        mIccRecords.unregisterForRecordsLoaded(this);
+        IccRecords r = mIccRecords.get();
+        if (r == null) {
+            return;
+        }
+        r.unregisterForNetworkSelectionModeAutomatic(this);
+        r.unregisterForNewSms(this);
+        r.unregisterForRecordsEvents(this);
+        r.unregisterForRecordsLoaded(this);
+    }
+
+    protected void log(String s) {
+            Log.d(LOG_TAG, "[GSMPhone] " + s);
     }
 
     @Override
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 40ee58c..b44ba0b 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -59,6 +59,8 @@
 import com.android.internal.telephony.DataConnectionAc;
 import com.android.internal.telephony.DataConnectionTracker;
 import com.android.internal.telephony.EventLogTags;
+import com.android.internal.telephony.IccCard;
+import com.android.internal.telephony.IccRecords;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneBase;
 import com.android.internal.telephony.RILConstants;
@@ -178,7 +180,6 @@
 
         p.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null);
         p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
-        p.mIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
         p.mCM.registerForDataNetworkStateChanged (this, EVENT_DATA_STATE_CHANGED, null);
         p.getCallTracker().registerForVoiceCallEnded (this, EVENT_VOICE_CALL_ENDED, null);
         p.getCallTracker().registerForVoiceCallStarted (this, EVENT_VOICE_CALL_STARTED, null);
@@ -219,7 +220,8 @@
         //Unregister for all events
         mPhone.mCM.unregisterForAvailable(this);
         mPhone.mCM.unregisterForOffOrNotAvailable(this);
-        mPhone.mIccRecords.unregisterForRecordsLoaded(this);
+        IccRecords r = mIccRecords.get();
+        if (r != null) { r.unregisterForRecordsLoaded(this);}
         mPhone.mCM.unregisterForDataNetworkStateChanged(this);
         mPhone.getCallTracker().unregisterForVoiceCallEnded(this);
         mPhone.getCallTracker().unregisterForVoiceCallStarted(this);
@@ -620,10 +622,12 @@
 
         int gprsState = mPhone.getServiceStateTracker().getCurrentDataConnectionState();
         boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState();
+        IccRecords r = mIccRecords.get();
+        boolean recordsLoaded = (r != null) ? r.getRecordsLoaded() : false;
 
         boolean allowed =
                     (gprsState == ServiceState.STATE_IN_SERVICE || mAutoAttachOnCreation) &&
-                    mPhone.mIccRecords.getRecordsLoaded() &&
+                    recordsLoaded &&
                     (mPhone.getState() == Phone.State.IDLE ||
                      mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) &&
                     internalDataEnabled &&
@@ -635,7 +639,7 @@
             if (!((gprsState == ServiceState.STATE_IN_SERVICE) || mAutoAttachOnCreation)) {
                 reason += " - gprs= " + gprsState;
             }
-            if (!mPhone.mIccRecords.getRecordsLoaded()) reason += " - SIM not loaded";
+            if (!recordsLoaded) reason += " - SIM not loaded";
             if (mPhone.getState() != Phone.State.IDLE &&
                     !mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
                 reason += " - PhoneState= " + mPhone.getState();
@@ -1896,7 +1900,8 @@
             log("onRadioAvailable: We're on the simulator; assuming data is connected");
         }
 
-        if (mPhone.mIccRecords.getRecordsLoaded()) {
+        IccRecords r = mIccRecords.get();
+        if (r != null && r.getRecordsLoaded()) {
             notifyOffApnsOfAvailability(null);
         }
 
@@ -2208,7 +2213,8 @@
      */
     private void createAllApnList() {
         mAllApns = new ArrayList<ApnSetting>();
-        String operator = mPhone.mIccRecords.getOperatorNumeric();
+        IccRecords r = mIccRecords.get();
+        String operator = (r != null) ? r.getOperatorNumeric() : "";
         if (operator != null) {
             String selection = "numeric = '" + operator + "'";
             // query only enabled apn.
@@ -2319,8 +2325,9 @@
             }
         }
 
-        String operator = mPhone.mIccRecords.getOperatorNumeric();
-        int networkType = mPhone.getServiceState().getNetworkType();
+        IccRecords r = mIccRecords.get();
+        String operator = (r != null) ? r.getOperatorNumeric() : "";
+        int radioTech = mPhone.getServiceState().getRadioTechnology();
 
         if (requestedApnType.equals(Phone.APN_TYPE_DEFAULT)) {
             if (canSetPreferApn && mPreferredApn != null) {
@@ -2329,7 +2336,7 @@
                         + mPreferredApn.numeric + ":" + mPreferredApn);
                 }
                 if (mPreferredApn.numeric.equals(operator)) {
-                    if (mPreferredApn.bearer == 0 || mPreferredApn.bearer == networkType) {
+                    if (mPreferredApn.bearer == 0 || mPreferredApn.bearer == radioTech) {
                         apnList.add(mPreferredApn);
                         if (DBG) log("buildWaitingApns: X added preferred apnList=" + apnList);
                         return apnList;
@@ -2348,7 +2355,7 @@
         if (mAllApns != null) {
             for (ApnSetting apn : mAllApns) {
                 if (apn.canHandleType(requestedApnType)) {
-                    if (apn.bearer == 0 || apn.bearer == networkType) {
+                    if (apn.bearer == 0 || apn.bearer == radioTech) {
                         if (DBG) log("apn info : " +apn.toString());
                         apnList.add(apn);
                     }
@@ -2556,6 +2563,33 @@
     }
 
     @Override
+    protected void onUpdateIcc() {
+        if (mUiccController == null ) {
+            return;
+        }
+
+        IccCard newIccCard = mUiccController.getIccCard();
+        IccRecords newIccRecords = null;
+        if (newIccCard != null) {
+            newIccRecords = newIccCard.getIccRecords();
+        }
+
+        IccRecords r = mIccRecords.get();
+        if (r != newIccRecords) {
+            if (r != null) {
+                log("Removing stale icc objects.");
+                r.unregisterForRecordsLoaded(this);
+                mIccRecords.set(null);
+            }
+            if (newIccCard != null) {
+                log("New card found");
+                mIccRecords.set(newIccRecords);
+                newIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
+            }
+        }
+    }
+
+    @Override
     protected void log(String s) {
         Log.d(LOG_TAG, "[GsmDCT] "+ s);
     }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
index 9b3d5cd..9e34b6a 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
@@ -885,7 +885,10 @@
                 */
                 if ((ar.exception == null) && (msg.arg1 == 1)) {
                     boolean cffEnabled = (msg.arg2 == 1);
-                    phone.mIccRecords.setVoiceCallForwardingFlag(1, cffEnabled);
+                    IccRecords r = phone.mIccRecords.get();
+                    if (r != null) {
+                        r.setVoiceCallForwardingFlag(1, cffEnabled);
+                    }
                 }
 
                 onSetComplete(ar);
@@ -1203,7 +1206,10 @@
                 (info.serviceClass & serviceClassMask)
                         == CommandsInterface.SERVICE_CLASS_VOICE) {
             boolean cffEnabled = (info.status == 1);
-            phone.mIccRecords.setVoiceCallForwardingFlag(1, cffEnabled);
+            IccRecords r = phone.mIccRecords.get();
+            if (r != null) {
+                r.setVoiceCallForwardingFlag(1, cffEnabled);
+            }
         }
 
         return TextUtils.replace(template, sources, destinations);
@@ -1228,7 +1234,10 @@
                 sb.append(context.getText(com.android.internal.R.string.serviceDisabled));
 
                 // Set unconditional CFF in SIM to false
-                phone.mIccRecords.setVoiceCallForwardingFlag(1, false);
+                IccRecords r = phone.mIccRecords.get();
+                if (r != null) {
+                    r.setVoiceCallForwardingFlag(1, false);
+                }
             } else {
 
                 SpannableStringBuilder tb = new SpannableStringBuilder();
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index c0acf5b..7c03d03 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -124,12 +124,6 @@
     long mSavedTime;
     long mSavedAtTime;
 
-    /**
-     * We can't register for SIM_RECORDS_LOADED immediately because the
-     * SIMRecords object may not be instantiated yet.
-     */
-    private boolean mNeedToRegForSimLoaded;
-
     /** Started the recheck process after finding gprs should registered but not. */
     private boolean mStartedGprsRegCheck = false;
 
@@ -192,10 +186,9 @@
     };
 
     public GsmServiceStateTracker(GSMPhone phone) {
-        super();
+        super(phone, phone.mCM);
 
         this.phone = phone;
-        cm = phone.mCM;
         ss = new ServiceState();
         newSS = new ServiceState();
         cellLoc = new GsmCellLocation();
@@ -213,7 +206,6 @@
         cm.setOnNITZTime(this, EVENT_NITZ_TIME, null);
         cm.setOnSignalStrengthUpdate(this, EVENT_SIGNAL_STRENGTH_UPDATE, null);
         cm.setOnRestrictedStateChanged(this, EVENT_RESTRICTED_STATE_CHANGED, null);
-        phone.getIccCard().registerForReady(this, EVENT_SIM_READY, null);
 
         // system setting property AIRPLANE_MODE_ON is set in Settings.
         int airplaneMode = Settings.System.getInt(
@@ -230,7 +222,6 @@
                 mAutoTimeZoneObserver);
 
         setSignalStrengthDefaultValues();
-        mNeedToRegForSimLoaded = true;
 
         // Monitor locale change
         IntentFilter filter = new IntentFilter();
@@ -242,12 +233,13 @@
     }
 
     public void dispose() {
+        checkCorrectThread();
         // Unregister for all events.
         cm.unregisterForAvailable(this);
         cm.unregisterForRadioStateChanged(this);
         cm.unregisterForVoiceNetworkStateChanged(this);
-        phone.getIccCard().unregisterForReady(this);
-        phone.mIccRecords.unregisterForRecordsLoaded(this);
+        if (mIccCard != null) {mIccCard.unregisterForReady(this);}
+        if (mIccRecords != null) {mIccRecords.unregisterForRecordsLoaded(this);}
         cm.unSetOnSignalStrengthUpdate(this);
         cm.unSetOnRestrictedStateChanged(this);
         cm.unSetOnNITZTime(this);
@@ -285,15 +277,6 @@
                 // Set the network type, in case the radio does not restore it.
                 cm.setCurrentPreferredNetworkType();
 
-                // The SIM is now ready i.e if it was locked
-                // it has been unlocked. At this stage, the radio is already
-                // powered on.
-                if (mNeedToRegForSimLoaded) {
-                    phone.mIccRecords.registerForRecordsLoaded(this,
-                            EVENT_SIM_RECORDS_LOADED, null);
-                    mNeedToRegForSimLoaded = false;
-                }
-
                 boolean skipRestoringSelection = phone.getContext().getResources().getBoolean(
                         com.android.internal.R.bool.skip_restoring_network_selection);
 
@@ -495,8 +478,11 @@
     }
 
     protected void updateSpnDisplay() {
-        int rule = phone.mIccRecords.getDisplayRule(ss.getOperatorNumeric());
-        String spn = phone.mIccRecords.getServiceProviderName();
+        if (mIccRecords == null) {
+            return;
+        }
+        int rule = mIccRecords.getDisplayRule(ss.getOperatorNumeric());
+        String spn = mIccRecords.getServiceProviderName();
         String plmn = ss.getOperatorAlphaLong();
 
         // For emergency calls only, pass the EmergencyCallsOnly string via EXTRA_PLMN
@@ -1145,7 +1131,7 @@
                     ((state & RILConstants.RIL_RESTRICTED_STATE_CS_EMERGENCY) != 0) ||
                     ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) );
             //ignore the normal call and data restricted state before SIM READY
-            if (phone.getIccCard().getState() == IccCard.State.READY) {
+            if (mIccCard.getState() == IccCard.State.READY) {
                 newRs.setCsNormalRestricted(
                         ((state & RILConstants.RIL_RESTRICTED_STATE_CS_NORMAL) != 0) ||
                         ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) );
@@ -1672,6 +1658,35 @@
     }
 
     @Override
+    protected void onUpdateIccAvailability() {
+        if (mUiccController == null ) {
+            return;
+        }
+
+        IccCard newIccCard = mUiccController.getIccCard();
+
+        if (mIccCard != newIccCard) {
+            if (mIccCard != null) {
+                log("Removing stale icc objects.");
+                mIccCard.unregisterForReady(this);
+                if (mIccRecords != null) {
+                    mIccRecords.unregisterForRecordsLoaded(this);
+                }
+                mIccRecords = null;
+                mIccCard = null;
+            }
+            if (newIccCard != null) {
+                log("New card found");
+                mIccCard = newIccCard;
+                mIccRecords = mIccCard.getIccRecords();
+                mIccCard.registerForReady(this, EVENT_SIM_READY, null);
+                if (mIccRecords != null) {
+                    mIccRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
+                }
+            }
+        }
+    }
+    @Override
     protected void log(String s) {
         Log.d(LOG_TAG, "[GsmSST] " + s);
     }
@@ -1711,7 +1726,6 @@
         pw.println(" mSavedTimeZone=" + mSavedTimeZone);
         pw.println(" mSavedTime=" + mSavedTime);
         pw.println(" mSavedAtTime=" + mSavedAtTime);
-        pw.println(" mNeedToRegForSimLoaded=" + mNeedToRegForSimLoaded);
         pw.println(" mStartedGprsRegCheck=" + mStartedGprsRegCheck);
         pw.println(" mReportedGprsNoReg=" + mReportedGprsNoReg);
         pw.println(" mNotification=" + mNotification);
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
index 80988fd..3077995 100755
--- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
@@ -521,7 +521,7 @@
 
         boolean isRecordLoadResponse = false;
 
-        if (mDestroyed) {
+        if (mDestroyed.get()) {
             loge("Received message " + msg + "[" + msg.what + "] " +
                     " while being destroyed. Ignoring.");
             return;
@@ -1299,12 +1299,6 @@
 
     @Override
     public void onReady() {
-        /* broadcast intent SIM_READY here so that we can make sure
-          READY is sent before IMSI ready
-        */
-        mParentCard.broadcastIccStateChangedIntent(
-                IccCard.INTENT_VALUE_ICC_READY, null);
-
         fetchSimRecords();
     }
 
diff --git a/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java
index 35ba0d1..37f9a4f 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java
@@ -21,6 +21,7 @@
 import android.os.Message;
 import android.util.Log;
 
+import com.android.internal.telephony.IccFileHandler;
 import com.android.internal.telephony.IccPhoneBookInterfaceManager;
 
 /**
@@ -34,7 +35,6 @@
 
     public SimPhoneBookInterfaceManager(GSMPhone phone) {
         super(phone);
-        adnCache = phone.mIccRecords.getAdnCache();
         //NOTE service "simphonebook" added by IccSmsInterfaceManagerProxy
     }
 
@@ -61,8 +61,11 @@
             AtomicBoolean status = new AtomicBoolean(false);
             Message response = mBaseHandler.obtainMessage(EVENT_GET_SIZE_DONE, status);
 
-            phone.getIccFileHandler().getEFLinearRecordSize(efid, response);
-            waitForResult(status);
+            IccFileHandler fh = phone.getIccFileHandler();
+            if (fh != null) {
+                fh.getEFLinearRecordSize(efid, response);
+                waitForResult(status);
+            }
         }
 
         return recordSize;
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
index 5c4b446..0243522 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
@@ -461,4 +461,8 @@
             notifyPhoneStateChanged();
         }
     }
+
+    @Override
+    protected void onUpdateIccAvailability() {
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/uicc/UiccController.java b/telephony/java/com/android/internal/telephony/uicc/UiccController.java
index 5961efd..4e12d6d 100644
--- a/telephony/java/com/android/internal/telephony/uicc/UiccController.java
+++ b/telephony/java/com/android/internal/telephony/uicc/UiccController.java
@@ -16,78 +16,150 @@
 
 package com.android.internal.telephony.uicc;
 
+import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.IccCard;
+import com.android.internal.telephony.IccCardStatus;
+import com.android.internal.telephony.IccCardStatus.CardState;
 import com.android.internal.telephony.PhoneBase;
-import com.android.internal.telephony.cdma.CDMALTEPhone;
-import com.android.internal.telephony.cdma.CDMAPhone;
-import com.android.internal.telephony.gsm.GSMPhone;
 
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Registrant;
+import android.os.RegistrantList;
 import android.util.Log;
 
 /* This class is responsible for keeping all knowledge about
  * ICCs in the system. It is also used as API to get appropriate
  * applications to pass them to phone and service trackers.
  */
-public class UiccController {
+public class UiccController extends Handler {
     private static final boolean DBG = true;
     private static final String LOG_TAG = "RIL_UiccController";
 
+    private static final int EVENT_ICC_STATUS_CHANGED = 1;
+    private static final int EVENT_GET_ICC_STATUS_DONE = 2;
+
     private static UiccController mInstance;
 
     private PhoneBase mCurrentPhone;
-    private boolean mIsCurrentCard3gpp;
+    private CommandsInterface mCi;
     private IccCard mIccCard;
+    private boolean mRegisteredWithCi = false;
+
+    private RegistrantList mIccChangedRegistrants = new RegistrantList();
 
     public static synchronized UiccController getInstance(PhoneBase phone) {
         if (mInstance == null) {
             mInstance = new UiccController(phone);
-        } else {
+        } else if (phone != null) {
             mInstance.setNewPhone(phone);
         }
         return mInstance;
     }
 
-    public IccCard getIccCard() {
+    // This method is not synchronized as getInstance(PhoneBase) is.
+    public static UiccController getInstance() {
+        return getInstance(null);
+    }
+
+    public synchronized IccCard getIccCard() {
         return mIccCard;
     }
 
+    //Notifies when card status changes
+    public void registerForIccChanged(Handler h, int what, Object obj) {
+        Registrant r = new Registrant (h, what, obj);
+        mIccChangedRegistrants.add(r);
+        //Notify registrant right after registering, so that it will get the latest ICC status,
+        //otherwise which may not happen until there is an actual change in ICC status.
+        r.notifyRegistrant();
+    }
+    public void unregisterForIccChanged(Handler h) {
+        mIccChangedRegistrants.remove(h);
+    }
+
+    @Override
+    public void handleMessage (Message msg) {
+        switch (msg.what) {
+            case EVENT_ICC_STATUS_CHANGED:
+                if (DBG) log("Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus");
+                mCi.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE));
+                break;
+            case EVENT_GET_ICC_STATUS_DONE:
+                if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE");
+                AsyncResult ar = (AsyncResult)msg.obj;
+                onGetIccCardStatusDone(ar);
+                break;
+            default:
+                Log.e(LOG_TAG, " Unknown Event " + msg.what);
+        }
+    }
+
     private UiccController(PhoneBase phone) {
         if (DBG) log("Creating UiccController");
         setNewPhone(phone);
     }
 
-    private void setNewPhone(PhoneBase phone) {
-        mCurrentPhone = phone;
-        if (phone instanceof GSMPhone) {
-            if (DBG) log("New phone is GSMPhone");
-            updateCurrentCard(IccCard.CARD_IS_3GPP);
-        } else if (phone instanceof CDMALTEPhone){
-            if (DBG) log("New phone type is CDMALTEPhone");
-            updateCurrentCard(IccCard.CARD_IS_3GPP);
-        } else if (phone instanceof CDMAPhone){
-            if (DBG) log("New phone type is CDMAPhone");
-            updateCurrentCard(IccCard.CARD_IS_NOT_3GPP);
-        } else {
-            Log.e(LOG_TAG, "Unhandled phone type. Critical error!");
-        }
-    }
-
-    private void updateCurrentCard(boolean isNewCard3gpp) {
-        if (mIsCurrentCard3gpp == isNewCard3gpp && mIccCard != null) {
+    private synchronized void onGetIccCardStatusDone(AsyncResult ar) {
+        if (ar.exception != null) {
+            Log.e(LOG_TAG,"Error getting ICC status. "
+                    + "RIL_REQUEST_GET_ICC_STATUS should "
+                    + "never return an error", ar.exception);
             return;
         }
 
-        if (mIccCard != null) {
+        IccCardStatus status = (IccCardStatus)ar.result;
+
+        //Update already existing card
+        if (mIccCard != null && status.getCardState() == CardState.CARDSTATE_PRESENT) {
+            mIccCard.update(mCurrentPhone, status);
+        }
+
+        //Dispose of removed card
+        if (mIccCard != null && status.getCardState() != CardState.CARDSTATE_PRESENT) {
             mIccCard.dispose();
             mIccCard = null;
         }
 
-        mIsCurrentCard3gpp = isNewCard3gpp;
-        mIccCard = new IccCard(mCurrentPhone, mCurrentPhone.getPhoneName(),
-                isNewCard3gpp, DBG);
+        //Create new card
+        if (mIccCard == null && status.getCardState() == CardState.CARDSTATE_PRESENT) {
+            mIccCard = new IccCard(mCurrentPhone, status, mCurrentPhone.getPhoneName(), true);
+        }
+
+        if (DBG) log("Notifying IccChangedRegistrants");
+        mIccChangedRegistrants.notifyRegistrants();
+    }
+
+    private void setNewPhone(PhoneBase phone) {
+        if (phone == null) {
+            throw new RuntimeException("Phone can't be null in UiccController");
+        }
+
+        if (DBG) log("setNewPhone");
+        if (mCurrentPhone != phone) {
+            if (mIccCard != null) {
+                // Refresh card if phone changed
+                // TODO: Remove once card is simplified
+                if (DBG) log("Disposing card since phone object changed");
+                mIccCard.dispose();
+                mIccCard = null;
+            }
+            sendMessage(obtainMessage(EVENT_ICC_STATUS_CHANGED));
+            mCurrentPhone = phone;
+
+            if (!mRegisteredWithCi) {
+                // This needs to be done only once after we have valid phone object
+                mCi = mCurrentPhone.mCM;
+                mCi.registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, null);
+                // TODO remove this once modem correctly notifies the unsols
+                mCi.registerForOn(this, EVENT_ICC_STATUS_CHANGED, null);
+                mRegisteredWithCi = true;
+            }
+        }
     }
 
     private void log(String string) {
         Log.d(LOG_TAG, string);
     }
-}
\ No newline at end of file
+}
diff --git a/tests/GridLayoutTest/AndroidManifest.xml b/tests/GridLayoutTest/AndroidManifest.xml
index 141e8fa..677220d 100644
--- a/tests/GridLayoutTest/AndroidManifest.xml
+++ b/tests/GridLayoutTest/AndroidManifest.xml
@@ -83,6 +83,13 @@
                 <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
+
+        <activity android:name="LayoutInsetsTest" android:label="LayoutInsetsTest">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
     </application>
 
 
diff --git a/tests/GridLayoutTest/res/drawable/btn_default.xml b/tests/GridLayoutTest/res/drawable/btn_default.xml
new file mode 100644
index 0000000..c6cfda0
--- /dev/null
+++ b/tests/GridLayoutTest/res/drawable/btn_default.xml
@@ -0,0 +1,33 @@
+<?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/my_btn_default_normal" />
+    <item android:state_window_focused="false" android:state_enabled="false"
+        android:drawable="@drawable/my_btn_default_normal" />
+    <item android:state_pressed="true" 
+        android:drawable="@drawable/my_btn_default_pressed" />
+    <item android:state_focused="true" android:state_enabled="true"
+        android:drawable="@drawable/my_btn_default_selected" />
+    <item android:state_enabled="true"
+        android:drawable="@drawable/my_btn_default_normal" />
+    <item android:state_focused="true"
+        android:drawable="@drawable/my_btn_default_normal_disable_focused" />
+    <item
+         android:drawable="@drawable/my_btn_default_normal_disable" />
+</selector>
diff --git a/tests/GridLayoutTest/res/drawable/my_btn_default_normal.9.png b/tests/GridLayoutTest/res/drawable/my_btn_default_normal.9.png
new file mode 100644
index 0000000..cd0b7d5
--- /dev/null
+++ b/tests/GridLayoutTest/res/drawable/my_btn_default_normal.9.png
Binary files differ
diff --git a/tests/GridLayoutTest/res/drawable/my_btn_default_normal_disable.9.png b/tests/GridLayoutTest/res/drawable/my_btn_default_normal_disable.9.png
new file mode 100755
index 0000000..f4f01c7
--- /dev/null
+++ b/tests/GridLayoutTest/res/drawable/my_btn_default_normal_disable.9.png
Binary files differ
diff --git a/tests/GridLayoutTest/res/drawable/my_btn_default_normal_disable_focused.9.png b/tests/GridLayoutTest/res/drawable/my_btn_default_normal_disable_focused.9.png
new file mode 100755
index 0000000..5376db2
--- /dev/null
+++ b/tests/GridLayoutTest/res/drawable/my_btn_default_normal_disable_focused.9.png
Binary files differ
diff --git a/tests/GridLayoutTest/res/drawable/my_btn_default_pressed.9.png b/tests/GridLayoutTest/res/drawable/my_btn_default_pressed.9.png
new file mode 100755
index 0000000..4312c27
--- /dev/null
+++ b/tests/GridLayoutTest/res/drawable/my_btn_default_pressed.9.png
Binary files differ
diff --git a/tests/GridLayoutTest/res/drawable/my_btn_default_selected.9.png b/tests/GridLayoutTest/res/drawable/my_btn_default_selected.9.png
new file mode 100755
index 0000000..06b7790
--- /dev/null
+++ b/tests/GridLayoutTest/res/drawable/my_btn_default_selected.9.png
Binary files differ
diff --git a/tests/GridLayoutTest/res/layout/grid7.xml b/tests/GridLayoutTest/res/layout/grid7.xml
index b9e58d7..0e5be0c 100644
--- a/tests/GridLayoutTest/res/layout/grid7.xml
+++ b/tests/GridLayoutTest/res/layout/grid7.xml
@@ -17,7 +17,7 @@
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:layout_width="match_parent"
         android:layout_height="match_parent">
-    android:columnCount="2"
+
     <Space
             android:layout_row="0"
             android:layout_column="0"
diff --git a/tests/GridLayoutTest/src/com/android/test/layout/LayoutInsetsTest.java b/tests/GridLayoutTest/src/com/android/test/layout/LayoutInsetsTest.java
new file mode 100644
index 0000000..74daccc
--- /dev/null
+++ b/tests/GridLayoutTest/src/com/android/test/layout/LayoutInsetsTest.java
@@ -0,0 +1,59 @@
+package com.android.test.layout;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.GridLayout;
+import android.widget.Space;
+import android.widget.TextView;
+
+import static android.text.InputType.TYPE_CLASS_TEXT;
+import static android.text.InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
+import static android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD;
+import static android.widget.GridLayout.*;
+import static android.widget.GridLayout.FILL;
+import static android.widget.GridLayout.spec;
+
+public class LayoutInsetsTest extends Activity {
+    public static View create(Context context) {
+        GridLayout p = new GridLayout(context);
+        p.setUseDefaultMargins(true);
+        p.setAlignmentMode(ALIGN_BOUNDS);
+        p.setOrientation(VERTICAL);
+
+        {
+            TextView c = new TextView(context);
+            c.setTextSize(32);
+            c.setText("Email setup");
+            p.addView(c);
+        }
+        {
+            Button c = new Button(context);
+            c.setBackgroundResource(R.drawable.btn_default);
+            c.setText("Manual setup");
+            p.addView(c);
+            c.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    Button b = (Button) v;
+                    b.setEnabled(false);
+                }
+            });
+        }
+
+        return p;
+    }
+
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        //getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.ICE_CREAM_SANDWICH;
+        getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.JELLY_BEAN;
+        setContentView(create(this));
+    }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/element.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/element.rs
index 0c42d84..419ce07 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/element.rs
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/element.rs
@@ -101,7 +101,7 @@
     _RS_ASSERT(rsElementGetDataKind(complexElem) == RS_KIND_USER);
     _RS_ASSERT(rsElementGetDataType(complexElem) == RS_TYPE_NONE);
     _RS_ASSERT(rsElementGetVectorSize(complexElem) == 1);
-    _RS_ASSERT(rsElementGetSizeBytes(complexElem) == sizeof(*complexStruct));
+    _RS_ASSERT(rsElementGetBytesSize(complexElem) == sizeof(*complexStruct));
 
     char buffer[64];
     for (uint32_t i = 0; i < subElemCount; i ++) {
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs
index 11b8c30..3d6b502 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs
@@ -7,10 +7,10 @@
 static bool test_program_raster_getters() {
     bool failed = false;
 
-    _RS_ASSERT(rsgProgramRasterGetPointSpriteEnabled(pointSpriteEnabled) == true);
+    _RS_ASSERT(rsgProgramRasterIsPointSpriteEnabled(pointSpriteEnabled) == true);
     _RS_ASSERT(rsgProgramRasterGetCullMode(pointSpriteEnabled) == RS_CULL_BACK);
 
-    _RS_ASSERT(rsgProgramRasterGetPointSpriteEnabled(cullMode) == false);
+    _RS_ASSERT(rsgProgramRasterIsPointSpriteEnabled(cullMode) == false);
     _RS_ASSERT(rsgProgramRasterGetCullMode(cullMode) == RS_CULL_FRONT);
 
     if (failed) {
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs
index 3cd8a20..2ae5636 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs
@@ -15,92 +15,92 @@
     bool failed = false;
 
     _RS_ASSERT(rsgProgramStoreGetDepthFunc(depthFunc) == RS_DEPTH_FUNC_GREATER);
-    _RS_ASSERT(rsgProgramStoreGetDepthMask(depthFunc) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskR(depthFunc) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskG(depthFunc) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskB(depthFunc) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskA(depthFunc) == false);
-    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(depthFunc) == false);
+    _RS_ASSERT(rsgProgramStoreIsDepthMaskEnabled(depthFunc) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskRedEnabled(depthFunc) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskGreenEnabled(depthFunc) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskBlueEnabled(depthFunc) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskAlphaEnabled( depthFunc) == false);
+    _RS_ASSERT(rsgProgramStoreIsDitherEnabled(depthFunc) == false);
     _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(depthFunc) == RS_BLEND_SRC_ZERO);
     _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(depthFunc) == RS_BLEND_DST_ZERO);
 
     _RS_ASSERT(rsgProgramStoreGetDepthFunc(depthWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
-    _RS_ASSERT(rsgProgramStoreGetDepthMask(depthWriteEnable) == true);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskR(depthWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskG(depthWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskB(depthWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskA(depthWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(depthWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreIsDepthMaskEnabled(depthWriteEnable) == true);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskRedEnabled(depthWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskGreenEnabled(depthWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskBlueEnabled(depthWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskAlphaEnabled( depthWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreIsDitherEnabled(depthWriteEnable) == false);
     _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(depthWriteEnable) == RS_BLEND_SRC_ZERO);
     _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(depthWriteEnable) == RS_BLEND_DST_ZERO);
 
     _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorRWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
-    _RS_ASSERT(rsgProgramStoreGetDepthMask(colorRWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorRWriteEnable) == true);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorRWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorRWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorRWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorRWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreIsDepthMaskEnabled(colorRWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskRedEnabled(colorRWriteEnable) == true);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskGreenEnabled(colorRWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskBlueEnabled(colorRWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskAlphaEnabled( colorRWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreIsDitherEnabled(colorRWriteEnable) == false);
     _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorRWriteEnable) == RS_BLEND_SRC_ZERO);
     _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorRWriteEnable) == RS_BLEND_DST_ZERO);
 
     _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorGWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
-    _RS_ASSERT(rsgProgramStoreGetDepthMask(colorGWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorGWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorGWriteEnable) == true);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorGWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorGWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorGWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreIsDepthMaskEnabled(colorGWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskRedEnabled(colorGWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskGreenEnabled(colorGWriteEnable) == true);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskBlueEnabled(colorGWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskAlphaEnabled( colorGWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreIsDitherEnabled(colorGWriteEnable) == false);
     _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorGWriteEnable) == RS_BLEND_SRC_ZERO);
     _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorGWriteEnable) == RS_BLEND_DST_ZERO);
 
     _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorBWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
-    _RS_ASSERT(rsgProgramStoreGetDepthMask(colorBWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorBWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorBWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorBWriteEnable) == true);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorBWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorBWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreIsDepthMaskEnabled(colorBWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskRedEnabled(colorBWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskGreenEnabled(colorBWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskBlueEnabled(colorBWriteEnable) == true);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskAlphaEnabled( colorBWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreIsDitherEnabled(colorBWriteEnable) == false);
     _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorBWriteEnable) == RS_BLEND_SRC_ZERO);
     _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorBWriteEnable) == RS_BLEND_DST_ZERO);
 
     _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorAWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
-    _RS_ASSERT(rsgProgramStoreGetDepthMask(colorAWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorAWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorAWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorAWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorAWriteEnable) == true);
-    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorAWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreIsDepthMaskEnabled(colorAWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskRedEnabled(colorAWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskGreenEnabled(colorAWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskBlueEnabled(colorAWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskAlphaEnabled( colorAWriteEnable) == true);
+    _RS_ASSERT(rsgProgramStoreIsDitherEnabled(colorAWriteEnable) == false);
     _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorAWriteEnable) == RS_BLEND_SRC_ZERO);
     _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorAWriteEnable) == RS_BLEND_DST_ZERO);
 
     _RS_ASSERT(rsgProgramStoreGetDepthFunc(ditherEnable) == RS_DEPTH_FUNC_ALWAYS);
-    _RS_ASSERT(rsgProgramStoreGetDepthMask(ditherEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskR(ditherEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskG(ditherEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskB(ditherEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskA(ditherEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(ditherEnable) == true);
+    _RS_ASSERT(rsgProgramStoreIsDepthMaskEnabled(ditherEnable) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskRedEnabled(ditherEnable) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskGreenEnabled(ditherEnable) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskBlueEnabled(ditherEnable) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskAlphaEnabled( ditherEnable) == false);
+    _RS_ASSERT(rsgProgramStoreIsDitherEnabled(ditherEnable) == true);
     _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(ditherEnable) == RS_BLEND_SRC_ZERO);
     _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(ditherEnable) == RS_BLEND_DST_ZERO);
 
     _RS_ASSERT(rsgProgramStoreGetDepthFunc(blendSrc) == RS_DEPTH_FUNC_ALWAYS);
-    _RS_ASSERT(rsgProgramStoreGetDepthMask(blendSrc) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskR(blendSrc) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskG(blendSrc) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskB(blendSrc) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskA(blendSrc) == false);
-    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(blendSrc) == false);
+    _RS_ASSERT(rsgProgramStoreIsDepthMaskEnabled(blendSrc) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskRedEnabled(blendSrc) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskGreenEnabled(blendSrc) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskBlueEnabled(blendSrc) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskAlphaEnabled( blendSrc) == false);
+    _RS_ASSERT(rsgProgramStoreIsDitherEnabled(blendSrc) == false);
     _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(blendSrc) == RS_BLEND_SRC_DST_COLOR);
     _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(blendSrc) == RS_BLEND_DST_ZERO);
 
     _RS_ASSERT(rsgProgramStoreGetDepthFunc(blendDst) == RS_DEPTH_FUNC_ALWAYS);
-    _RS_ASSERT(rsgProgramStoreGetDepthMask(blendDst) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskR(blendDst) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskG(blendDst) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskB(blendDst) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskA(blendDst) == false);
-    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(blendDst) == false);
+    _RS_ASSERT(rsgProgramStoreIsDepthMaskEnabled(blendDst) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskRedEnabled(blendDst) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskGreenEnabled(blendDst) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskBlueEnabled(blendDst) == false);
+    _RS_ASSERT(rsgProgramStoreIsColorMaskAlphaEnabled( blendDst) == false);
+    _RS_ASSERT(rsgProgramStoreIsDitherEnabled(blendDst) == false);
     _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(blendDst) == RS_BLEND_SRC_ZERO);
     _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(blendDst) == RS_BLEND_DST_DST_ALPHA);
 
diff --git a/tests/SmokeTest/Android.mk b/tests/SmokeTest/Android.mk
index 0adfd4c..591a84e 100644
--- a/tests/SmokeTest/Android.mk
+++ b/tests/SmokeTest/Android.mk
@@ -6,11 +6,11 @@
 # This builds "SmokeTestApp"
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := android.test.runner
-
 LOCAL_PACKAGE_NAME := SmokeTestApp
 
+LOCAL_SDK_VERSION := 8
+
 include $(BUILD_PACKAGE)
 
 # This builds "SmokeTest"
-include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/SmokeTest/tests/Android.mk b/tests/SmokeTest/tests/Android.mk
index 86bf23d..18e682e 100644
--- a/tests/SmokeTest/tests/Android.mk
+++ b/tests/SmokeTest/tests/Android.mk
@@ -4,8 +4,6 @@
 # We only want this apk build for tests.
 LOCAL_MODULE_TAGS := tests
 
-LOCAL_JAVA_LIBRARIES := android.test.runner
-
 # Include all test java files.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
@@ -17,5 +15,7 @@
 
 LOCAL_INSTRUMENTATION_FOR := SmokeTestApp
 
+LOCAL_SDK_VERSION := 8
+
 include $(BUILD_PACKAGE)
 
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index ae01c75..5eac1f2 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -44,7 +44,7 @@
     private final static String TAG = "NotificationTestList";
 
     NotificationManager mNM;
-    Vibrator mVibrator = new Vibrator();
+    Vibrator mVibrator = (Vibrator)getSystemService(VIBRATOR_SERVICE);
     Handler mHandler = new Handler();
 
     long mActivityCreateTime = System.currentTimeMillis();
diff --git a/tests/TileBenchmark/AndroidManifest.xml b/tests/TileBenchmark/AndroidManifest.xml
index f125c70..c569ff4 100644
--- a/tests/TileBenchmark/AndroidManifest.xml
+++ b/tests/TileBenchmark/AndroidManifest.xml
@@ -3,6 +3,7 @@
       android:versionCode="1"
       android:versionName="1.0" package="com.test.tilebenchmark">
     <uses-permission android:name="android.permission.INTERNET"/>
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
     <application android:icon="@drawable/icon"
                  android:label="@string/app_name"
                  android:hardwareAccelerated="true">
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index cbd591f..a4473c8 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -1192,10 +1192,14 @@
             if (targetSdk < 4) {
                 if (!hasWriteExternalStoragePermission) {
                     printf("uses-permission:'android.permission.WRITE_EXTERNAL_STORAGE'\n");
+                    printf("uses-implied-permission:'android.permission.WRITE_EXTERNAL_STORAGE'," \
+                            "'targetSdkVersion < 4'\n");
                     hasWriteExternalStoragePermission = true;
                 }
                 if (!hasReadPhoneStatePermission) {
                     printf("uses-permission:'android.permission.READ_PHONE_STATE'\n");
+                    printf("uses-implied-permission:'android.permission.READ_PHONE_STATE'," \
+                            "'targetSdkVersion < 4'\n");
                 }
             }
 
@@ -1203,15 +1207,21 @@
             // force them to always take READ_EXTERNAL_STORAGE as well.
             if (!hasReadExternalStoragePermission && hasWriteExternalStoragePermission) {
                 printf("uses-permission:'android.permission.READ_EXTERNAL_STORAGE'\n");
+                printf("uses-implied-permission:'android.permission.READ_EXTERNAL_STORAGE'," \
+                        "'requested WRITE_EXTERNAL_STORAGE'\n");
             }
 
             // Pre-JellyBean call log permission compatibility.
             if (targetSdk < 16) {
                 if (!hasReadCallLogPermission && hasReadContactsPermission) {
                     printf("uses-permission:'android.permission.READ_CALL_LOG'\n");
+                    printf("uses-implied-permission:'android.permission.READ_CALL_LOG'," \
+                            "'targetSdkVersion < 16 and requested READ_CONTACTS'\n");
                 }
                 if (!hasWriteCallLogPermission && hasWriteContactsPermission) {
                     printf("uses-permission:'android.permission.WRITE_CALL_LOG'\n");
+                    printf("uses-implied-permission:'android.permission.WRITE_CALL_LOG'," \
+                            "'targetSdkVersion < 16 and requested WRITE_CONTACTS'\n");
                 }
             }
 
@@ -1223,10 +1233,18 @@
              */
             // Camera-related back-compatibility logic
             if (!specCameraFeature) {
-                if (reqCameraFlashFeature || reqCameraAutofocusFeature) {
+                if (reqCameraFlashFeature) {
                     // if app requested a sub-feature (autofocus or flash) and didn't
                     // request the base camera feature, we infer that it meant to
                     printf("uses-feature:'android.hardware.camera'\n");
+                    printf("uses-implied-feature:'android.hardware.camera'," \
+                            "'requested android.hardware.camera.flash feature'\n");
+                } else if (reqCameraAutofocusFeature) {
+                    // if app requested a sub-feature (autofocus or flash) and didn't
+                    // request the base camera feature, we infer that it meant to
+                    printf("uses-feature:'android.hardware.camera'\n");
+                    printf("uses-implied-feature:'android.hardware.camera'," \
+                            "'requested android.hardware.camera.autofocus feature'\n");
                 } else if (hasCameraPermission) {
                     // if app wants to use camera but didn't request the feature, we infer 
                     // that it meant to, and further that it wants autofocus
@@ -1234,6 +1252,8 @@
                     printf("uses-feature:'android.hardware.camera'\n");
                     if (!specCameraAutofocusFeature) {
                         printf("uses-feature:'android.hardware.camera.autofocus'\n");
+                        printf("uses-implied-feature:'android.hardware.camera.autofocus'," \
+                                "'requested android.permission.CAMERA permission'\n");
                     }
                 }
             }
@@ -1245,16 +1265,22 @@
                 // if app either takes a location-related permission or requests one of the
                 // sub-features, we infer that it also meant to request the base location feature
                 printf("uses-feature:'android.hardware.location'\n");
+                printf("uses-implied-feature:'android.hardware.location'," \
+                        "'requested a location access permission'\n");
             }
             if (!specGpsFeature && hasGpsPermission) {
                 // if app takes GPS (FINE location) perm but does not request the GPS
                 // feature, we infer that it meant to
                 printf("uses-feature:'android.hardware.location.gps'\n");
+                printf("uses-implied-feature:'android.hardware.location.gps'," \
+                        "'requested android.permission.ACCESS_FINE_LOCATION permission'\n");
             }
             if (!specNetworkLocFeature && hasCoarseLocPermission) {
                 // if app takes Network location (COARSE location) perm but does not request the
                 // network location feature, we infer that it meant to
                 printf("uses-feature:'android.hardware.location.network'\n");
+                printf("uses-implied-feature:'android.hardware.location.network'," \
+                        "'requested android.permission.ACCESS_COURSE_LOCATION permission'\n");
             }
 
             // Bluetooth-related compatibility logic
@@ -1262,6 +1288,9 @@
                 // if app takes a Bluetooth permission but does not request the Bluetooth
                 // feature, we infer that it meant to
                 printf("uses-feature:'android.hardware.bluetooth'\n");
+                printf("uses-implied-feature:'android.hardware.bluetooth'," \
+                        "'requested android.permission.BLUETOOTH or android.permission.BLUETOOTH_ADMIN " \
+                        "permission and targetSdkVersion > 4'\n");
             }
 
             // Microphone-related compatibility logic
@@ -1269,6 +1298,8 @@
                 // if app takes the record-audio permission but does not request the microphone
                 // feature, we infer that it meant to
                 printf("uses-feature:'android.hardware.microphone'\n");
+                printf("uses-implied-feature:'android.hardware.microphone'," \
+                        "'requested android.permission.RECORD_AUDIO permission'\n");
             }
 
             // WiFi-related compatibility logic
@@ -1276,6 +1307,10 @@
                 // if app takes one of the WiFi permissions but does not request the WiFi
                 // feature, we infer that it meant to
                 printf("uses-feature:'android.hardware.wifi'\n");
+                printf("uses-implied-feature:'android.hardware.wifi'," \
+                        "'requested android.permission.ACCESS_WIFI_STATE, " \
+                        "android.permission.CHANGE_WIFI_STATE, or " \
+                        "android.permission.CHANGE_WIFI_MULTICAST_STATE permission'\n");
             }
 
             // Telephony-related compatibility logic
@@ -1283,6 +1318,8 @@
                 // if app takes one of the telephony permissions or requests a sub-feature but
                 // does not request the base telephony feature, we infer that it meant to
                 printf("uses-feature:'android.hardware.telephony'\n");
+                printf("uses-implied-feature:'android.hardware.telephony'," \
+                        "'requested a telephony-related permission or feature'\n");
             }
 
             // Touchscreen-related back-compatibility logic
@@ -1292,11 +1329,15 @@
                 // Note that specTouchscreenFeature is true if the tag is present, regardless
                 // of whether its value is true or false, so this is safe
                 printf("uses-feature:'android.hardware.touchscreen'\n");
+                printf("uses-implied-feature:'android.hardware.touchscreen'," \
+                        "'assumed you require a touch screen unless explicitly made optional'\n");
             }
             if (!specMultitouchFeature && reqDistinctMultitouchFeature) {
                 // if app takes one of the telephony permissions or requests a sub-feature but
                 // does not request the base telephony feature, we infer that it meant to
                 printf("uses-feature:'android.hardware.touchscreen.multitouch'\n");
+                printf("uses-implied-feature:'android.hardware.touchscreen.multitouch'," \
+                        "'requested android.hardware.touchscreen.multitouch.distinct feature'\n");
             }
 
             // Landscape/portrait-related compatibility logic
@@ -1306,9 +1347,13 @@
                 // orientation is required.
                 if (reqScreenLandscapeFeature) {
                     printf("uses-feature:'android.hardware.screen.landscape'\n");
+                    printf("uses-implied-feature:'android.hardware.screen.landscape'," \
+                            "'one or more activities have specified a landscape orientation'\n");
                 }
                 if (reqScreenPortraitFeature) {
                     printf("uses-feature:'android.hardware.screen.portrait'\n");
+                    printf("uses-implied-feature:'android.hardware.screen.portrait'," \
+                            "'one or more activities have specified a portrait orientation'\n");
                 }
             }
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
index e6c9351..44d28fa 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
@@ -229,6 +229,12 @@
     }
 
     @Override
+    public void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
+            int startHeight) throws RemoteException {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
     public void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX, int startY,
             IRemoteCallback startedCallback) throws RemoteException {
         // TODO Auto-generated method stub
diff --git a/tools/validatekeymaps/Main.cpp b/tools/validatekeymaps/Main.cpp
index 563225e..91e4fda 100644
--- a/tools/validatekeymaps/Main.cpp
+++ b/tools/validatekeymaps/Main.cpp
@@ -89,7 +89,8 @@
 
     case FILETYPE_KEYCHARACTERMAP: {
         sp<KeyCharacterMap> map;
-        status_t status = KeyCharacterMap::load(String8(filename), &map);
+        status_t status = KeyCharacterMap::load(String8(filename),
+                KeyCharacterMap::FORMAT_ANY, &map);
         if (status) {
             fprintf(stderr, "Error %d parsing key character map file.\n\n", status);
             return false;
diff --git a/wifi/java/android/net/wifi/StateChangeResult.java b/wifi/java/android/net/wifi/StateChangeResult.java
index 8ab5982..b15c4a6 100644
--- a/wifi/java/android/net/wifi/StateChangeResult.java
+++ b/wifi/java/android/net/wifi/StateChangeResult.java
@@ -23,12 +23,15 @@
  * @hide
  */
 public class StateChangeResult {
-    StateChangeResult(int networkId, String BSSID, SupplicantState state) {
+    StateChangeResult(int networkId, String SSID, String BSSID, SupplicantState state) {
         this.state = state;
+        this.SSID = SSID;
         this.BSSID = BSSID;
         this.networkId = networkId;
     }
+
     int networkId;
+    String SSID;
     String BSSID;
     SupplicantState state;
 }
diff --git a/wifi/java/android/net/wifi/WifiMonitor.java b/wifi/java/android/net/wifi/WifiMonitor.java
index 3bd03f5..a447c86 100644
--- a/wifi/java/android/net/wifi/WifiMonitor.java
+++ b/wifi/java/android/net/wifi/WifiMonitor.java
@@ -637,6 +637,9 @@
          * id=network-id state=new-state
          */
         private void handleSupplicantStateChange(String dataString) {
+            String SSID = null;
+            int index = dataString.lastIndexOf("SSID=");
+            if (index != -1) SSID = dataString.substring(index + 5);
             String[] dataTokens = dataString.split(" ");
 
             String BSSID = null;
@@ -657,7 +660,6 @@
                 try {
                     value = Integer.parseInt(nameValue[1]);
                 } catch (NumberFormatException e) {
-                    Log.w(TAG, "STATE-CHANGE non-integer parameter: " + token);
                     continue;
                 }
 
@@ -680,7 +682,7 @@
             if (newSupplicantState == SupplicantState.INVALID) {
                 Log.w(TAG, "Invalid supplicant state: " + newState);
             }
-            notifySupplicantStateChange(networkId, BSSID, newSupplicantState);
+            notifySupplicantStateChange(networkId, SSID, BSSID, newSupplicantState);
         }
     }
 
@@ -729,11 +731,13 @@
      * 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 SSID network name
+     * @param BSSID network address
      * @param newState the new {@code SupplicantState}
      */
-    void notifySupplicantStateChange(int networkId, String BSSID, SupplicantState newState) {
+    void notifySupplicantStateChange(int networkId, String SSID, String BSSID, SupplicantState newState) {
         mStateMachine.sendMessage(mStateMachine.obtainMessage(SUPPLICANT_STATE_CHANGE_EVENT,
-                new StateChangeResult(networkId, BSSID, newState)));
+                new StateChangeResult(networkId, SSID, BSSID, newState)));
     }
 
     /**
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index cc0df52..2f14098 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -669,6 +669,7 @@
 
         setInitialState(mInitialState);
 
+        setProcessedMessagesSize(100);
         if (DBG) setDbg(true);
 
         //start the state machine
@@ -1121,6 +1122,37 @@
         return sb.toString();
     }
 
+    @Override
+    protected boolean recordProcessedMessage(Message msg) {
+        //Ignore screen on/off & common messages when driver has started
+        if (getCurrentState() == mConnectedState || getCurrentState() == mDisconnectedState) {
+            switch (msg.what) {
+                case CMD_LOAD_DRIVER:
+                case CMD_START_SUPPLICANT:
+                case CMD_START_DRIVER:
+                case CMD_SET_SCAN_MODE:
+                case CMD_SET_HIGH_PERF_MODE:
+                case CMD_SET_SUSPEND_OPTIMIZATIONS:
+                case CMD_CLEAR_SUSPEND_OPTIMIZATIONS:
+                case CMD_ENABLE_BACKGROUND_SCAN:
+                case CMD_ENABLE_ALL_NETWORKS:
+                return false;
+            }
+        }
+
+        switch (msg.what) {
+            case CMD_START_SCAN:
+            case CMD_ENABLE_RSSI_POLL:
+            case CMD_RSSI_POLL:
+            case CMD_DELAYED_STOP_DRIVER:
+            case WifiMonitor.SCAN_RESULTS_EVENT:
+            case WifiWatchdogStateMachine.RSSI_FETCH:
+                return false;
+            default:
+                return true;
+        }
+    }
+
     /*********************************************************
      * Internal private functions
      ********************************************************/
@@ -1409,23 +1441,6 @@
         mScanResults = scanList;
     }
 
-    private String fetchSSID() {
-        String status = mWifiNative.status();
-        if (status == null) {
-            return null;
-        }
-        // extract ssid from a series of "name=value"
-        String[] lines = status.split("\n");
-        for (String line : lines) {
-            String[] prop = line.split(" *= *");
-            if (prop.length < 2) continue;
-            String name = prop[0];
-            String value = prop[1];
-            if (name.equalsIgnoreCase("ssid")) return value;
-        }
-        return null;
-    }
-
     /*
      * Fetch RSSI and linkspeed on current connection
      */
@@ -1586,6 +1601,7 @@
             /* BSSID is valid only in ASSOCIATING state */
             mWifiInfo.setBSSID(stateChangeResult.BSSID);
         }
+        mWifiInfo.setSSID(stateChangeResult.SSID);
 
         mSupplicantStateTracker.sendMessage(Message.obtain(message));
 
@@ -2015,7 +2031,6 @@
                 default:
                     return NOT_HANDLED;
             }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
             return HANDLED;
         }
     }
@@ -2068,7 +2083,6 @@
                 default:
                     return NOT_HANDLED;
             }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
             return HANDLED;
         }
     }
@@ -2148,7 +2162,6 @@
                 default:
                     return NOT_HANDLED;
             }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
             return HANDLED;
         }
     }
@@ -2169,7 +2182,6 @@
                 default:
                     return NOT_HANDLED;
             }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
             return HANDLED;
         }
     }
@@ -2250,7 +2262,6 @@
                 default:
                     return NOT_HANDLED;
             }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
             return HANDLED;
         }
     }
@@ -2274,7 +2285,6 @@
         public boolean processMessage(Message message) {
             if (DBG) log(getName() + message.toString() + "\n");
             WifiConfiguration config;
-            boolean eventLoggingEnabled = true;
             switch(message.what) {
                 case CMD_STOP_SUPPLICANT:   /* Supplicant stopped by user */
                     transitionTo(mSupplicantStoppingState);
@@ -2291,7 +2301,6 @@
                     sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
                     break;
                 case WifiMonitor.SCAN_RESULTS_EVENT:
-                    eventLoggingEnabled = false;
                     setScanResults(mWifiNative.scanResults());
                     sendScanResultsAvailableBroadcast();
                     mScanResultIsPending = false;
@@ -2381,9 +2390,6 @@
                 default:
                     return NOT_HANDLED;
             }
-            if (eventLoggingEnabled) {
-                EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-            }
             return HANDLED;
         }
 
@@ -2459,7 +2465,6 @@
                 default:
                     return NOT_HANDLED;
             }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
             return HANDLED;
         }
     }
@@ -2505,7 +2510,6 @@
                 default:
                     return NOT_HANDLED;
             }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
             return HANDLED;
         }
     }
@@ -2564,14 +2568,12 @@
         @Override
         public boolean processMessage(Message message) {
             if (DBG) log(getName() + message.toString() + "\n");
-            boolean eventLoggingEnabled = true;
             switch(message.what) {
                case CMD_SET_SCAN_TYPE:
                     mSetScanActive = (message.arg1 == SCAN_ACTIVE);
                     mWifiNative.setScanMode(mSetScanActive);
                     break;
                 case CMD_START_SCAN:
-                    eventLoggingEnabled = false;
                     boolean forceActive = (message.arg1 == SCAN_ACTIVE);
                     if (forceActive && !mSetScanActive) {
                         mWifiNative.setScanMode(forceActive);
@@ -2681,9 +2683,6 @@
                 default:
                     return NOT_HANDLED;
             }
-            if (eventLoggingEnabled) {
-                EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-            }
             return HANDLED;
         }
         @Override
@@ -2731,7 +2730,6 @@
                 default:
                     return NOT_HANDLED;
             }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
             return HANDLED;
         }
     }
@@ -2764,7 +2762,6 @@
                 default:
                     return NOT_HANDLED;
             }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
             return HANDLED;
         }
     }
@@ -2801,7 +2798,6 @@
                 default:
                     return NOT_HANDLED;
             }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
             return HANDLED;
         }
     }
@@ -2923,8 +2919,6 @@
                     mLastNetworkId = message.arg1;
                     mLastBssid = (String) message.obj;
 
-                    //TODO: make supplicant modification to push this in events
-                    mWifiInfo.setSSID(fetchSSID());
                     mWifiInfo.setBSSID(mLastBssid);
                     mWifiInfo.setNetworkId(mLastNetworkId);
                     /* send event to CM & network change broadcast */
@@ -2940,7 +2934,6 @@
                 default:
                     return NOT_HANDLED;
             }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
             return HANDLED;
         }
     }
@@ -2959,7 +2952,6 @@
         @Override
         public boolean processMessage(Message message) {
             if (DBG) log(getName() + message.toString() + "\n");
-            boolean eventLoggingEnabled = true;
             switch (message.what) {
               case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
                   handlePreDhcpSetup();
@@ -2988,7 +2980,6 @@
                     }
                     break;
                 case CMD_START_SCAN:
-                    eventLoggingEnabled = false;
                     /* When the network is connected, re-scanning can trigger
                      * a reconnection. Put it in scan-only mode during scan.
                      * When scan results are received, the mode is switched
@@ -3031,7 +3022,6 @@
                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
                     break;
                 case CMD_RSSI_POLL:
-                    eventLoggingEnabled = false;
                     if (message.arg1 == mRssiPollToken) {
                         // Get Info and continue polling
                         fetchRssiAndLinkSpeedNative();
@@ -3052,7 +3042,6 @@
                     }
                     break;
                 case WifiWatchdogStateMachine.RSSI_FETCH:
-                    eventLoggingEnabled = false;
                     fetchRssiAndLinkSpeedNative();
                     replyToMessage(message, WifiWatchdogStateMachine.RSSI_FETCH_SUCCEEDED,
                             mWifiInfo.getRssi());
@@ -3061,9 +3050,6 @@
                     return NOT_HANDLED;
             }
 
-            if (eventLoggingEnabled) {
-                EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-            }
             return HANDLED;
         }
 
@@ -3131,7 +3117,6 @@
               default:
                   return NOT_HANDLED;
           }
-          EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
           return HANDLED;
       }
     }
@@ -3168,7 +3153,6 @@
                 default:
                     return NOT_HANDLED;
             }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
             return HANDLED;
         }
     }
@@ -3202,7 +3186,6 @@
                 default:
                     return NOT_HANDLED;
             }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
             return HANDLED;
         }
         @Override
@@ -3240,7 +3223,6 @@
                 default:
                     return NOT_HANDLED;
             }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
             return HANDLED;
         }
     }
@@ -3343,7 +3325,6 @@
                 default:
                     return NOT_HANDLED;
             }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
             return HANDLED;
         }
 
@@ -3432,7 +3413,6 @@
                 default:
                     return NOT_HANDLED;
             }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
             return HANDLED;
         }
 
@@ -3504,7 +3484,6 @@
                 default:
                     return NOT_HANDLED;
             }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
             return HANDLED;
         }
     }
@@ -3548,7 +3527,6 @@
                 default:
                     return NOT_HANDLED;
             }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
             return HANDLED;
         }
     }
@@ -3598,7 +3576,6 @@
                 default:
                     return NOT_HANDLED;
             }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
             return HANDLED;
         }
     }
@@ -3629,7 +3606,6 @@
                 default:
                     return NOT_HANDLED;
             }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
             return HANDLED;
         }
     }
@@ -3692,7 +3668,6 @@
                 default:
                     return NOT_HANDLED;
             }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
             return HANDLED;
         }
     }
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 35f37a8..df14bb9 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -22,8 +22,8 @@
 import android.net.ConnectivityManager;
 import android.net.IConnectivityManager;
 import android.net.nsd.DnsSdTxtRecord;
-import android.net.wifi.p2p.nsd.WifiP2pBonjourServiceInfo;
-import android.net.wifi.p2p.nsd.WifiP2pBonjourServiceResponse;
+import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceInfo;
+import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceResponse;
 import android.net.wifi.p2p.nsd.WifiP2pServiceInfo;
 import android.net.wifi.p2p.nsd.WifiP2pServiceRequest;
 import android.net.wifi.p2p.nsd.WifiP2pServiceResponse;
@@ -56,21 +56,20 @@
  * callbacks provided by the application. The application needs to do an initialization with
  * {@link #initialize} before doing any p2p operation.
  *
- * <p> Application actions {@link #discoverPeers}, {@link #connect}, {@link #cancelConnect},
- * {@link #createGroup} and {@link #removeGroup} need a {@link ActionListener} instance for
- * receiving callbacks {@link ActionListener#onSuccess} or {@link ActionListener#onFailure}.
- * Action callbacks indicate whether the initiation of the action was a success or a failure.
+ * <p> Most application calls need a {@link ActionListener} instance for receiving callbacks
+ * {@link ActionListener#onSuccess} or {@link ActionListener#onFailure}. Action callbacks
+ * indicate whether the initiation of the action was a success or a failure.
  * Upon failure, the reason of failure can be one of {@link #ERROR}, {@link #P2P_UNSUPPORTED}
  * or {@link #BUSY}.
  *
  * <p> An application can initiate discovery of peers with {@link #discoverPeers}. An initiated
  * discovery request from an application stays active until the device starts connecting to a peer
- * or forms a p2p group. The {@link ActionListener} callbacks provide feedback on whether the
- * discovery initiation was successful or failure. Additionally, applications can listen
- * to {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent action to know when the peer list changes.
+ * ,forms a p2p group or there is an explicit {@link #stopPeerDiscovery}.
+ * Applications can listen to {@link #WIFI_P2P_DISCOVERY_CHANGED_ACTION} to know if a peer-to-peer
+ * discovery is running or stopped. Additionally, {@link #WIFI_P2P_PEERS_CHANGED_ACTION} indicates
+ * if the peer list has changed.
  *
- * <p> When the peer list change intent {@link #WIFI_P2P_PEERS_CHANGED_ACTION} is received
- * or when an application needs to fetch the current list of peers, it can request the list
+ * <p> When an application needs to fetch the current list of peers, it can request the list
  * of peers with {@link #requestPeers}. When the peer list is available
  * {@link PeerListListener#onPeersAvailable} is called with the device list.
  *
@@ -78,7 +77,7 @@
  * {@link WifiP2pConfig} for details on setting up the configuration. For communication with legacy
  * Wi-Fi devices that do not support p2p, an app can create a group using {@link #createGroup}
  * which creates an access point whose details can be fetched with {@link #requestGroupInfo}.
-*
+ *
  * <p> After a successful group formation through {@link #createGroup} or through {@link #connect},
  * use {@link #requestConnectionInfo} to fetch the connection details. The connection info
  * {@link WifiP2pInfo} contains the address of the group owner
@@ -86,8 +85,36 @@
  * if the current device is a p2p group owner. A p2p client can thus communicate with
  * the p2p group owner through a socket connection.
  *
- * <p> Android has no platform support for service discovery yet, so applications could
- * run a service discovery protocol to discover services on the peer-to-peer netework.
+ * <p> With peer discovery using {@link  #discoverPeers}, an application discovers the neighboring
+ * peers, but has no good way to figure out which peer to establish a connection with. For example,
+ * if a game application is interested in finding all the neighboring peers that are also running
+ * the same game, it has no way to find out until after the connection is setup. Pre-association
+ * service discovery is meant to address this issue of filtering the peers based on the running
+ * services.
+ *
+ * <p>With pre-association service discovery, an application can advertise a service for a
+ * application on a peer device prior to a connection setup between the devices.
+ * Currently, DNS based service discovery (Bonjour) and Upnp are the higher layer protocols
+ * supported. Get Bonjour resources at dns-sd.org and Upnp resources at upnp.org
+ * As an example, a video application can discover a Upnp capable media renderer
+ * prior to setting up a Wi-fi p2p connection with the device.
+ *
+ * <p> An application can advertise a Upnp or a Bonjour service with a call to
+ * {@link #addLocalService}. After a local service is added,
+ * the framework automatically responds to a peer application discovering the service prior
+ * to establishing a p2p connection. A call to {@link #removeLocalService} removes a local
+ * service and {@link #clearLocalServices} can be used to clear all local services.
+ *
+ * <p> An application that is looking for peer devices that support certain services
+ * can do so with a call to  {@link #discoverServices}. Prior to initiating the discovery,
+ * application can add service discovery request with a call to {@link #addServiceRequest},
+ * remove a service discovery request with a call to {@link #removeServiceRequest} or clear
+ * all requests with a call to {@link #clearServiceRequests}. When no service requests remain,
+ * a previously running service discovery will stop.
+ *
+ * The application is notified of a result of service discovery request through listener callbacks
+ * set through {@link #setDnsSdResponseListeners} for Bonjour or
+ * {@link #setUpnpServiceResponseListener} for Upnp.
  *
  * <p class="note"><strong>Note:</strong>
  * Registering an application handler with {@link #initialize} requires the permissions
@@ -443,30 +470,28 @@
 
     /**
     * Interface for callback invocation when service discovery response other than
-    * UPnP or Bonjour is received
-    * @hide
+    * Upnp or Bonjour is received
     */
     public interface ServiceResponseListener {
 
         /**
          * The requested service response is available.
          *
-         * @param serviceType service type. see the service type of
-         * {@link WifiP2pServiceInfo}
+         * @param protocolType protocol type. currently only
+         * {@link WifiP2pServiceInfo#SERVICE_TYPE_VENDOR_SPECIFIC}.
          * @param responseData service discovery response data based on the requested
          *  service protocol type. The format depends on the service type.
          * @param srcDevice source device.
          */
-        public void onServiceAvailable(int serviceType,
+        public void onServiceAvailable(int protocolType,
                 byte[] responseData, WifiP2pDevice srcDevice);
     }
 
     /**
      * Interface for callback invocation when Bonjour service discovery response
      * is received
-     * @hide
      */
-    public interface BonjourServiceResponseListener {
+    public interface DnsSdServiceResponseListener {
 
         /**
          * The requested Bonjour service response is available.
@@ -479,7 +504,7 @@
          * e.g) "_ipp._tcp.local."
          * @param srcDevice source device.
          */
-        public void onBonjourServiceAvailable(String instanceName,
+        public void onDnsSdServiceAvailable(String instanceName,
                 String registrationType, WifiP2pDevice srcDevice);
 
    }
@@ -487,9 +512,8 @@
     /**
      * Interface for callback invocation when Bonjour TXT record is available
      * for a service
-     * @hide
      */
-   public interface BonjourTxtRecordListener {
+   public interface DnsSdTxtRecordListener {
         /**
          * The requested Bonjour service response is available.
          *
@@ -501,7 +525,7 @@
          * @param record txt record.
          * @param srcDevice source device.
          */
-        public void onBonjourTxtRecordAvailable(String fullDomainName,
+        public void onDnsSdTxtRecordAvailable(String fullDomainName,
                 DnsSdTxtRecord record,
                 WifiP2pDevice srcDevice);
    }
@@ -509,7 +533,6 @@
     /**
      * Interface for callback invocation when upnp service discovery response
      * is received
-     * @hide
      * */
     public interface UpnpServiceResponseListener {
 
@@ -542,8 +565,8 @@
         private final static int INVALID_LISTENER_KEY = 0;
         private ChannelListener mChannelListener;
         private ServiceResponseListener mServRspListener;
-        private BonjourServiceResponseListener mBonjourServRspListener;
-        private BonjourTxtRecordListener mBonjourTxtListener;
+        private DnsSdServiceResponseListener mDnsSdServRspListener;
+        private DnsSdTxtRecordListener mDnsSdTxtListener;
         private UpnpServiceResponseListener mUpnpServRspListener;
         private HashMap<Integer, Object> mListenerMap = new HashMap<Integer, Object>();
         private Object mListenerMapLock = new Object();
@@ -632,8 +655,8 @@
         }
 
         private void handleServiceResponse(WifiP2pServiceResponse resp) {
-            if (resp instanceof WifiP2pBonjourServiceResponse) {
-                handleBonjourServiceResponse((WifiP2pBonjourServiceResponse)resp);
+            if (resp instanceof WifiP2pDnsSdServiceResponse) {
+                handleDnsSdServiceResponse((WifiP2pDnsSdServiceResponse)resp);
             } else if (resp instanceof WifiP2pUpnpServiceResponse) {
                 if (mUpnpServRspListener != null) {
                     handleUpnpServiceResponse((WifiP2pUpnpServiceResponse)resp);
@@ -651,17 +674,17 @@
                     resp.getSrcDevice());
         }
 
-        private void handleBonjourServiceResponse(WifiP2pBonjourServiceResponse resp) {
-            if (resp.getDnsType() == WifiP2pBonjourServiceInfo.DNS_TYPE_PTR) {
-                if (mBonjourServRspListener != null) {
-                    mBonjourServRspListener.onBonjourServiceAvailable(
+        private void handleDnsSdServiceResponse(WifiP2pDnsSdServiceResponse resp) {
+            if (resp.getDnsType() == WifiP2pDnsSdServiceInfo.DNS_TYPE_PTR) {
+                if (mDnsSdServRspListener != null) {
+                    mDnsSdServRspListener.onDnsSdServiceAvailable(
                             resp.getInstanceName(),
                             resp.getDnsQueryName(),
                             resp.getSrcDevice());
                 }
-            } else if (resp.getDnsType() == WifiP2pBonjourServiceInfo.DNS_TYPE_TXT) {
-                if (mBonjourTxtListener != null) {
-                    mBonjourTxtListener.onBonjourTxtRecordAvailable(
+            } else if (resp.getDnsType() == WifiP2pDnsSdServiceInfo.DNS_TYPE_TXT) {
+                if (mDnsSdTxtListener != null) {
+                    mDnsSdTxtListener.onDnsSdTxtRecordAvailable(
                             resp.getDnsQueryName(),
                             resp.getTxtRecord(),
                             resp.getSrcDevice());
@@ -749,10 +772,16 @@
         c.mAsyncChannel.sendMessage(DISCOVER_PEERS, 0, c.putListener(listener));
     }
 
-    /**
-     * TODO: Add more documentation before opening up
-     * Cancel peer discovery
-     * @hide
+   /**
+     * Stop an ongoing peer discovery
+     *
+     * <p> The function call immediately returns after sending a stop request
+     * to the framework. The application is notified of a success or failure to initiate
+     * stop through listener callbacks {@link ActionListener#onSuccess} or
+     * {@link ActionListener#onFailure}.
+     *
+     * @param c is the channel created at {@link #initialize}
+     * @param listener for callbacks on success or failure. Can be null.
      */
     public void stopPeerDiscovery(Channel c, ActionListener listener) {
         checkChannel(c);
@@ -843,27 +872,25 @@
     }
 
     /**
-     * Register a local service of service discovery.
+     * Register a local service for service discovery. If a local service is registered,
+     * the framework automatically responds to a service discovery request from a peer.
      *
      * <p> The function call immediately returns after sending a request to add a local
      * service to the framework. The application is notified of a success or failure to
      * add service through listener callbacks {@link ActionListener#onSuccess} or
      * {@link ActionListener#onFailure}.
      *
-     * <p>The service information is set through the subclass of {@link WifiP2pServiceInfo}.<br>
-     * e.g )  {@link WifiP2pUpnpServiceInfo#newInstance} or
-     *  {@link WifiP2pBonjourServiceInfo#newInstance}
+     * <p>The service information is set through {@link WifiP2pServiceInfo}.<br>
+     * or its subclass calls  {@link WifiP2pUpnpServiceInfo#newInstance} or
+     *  {@link WifiP2pDnsSdServiceInfo#newInstance} for a Upnp or Bonjour service
+     * respectively
      *
-     * <p>If a local service is added, the framework responds the appropriate service discovery
-     *  request automatically.
-     *
-     * <p>These service information will be clear when p2p is disabled or call
+     * <p>The service information can be cleared with calls to
      *  {@link #removeLocalService} or {@link #clearLocalServices}.
      *
      * @param c is the channel created at {@link #initialize}
      * @param servInfo is a local service information.
      * @param listener for callbacks on success or failure. Can be null.
-     * @hide
      */
     public void addLocalService(Channel c, WifiP2pServiceInfo servInfo, ActionListener listener) {
         checkChannel(c);
@@ -872,7 +899,7 @@
     }
 
     /**
-     * Unregister a specified local service of service discovery.
+     * Remove a registered local service added with {@link #addLocalService}
      *
      * <p> The function call immediately returns after sending a request to remove a
      * local service to the framework. The application is notified of a success or failure to
@@ -882,7 +909,6 @@
      * @param c is the channel created at {@link #initialize}
      * @param servInfo is the local service information.
      * @param listener for callbacks on success or failure. Can be null.
-     * @hide
      */
     public void removeLocalService(Channel c, WifiP2pServiceInfo servInfo,
             ActionListener listener) {
@@ -901,7 +927,6 @@
      *
      * @param c is the channel created at {@link #initialize}
      * @param listener for callbacks on success or failure. Can be null.
-     * @hide
      */
     public void clearLocalServices(Channel c, ActionListener listener) {
         checkChannel(c);
@@ -910,12 +935,14 @@
 
     /**
      * Register a callback to be invoked on receiving service discovery response.
+     * Used only for vendor specific protocol right now. For Bonjour or Upnp, use
+     * {@link #setDnsSdResponseListeners} or {@link #setUpnpServiceResponseListener}
+     * respectively.
      *
      * <p> see {@link #discoverServices} for the detail.
      *
      * @param c is the channel created at {@link #initialize}
      * @param listener for callbacks on receiving service discovery response.
-     * @hide
      */
     public void setServiceResponseListener(Channel c,
             ServiceResponseListener listener) {
@@ -930,15 +957,14 @@
      * <p> see {@link #discoverServices} for the detail.
      *
      * @param c
-     * @param servlistener is for listening to a Bonjour service response
-     * @param txtListener is for listening to a Bonjour TXT record
-     * @hide
+     * @param servListener is for listening to a Bonjour service response
+     * @param txtListener is for listening to a Bonjour TXT record response
      */
-    public void setBonjourResponseListeners(Channel c,
-            BonjourServiceResponseListener servListener, BonjourTxtRecordListener txtListener) {
+    public void setDnsSdResponseListeners(Channel c,
+            DnsSdServiceResponseListener servListener, DnsSdTxtRecordListener txtListener) {
         checkChannel(c);
-        c.mBonjourServRspListener = servListener;
-        c.mBonjourTxtListener = txtListener;
+        c.mDnsSdServRspListener = servListener;
+        c.mDnsSdTxtListener = txtListener;
     }
 
     /**
@@ -949,7 +975,6 @@
      *
      * @param c is the channel created at {@link #initialize}
      * @param listener for callbacks on receiving service discovery response.
-     * @hide
      */
     public void setUpnpServiceResponseListener(Channel c,
             UpnpServiceResponseListener listener) {
@@ -971,11 +996,10 @@
      *
      * <p>The application is notified of the response against the service discovery request
      * through listener callbacks registered by {@link #setServiceResponseListener} or
-     * {@link #setBonjourServiceResponseListener}, or {@link #setUpnpServiceResponseListener}.
+     * {@link #setDnsSdResponseListeners}, or {@link #setUpnpServiceResponseListener}.
      *
      * @param c is the channel created at {@link #initialize}
      * @param listener for callbacks on success or failure. Can be null.
-     * @hide
      */
     public void discoverServices(Channel c, ActionListener listener) {
         checkChannel(c);
@@ -993,14 +1017,13 @@
      * <p>After service discovery request is added, you can initiate service discovery by
      * {@link #discoverServices}.
      *
-     * <p>These information will be clear when wifi p2p is disabled or
+     * <p>The added service requests can be cleared with calls to
      * {@link #removeServiceRequest(Channel, WifiP2pServiceRequest, ActionListener)} or
-     * {@link #clearServiceRequests(Channel, ActionListener)} is called.
+     * {@link #clearServiceRequests(Channel, ActionListener)}.
      *
      * @param c is the channel created at {@link #initialize}
      * @param req is the service discovery request.
      * @param listener for callbacks on success or failure. Can be null.
-     * @hide
      */
     public void addServiceRequest(Channel c,
             WifiP2pServiceRequest req, ActionListener listener) {
@@ -1011,7 +1034,7 @@
     }
 
     /**
-     * Remove a specified service discovery request.
+     * Remove a specified service discovery request added with {@link #addServiceRequest}
      *
      * <p> The function call immediately returns after sending a request to remove service
      * discovery request to the framework. The application is notified of a success or failure to
@@ -1021,7 +1044,6 @@
      * @param c is the channel created at {@link #initialize}
      * @param req is the service discovery request.
      * @param listener for callbacks on success or failure. Can be null.
-     * @hide
      */
     public void removeServiceRequest(Channel c, WifiP2pServiceRequest req,
             ActionListener listener) {
@@ -1041,7 +1063,6 @@
      *
      * @param c is the channel created at {@link #initialize}
      * @param listener for callbacks on success or failure. Can be null.
-     * @hide
      */
     public void clearServiceRequests(Channel c, ActionListener listener) {
         checkChannel(c);
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pBonjourServiceRequest.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pBonjourServiceRequest.java
deleted file mode 100644
index d1635f1..0000000
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pBonjourServiceRequest.java
+++ /dev/null
@@ -1,102 +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 android.net.wifi.p2p.nsd;
-
-
-/**
- * A class for a request of bonjour service discovery.
- * @hide
- */
-public class WifiP2pBonjourServiceRequest extends WifiP2pServiceRequest {
-
-    /**
-     * This constructor is only used in newInstance().
-     *
-     * @param query The part of service specific query.
-     * @hide
-     */
-    private WifiP2pBonjourServiceRequest(String query) {
-        super(WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR, query);
-    }
-
-    /**
-     * This constructor is only used in newInstance().
-     * @hide
-     */
-    private WifiP2pBonjourServiceRequest() {
-        super(WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR, null);
-    }
-
-    private WifiP2pBonjourServiceRequest(String registrationType, int dnsType, int version) {
-        super(WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR, WifiP2pBonjourServiceInfo.createRequest(
-                registrationType,
-                WifiP2pBonjourServiceInfo.DNS_TYPE_PTR,
-                WifiP2pBonjourServiceInfo.VERSION_1));
-    }
-
-    /**
-     * Create a service discovery request to search all Bonjour services.
-     *
-     * @return service request for Bonjour.
-     */
-    public static WifiP2pBonjourServiceRequest newInstance() {
-        return new WifiP2pBonjourServiceRequest();
-    }
-
-    /**
-     * Create a service discovery request to resolve the instance name with the specified
-     * registration type.
-     *
-     * @param registrationType registration type. Cannot be null <br>
-     * e.g) <br>
-     *  "_afpovertcp._tcp.local."(Apple File Sharing over TCP)<br>
-     *  "_ipp._tcp.local." (IP Printing over TCP)<br>
-     * @return service request for Bonjour.
-     */
-    public static WifiP2pBonjourServiceRequest newInstance(String registrationType) {
-        if (registrationType == null) {
-            throw new IllegalArgumentException("registration type cannot be null");
-        }
-        return new WifiP2pBonjourServiceRequest(registrationType,
-                WifiP2pBonjourServiceInfo.DNS_TYPE_PTR,
-                WifiP2pBonjourServiceInfo.VERSION_1);
-    }
-
-    /**
-     * Create a service discovery request to get the TXT data from the specified
-     * service.
-     *
-     * @param instanceName instance name. Cannot be null. <br>
-     *  "MyPrinter"
-     * @param registrationType registration type. Cannot be null. <br>
-     * e.g) <br>
-     *  "_afpovertcp._tcp.local."(Apple File Sharing over TCP)<br>
-     *  "_ipp._tcp.local." (IP Printing over TCP)<br>
-     * @return service request for Bonjour.
-     */
-    public static WifiP2pBonjourServiceRequest newInstance(String instanceName,
-            String registrationType) {
-        if (instanceName == null || registrationType == null) {
-            throw new IllegalArgumentException(
-                    "instance name or registration type cannot be null");
-        }
-        String fullDomainName = instanceName + "." + registrationType;
-        return new WifiP2pBonjourServiceRequest(fullDomainName,
-                WifiP2pBonjourServiceInfo.DNS_TYPE_TXT,
-                WifiP2pBonjourServiceInfo.VERSION_1);
-    }
-}
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pBonjourServiceInfo.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java
similarity index 78%
rename from wifi/java/android/net/wifi/p2p/nsd/WifiP2pBonjourServiceInfo.java
rename to wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java
index ed278d5..54b7ac4 100644
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pBonjourServiceInfo.java
+++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java
@@ -25,10 +25,15 @@
 import java.util.Map;
 
 /**
- * A class for Bonjour service information.
- * @hide
+ * A class for storing Bonjour service information that is advertised
+ * over a Wi-Fi peer-to-peer setup.
+ *
+ * {@see android.net.wifi.p2p.WifiP2pManager#addLocalService}
+ * {@see android.net.wifi.p2p.WifiP2pManager#removeLocalService}
+ * {@see WifiP2pServiceInfo}
+ * {@see WifiP2pUpnpServiceInfo}
  */
-public class WifiP2pBonjourServiceInfo extends WifiP2pServiceInfo {
+public class WifiP2pDnsSdServiceInfo extends WifiP2pServiceInfo {
 
     /**
      * Bonjour version 1.
@@ -67,25 +72,26 @@
      *
      * @param queryList
      */
-    private WifiP2pBonjourServiceInfo(List<String> queryList) {
+    private WifiP2pDnsSdServiceInfo(List<String> queryList) {
         super(queryList);
     }
 
     /**
-     * Create Bonjour service information object.
+     * Create a Bonjour service information object.
      *
      * @param instanceName instance name.<br>
      *  e.g) "MyPrinter"
-     * @param registrationType registration type.<br>
-     *  e.g) "_ipp._tcp.local."
-     * @param txtRecord text record.
+     * @param serviceType service type.<br>
+     *  e.g) "_ipp._tcp"
+     * @param txtRecord TXT record as defined at
+     * http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt
      * @return Bonjour service information object
      */
-    public static WifiP2pBonjourServiceInfo newInstance(String instanceName,
-            String registrationType, DnsSdTxtRecord txtRecord) {
-        if (TextUtils.isEmpty(instanceName) || TextUtils.isEmpty(registrationType)) {
+    public static WifiP2pDnsSdServiceInfo newInstance(String instanceName,
+            String serviceType, DnsSdTxtRecord txtRecord) {
+        if (TextUtils.isEmpty(instanceName) || TextUtils.isEmpty(serviceType)) {
             throw new IllegalArgumentException(
-                    "instance name or registration type cannot be empty");
+                    "instance name or service type cannot be empty");
         }
 
         if (txtRecord == null) {
@@ -93,10 +99,10 @@
         }
 
         ArrayList<String> queries = new ArrayList<String>();
-        queries.add(createPtrServiceQuery(instanceName, registrationType));
-        queries.add(createTxtServiceQuery(instanceName, registrationType, txtRecord));
+        queries.add(createPtrServiceQuery(instanceName, serviceType));
+        queries.add(createTxtServiceQuery(instanceName, serviceType, txtRecord));
 
-        return new WifiP2pBonjourServiceInfo(queries);
+        return new WifiP2pDnsSdServiceInfo(queries);
     }
 
     /**
@@ -104,16 +110,16 @@
      *
      * @param instanceName instance name.<br>
      *  e.g) "MyPrinter"
-     * @param registrationType registration type.<br>
-     *  e.g) "_ipp._tcp.local."
+     * @param serviceType service type.<br>
+     *  e.g) "_ipp._tcp"
      * @return wpa_supplicant service query.
      */
     private static String createPtrServiceQuery(String instanceName,
-            String registrationType) {
+            String serviceType) {
 
         StringBuffer sb = new StringBuffer();
         sb.append("bonjour ");
-        sb.append(createRequest(registrationType, DNS_TYPE_PTR, VERSION_1));
+        sb.append(createRequest(serviceType + ".local.", DNS_TYPE_PTR, VERSION_1));
         sb.append(" ");
 
         byte[] data = instanceName.getBytes();
@@ -130,20 +136,20 @@
      *
      * @param instanceName instance name.<br>
      *  e.g) "MyPrinter"
-     * @param registrationType registration type.<br>
-     *  e.g) "_ipp._tcp.local."
+     * @param serviceType service type.<br>
+     *  e.g) "_ipp._tcp"
      * @param txtRecord TXT record.<br>
      * @return wpa_supplicant service query.
      */
-    public static String createTxtServiceQuery(String instanceName,
-            String registrationType,
+    private static String createTxtServiceQuery(String instanceName,
+            String serviceType,
             DnsSdTxtRecord txtRecord) {
 
 
         StringBuffer sb = new StringBuffer();
         sb.append("bonjour ");
 
-        sb.append(createRequest((instanceName + "." + registrationType),
+        sb.append(createRequest((instanceName + "." + serviceType + ".local."),
                 DNS_TYPE_TXT, VERSION_1));
         sb.append(" ");
         byte[] rawData = txtRecord.getRawData();
@@ -173,7 +179,7 @@
          * ________________________________________________
          * |   Type (2)           | Version (1) |
          */
-        if (dnsType == WifiP2pBonjourServiceInfo.DNS_TYPE_TXT) {
+        if (dnsType == WifiP2pDnsSdServiceInfo.DNS_TYPE_TXT) {
             dnsName = dnsName.toLowerCase();
         }
         sb.append(compressDnsName(dnsName));
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceRequest.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceRequest.java
new file mode 100644
index 0000000..d5415e0
--- /dev/null
+++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceRequest.java
@@ -0,0 +1,107 @@
+/*
+ * 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.net.wifi.p2p.nsd;
+
+import android.net.wifi.p2p.WifiP2pManager;
+
+/**
+ * A class for creating a Bonjour service discovery request for use with
+ * {@link WifiP2pManager#addServiceRequest} and {@link WifiP2pManager#removeServiceRequest}
+ *
+ * {@see WifiP2pManager}
+ * {@see WifiP2pServiceRequest}
+ * {@see WifiP2pUpnpServiceRequest}
+ */
+public class WifiP2pDnsSdServiceRequest extends WifiP2pServiceRequest {
+
+    /**
+     * This constructor is only used in newInstance().
+     *
+     * @param query The part of service specific query.
+     * @hide
+     */
+    private WifiP2pDnsSdServiceRequest(String query) {
+        super(WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR, query);
+    }
+
+    /**
+     * This constructor is only used in newInstance().
+     * @hide
+     */
+    private WifiP2pDnsSdServiceRequest() {
+        super(WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR, null);
+    }
+
+    private WifiP2pDnsSdServiceRequest(String dnsQuery, int dnsType, int version) {
+        super(WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR, WifiP2pDnsSdServiceInfo.createRequest(
+                dnsQuery,
+                dnsType,
+                version));
+    }
+
+    /**
+     * Create a service discovery request to search all Bonjour services.
+     *
+     * @return service request for Bonjour.
+     */
+    public static WifiP2pDnsSdServiceRequest newInstance() {
+        return new WifiP2pDnsSdServiceRequest();
+    }
+
+    /**
+     * Create a service discovery to search for Bonjour services with the specified
+     * service type.
+     *
+     * @param serviceType service type. Cannot be null <br>
+     *  "_afpovertcp._tcp."(Apple File Sharing over TCP)<br>
+     *  "_ipp._tcp" (IP Printing over TCP)<br>
+     *  "_http._tcp" (http service)
+     * @return service request for DnsSd.
+     */
+    public static WifiP2pDnsSdServiceRequest newInstance(String serviceType) {
+        if (serviceType == null) {
+            throw new IllegalArgumentException("service type cannot be null");
+        }
+        return new WifiP2pDnsSdServiceRequest(serviceType + ".local.",
+                WifiP2pDnsSdServiceInfo.DNS_TYPE_PTR,
+                WifiP2pDnsSdServiceInfo.VERSION_1);
+    }
+
+    /**
+     * Create a service discovery request to get the TXT data from the specified
+     * Bonjour service.
+     *
+     * @param instanceName instance name. Cannot be null. <br>
+     *  "MyPrinter"
+     * @param serviceType service type. Cannot be null. <br>
+     * e.g) <br>
+     *  "_afpovertcp._tcp"(Apple File Sharing over TCP)<br>
+     *  "_ipp._tcp" (IP Printing over TCP)<br>
+     * @return service request for Bonjour.
+     */
+    public static WifiP2pDnsSdServiceRequest newInstance(String instanceName,
+            String serviceType) {
+        if (instanceName == null || serviceType == null) {
+            throw new IllegalArgumentException(
+                    "instance name or service type cannot be null");
+        }
+        String fullDomainName = instanceName + "." + serviceType + ".local.";
+        return new WifiP2pDnsSdServiceRequest(fullDomainName,
+                WifiP2pDnsSdServiceInfo.DNS_TYPE_TXT,
+                WifiP2pDnsSdServiceInfo.VERSION_1);
+    }
+}
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pBonjourServiceResponse.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceResponse.java
similarity index 88%
rename from wifi/java/android/net/wifi/p2p/nsd/WifiP2pBonjourServiceResponse.java
rename to wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceResponse.java
index c511569..c053c8a 100644
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pBonjourServiceResponse.java
+++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceResponse.java
@@ -30,7 +30,7 @@
  *
  * @hide
  */
-public class WifiP2pBonjourServiceResponse extends WifiP2pServiceResponse {
+public class WifiP2pDnsSdServiceResponse extends WifiP2pServiceResponse {
 
     /**
      * DNS query name.
@@ -46,27 +46,27 @@
      * Service instance name.
      * e.g) "MyPrinter"
      * This field is only used when the dns type equals to
-     * {@link WifiP2pBonjourServiceInfo#DNS_TYPE_PTR}.
+     * {@link WifiP2pDnsSdServiceInfo#DNS_TYPE_PTR}.
      */
     private String mInstanceName;
 
     /**
      * DNS Type.
-     * Should be {@link WifiP2pBonjourServiceInfo#DNS_TYPE_PTR} or
-     * {@link WifiP2pBonjourServiceInfo#DNS_TYPE_TXT}.
+     * Should be {@link WifiP2pDnsSdServiceInfo#DNS_TYPE_PTR} or
+     * {@link WifiP2pDnsSdServiceInfo#DNS_TYPE_TXT}.
      */
     private int mDnsType;
 
     /**
-     * Bonjour version number.
-     * Should be {@link WifiP2pBonjourServiceInfo#VERSION_1}.
+     * DnsSd version number.
+     * Should be {@link WifiP2pDnsSdServiceInfo#VERSION_1}.
      */
     private int mVersion;
 
     /**
      * Txt record.
      * This field is only used when the dns type equals to
-     * {@link WifiP2pBonjourServiceInfo#DNS_TYPE_TXT}.
+     * {@link WifiP2pDnsSdServiceInfo#DNS_TYPE_TXT}.
      */
     private DnsSdTxtRecord mTxtRecord;
 
@@ -128,7 +128,7 @@
     @Override
     public String toString() {
         StringBuffer sbuf = new StringBuffer();
-        sbuf.append("serviceType:Bonjour(").append(mServiceType).append(")");
+        sbuf.append("serviceType:DnsSd(").append(mServiceType).append(")");
         sbuf.append(" status:").append(Status.toString(mStatus));
         sbuf.append(" srcAddr:").append(mDevice.deviceAddress);
         sbuf.append(" version:").append(String.format("%02x", mVersion));
@@ -149,7 +149,7 @@
      * @param data RDATA.
      * @hide
      */
-    protected WifiP2pBonjourServiceResponse(int status,
+    protected WifiP2pDnsSdServiceResponse(int status,
             int tranId, WifiP2pDevice dev, byte[] data) {
         super(WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR,
                 status, tranId, dev, data);
@@ -159,7 +159,7 @@
     }
 
     /**
-     * Parse Bonjour service discovery response.
+     * Parse DnsSd service discovery response.
      *
      * @return {@code true} if the operation succeeded
      */
@@ -193,7 +193,7 @@
             return false;
         }
 
-        if (mDnsType == WifiP2pBonjourServiceInfo.DNS_TYPE_PTR) {
+        if (mDnsType == WifiP2pDnsSdServiceInfo.DNS_TYPE_PTR) {
             String rData = readDnsName(dis);
             if (rData == null) {
                 return false;
@@ -204,7 +204,7 @@
 
             mInstanceName = rData.substring(0,
                     rData.length() - mDnsQueryName.length() -1);
-        } else if (mDnsType == WifiP2pBonjourServiceInfo.DNS_TYPE_TXT) {
+        } else if (mDnsType == WifiP2pDnsSdServiceInfo.DNS_TYPE_TXT) {
             mTxtRecord = readTxtData(dis);
             if (mTxtRecord == null) {
                 return false;
@@ -287,23 +287,23 @@
     }
 
     /**
-     * Creates Bonjour service response.
+     * Creates DnsSd service response.
      *  This is only called from WifiP2pServiceResponse
      *
      * @param status status code.
      * @param dev source device.
-     * @param data Bonjour response data.
-     * @return Bonjour service response data.
+     * @param data DnsSd response data.
+     * @return DnsSd service response data.
      * @hide
      */
-    static WifiP2pBonjourServiceResponse newInstance(int status,
+    static WifiP2pDnsSdServiceResponse newInstance(int status,
             int transId, WifiP2pDevice dev, byte[] data) {
         if (status != WifiP2pServiceResponse.Status.SUCCESS) {
-            return new WifiP2pBonjourServiceResponse(status,
+            return new WifiP2pDnsSdServiceResponse(status,
                     transId, dev, null);
         }
         try {
-            return new WifiP2pBonjourServiceResponse(status,
+            return new WifiP2pDnsSdServiceResponse(status,
                     transId, dev, data);
         } catch (IllegalArgumentException e) {
             e.printStackTrace();
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.java
index aed5616..b931475 100644
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.java
+++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.java
@@ -23,13 +23,11 @@
 import java.util.List;
 
 /**
- * The class for service information.
- *
- * <p>Currently UPnP and Bonjour are only supported.
+ * A class for storing service information that is advertised
+ * over a Wi-Fi peer-to-peer setup
  *
  * @see WifiP2pUpnpServiceInfo
- * @see WifiP2pBonjourServiceInfo
- * @hide
+ * @see WifiP2pDnsSdServiceInfo
  */
 public class WifiP2pServiceInfo implements Parcelable {
 
@@ -39,7 +37,7 @@
     public static final int SERVICE_TYPE_ALL             = 0;
 
     /**
-     * Bonjour protocol.
+     * DNS based service discovery protocol.
      */
     public static final int SERVICE_TYPE_BONJOUR         = 1;
 
@@ -50,6 +48,7 @@
 
     /**
      * WS-Discovery protocol
+     * @hide
      */
     public static final int SERVICE_TYPE_WS_DISCOVERY    = 3;
 
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.java
index e41d9aa..c7f0e5f 100644
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.java
+++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.java
@@ -21,24 +21,26 @@
 import android.os.Parcelable;
 
 /**
- * A class for a request of service discovery.
+ * A class for creating a service discovery request for use with
+ * {@link WifiP2pManager#addServiceRequest} and {@link WifiP2pManager#removeServiceRequest}
  *
- * <p>This class is used when you create customized service discovery request.
- * e.g) vendor specific request/ws discovery etc.
+ * <p>This class is used to create service discovery request for custom
+ * vendor specific service discovery protocol {@link WifiP2pServiceInfo#SERVICE_TYPE_VENDOR_SPECIFIC}
+ * or to search all service protocols {@link WifiP2pServiceInfo#SERVICE_TYPE_ALL}.
  *
- * <p>If you want to create UPnP or Bonjour service request, then you had better
- * use {@link WifiP2pUpnpServiceRequest} or {@link WifiP2pBonjourServiceRequest}.
+ * <p>For the purpose of creating a UPnP or Bonjour service request, use
+ * {@link WifiP2pUpnpServiceRequest} or {@link WifiP2pDnsSdServiceRequest} respectively.
  *
- * @see WifiP2pUpnpServiceRequest
- * @see WifiP2pBonjourServiceRequest
- * @hide
+ * {@see WifiP2pManager}
+ * {@see WifiP2pUpnpServiceRequest}
+ * {@see WifiP2pDnsSdServiceRequest}
  */
 public class WifiP2pServiceRequest implements Parcelable {
 
     /**
-     * Service type. It's defined in table63 in Wi-Fi Direct specification.
+     * Service discovery protocol. It's defined in table63 in Wi-Fi Direct specification.
      */
-    private int mServiceType;
+    private int mProtocolType;
 
     /**
      * The length of the service request TLV.
@@ -56,7 +58,7 @@
     /**
      * The hex dump string of query data for the requested service information.
      *
-     * e.g) Bonjour apple file sharing over tcp (dns name=_afpovertcp._tcp.local.)
+     * e.g) DnsSd apple file sharing over tcp (dns name=_afpovertcp._tcp.local.)
      * 0b5f6166706f766572746370c00c000c01
      */
     private String mQuery;
@@ -64,14 +66,14 @@
     /**
      * This constructor is only used in newInstance().
      *
-     * @param serviceType service discovery type.
+     * @param protocolType service discovery protocol.
      * @param query The part of service specific query.
      * @hide
      */
-    protected WifiP2pServiceRequest(int serviceType, String query) {
+    protected WifiP2pServiceRequest(int protocolType, String query) {
         validateQuery(query);
 
-        mServiceType = serviceType;
+        mProtocolType = protocolType;
         mQuery = query;
         if (query != null) {
             mLength = query.length()/2 + 2;
@@ -90,7 +92,7 @@
      */
     private WifiP2pServiceRequest(int serviceType, int length,
             int transId, String query) {
-        mServiceType = serviceType;
+        mProtocolType = serviceType;
         mLength = length;
         mTransId = transId;
         mQuery = query;
@@ -134,7 +136,7 @@
         // 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", mServiceType));
+        sb.append(String.format("%02x", mProtocolType));
         sb.append(String.format("%02x", mTransId));
         if (mQuery != null) {
             sb.append(mQuery);
@@ -177,42 +179,34 @@
     }
 
     /**
-     * Create service discovery request.
+     * Create a service discovery request.
      *
-     * <p>The created instance is set to framework by
-     * {@link WifiP2pManager#addLocalService}.
+     * @param protocolType can be {@link WifiP2pServiceInfo#SERVICE_TYPE_ALL}
+     * or {@link WifiP2pServiceInfo#SERVICE_TYPE_VENDOR_SPECIFIC}.
+     * In order to create a UPnP or Bonjour service request, use
+     * {@link WifiP2pUpnpServiceRequest} or {@link WifiP2pDnsSdServiceRequest}
+     * respectively
      *
-     * @param serviceType service type.<br>
-     * e.g) {@link WifiP2pServiceInfo#SERVICE_TYPE_ALL},
-     *  {@link WifiP2pServiceInfo#SERVICE_TYPE_WS_DISCOVERY},
-     * {@link WifiP2pServiceInfo#SERVICE_TYPE_VENDOR_SPECIFIC}.
-     * If you want to use UPnP or Bonjour, you create  the request by
-     * {@link WifiP2pUpnpServiceRequest} or {@link WifiP2pBonjourServiceRequest}
-     *
-     * @param query hex string. if null, all specified services are requested.
+     * @param queryData hex string that is vendor specific.  Can be null.
      * @return service discovery request.
      */
-    public static WifiP2pServiceRequest newInstance(int serviceType, String query) {
-        return new WifiP2pServiceRequest(serviceType, query);
+    public static WifiP2pServiceRequest newInstance(int protocolType, String queryData) {
+        return new WifiP2pServiceRequest(protocolType, queryData);
     }
 
     /**
-     * Create all service discovery request.
+     * Create a service discovery request.
      *
-     * <p>The created instance is set to framework by
-     * {@link WifiP2pManager#addLocalService}.
-     *
-     * @param serviceType service type.<br>
-     * e.g) {@link WifiP2pServiceInfo#SERVICE_TYPE_ALL},
-     *  {@link WifiP2pServiceInfo#SERVICE_TYPE_WS_DISCOVERY},
-     * {@link WifiP2pServiceInfo#SERVICE_TYPE_VENDOR_SPECIFIC}.
-     * If you want to use UPnP or Bonjour, you create  the request by
-     * {@link WifiP2pUpnpServiceRequest} or {@link WifiP2pBonjourServiceRequest}
+     * @param protocolType can be {@link WifiP2pServiceInfo#SERVICE_TYPE_ALL}
+     * or {@link WifiP2pServiceInfo#SERVICE_TYPE_VENDOR_SPECIFIC}.
+     * In order to create a UPnP or Bonjour service request, use
+     * {@link WifiP2pUpnpServiceRequest} or {@link WifiP2pDnsSdServiceRequest}
+     * respectively
      *
      * @return service discovery request.
      */
-    public static WifiP2pServiceRequest newInstance(int serviceType) {
-        return new WifiP2pServiceRequest(serviceType, null);
+    public static WifiP2pServiceRequest newInstance(int protocolType ) {
+        return new WifiP2pServiceRequest(protocolType, null);
     }
 
     @Override
@@ -230,7 +224,7 @@
          * Not compare transaction id.
          * Transaction id may be changed on each service discovery operation.
          */
-        if ((req.mServiceType != mServiceType) ||
+        if ((req.mProtocolType != mProtocolType) ||
                 (req.mLength != mLength)) {
             return false;
         }
@@ -246,7 +240,7 @@
     @Override
     public int hashCode() {
         int result = 17;
-        result = 31 * result + mServiceType;
+        result = 31 * result + mProtocolType;
         result = 31 * result + mLength;
         result = 31 * result + (mQuery == null ? 0 : mQuery.hashCode());
         return result;
@@ -259,7 +253,7 @@
 
     /** Implement the Parcelable interface {@hide} */
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mServiceType);
+        dest.writeInt(mProtocolType);
         dest.writeInt(mLength);
         dest.writeInt(mTransId);
         dest.writeString(mQuery);
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceResponse.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceResponse.java
index 0855eae..ac31663 100644
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceResponse.java
+++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceResponse.java
@@ -246,7 +246,7 @@
 
                 WifiP2pServiceResponse resp;
                 if (type ==  WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR) {
-                    resp = WifiP2pBonjourServiceResponse.newInstance(status,
+                    resp = WifiP2pDnsSdServiceResponse.newInstance(status,
                             transId, dev, data);
                 } else if (type == WifiP2pServiceInfo.SERVICE_TYPE_UPNP) {
                     resp = WifiP2pUpnpServiceResponse.newInstance(status,
@@ -373,7 +373,7 @@
                     in.readByteArray(data);
                 }
                 if (type ==  WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR) {
-                    return WifiP2pBonjourServiceResponse.newInstance(status,
+                    return WifiP2pDnsSdServiceResponse.newInstance(status,
                             transId, dev, data);
                 } else if (type == WifiP2pServiceInfo.SERVICE_TYPE_UPNP) {
                     return WifiP2pUpnpServiceResponse.newInstance(status,
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceInfo.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceInfo.java
index 4d40e81..40a0d61 100644
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceInfo.java
+++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceInfo.java
@@ -21,8 +21,13 @@
 import java.util.UUID;
 
 /**
- * The class for UPnP service information.
- * @hide
+ * A class for storing Upnp service information that is advertised
+ * over a Wi-Fi peer-to-peer setup.
+ *
+ * {@see android.net.wifi.p2p.WifiP2pManager#addLocalService}
+ * {@see android.net.wifi.p2p.WifiP2pManager#removeLocalService}
+ * {@see WifiP2pServiceInfo}
+ * {@see WifiP2pDnsSdServiceInfo}
  */
 public class WifiP2pUpnpServiceInfo extends WifiP2pServiceInfo {
 
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceRequest.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceRequest.java
index b97637a..b5cf144 100644
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceRequest.java
+++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceRequest.java
@@ -16,9 +16,15 @@
 
 package android.net.wifi.p2p.nsd;
 
+import android.net.wifi.p2p.WifiP2pManager;
+
 /**
- * The class for a request of upnp service discovery.
- * @hide
+ * A class for creating a Upnp service discovery request for use with
+ * {@link WifiP2pManager#addServiceRequest} and {@link WifiP2pManager#removeServiceRequest}
+ *
+ * {@see WifiP2pManager}
+ * {@see WifiP2pServiceRequest}
+ * {@see WifiP2pDnsSdServiceRequest}
  */
 public class WifiP2pUpnpServiceRequest extends WifiP2pServiceRequest {