am 2988436b: am fb28bd15: Merge "Docs: Add TOC page for Wearable samples" into lmp-dev

* commit '2988436b65d5fbabff8a6b9cb7c9b56dcd31b84a':
  Docs: Add TOC page for Wearable samples
diff --git a/api/current.txt b/api/current.txt
index d66867b..074175b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3052,9 +3052,10 @@
     method public android.graphics.Rect evaluate(float, android.graphics.Rect, android.graphics.Rect);
   }
 
-  public class StateListAnimator {
+  public class StateListAnimator implements java.lang.Cloneable {
     ctor public StateListAnimator();
     method public void addState(int[], android.animation.Animator);
+    method public android.animation.StateListAnimator clone();
     method public void jumpToCurrentState();
   }
 
@@ -7432,6 +7433,7 @@
     method public java.lang.Object clone();
     method public android.content.Intent cloneFilter();
     method public static android.content.Intent createChooser(android.content.Intent, java.lang.CharSequence);
+    method public static android.content.Intent createChooser(android.content.Intent, java.lang.CharSequence, android.content.IntentSender);
     method public int describeContents();
     method public int fillIn(android.content.Intent, int);
     method public boolean filterEquals(android.content.Intent);
@@ -7707,6 +7709,8 @@
     field public static final java.lang.String EXTRA_CHANGED_COMPONENT_NAME_LIST = "android.intent.extra.changed_component_name_list";
     field public static final java.lang.String EXTRA_CHANGED_PACKAGE_LIST = "android.intent.extra.changed_package_list";
     field public static final java.lang.String EXTRA_CHANGED_UID_LIST = "android.intent.extra.changed_uid_list";
+    field public static final java.lang.String EXTRA_CHOSEN_COMPONENT = "android.intent.extra.CHOSEN_COMPONENT";
+    field public static final java.lang.String EXTRA_CHOSEN_COMPONENT_INTENT_SENDER = "android.intent.extra.CHOSEN_COMPONENT_INTENT_SENDER";
     field public static final java.lang.String EXTRA_DATA_REMOVED = "android.intent.extra.DATA_REMOVED";
     field public static final java.lang.String EXTRA_DOCK_STATE = "android.intent.extra.DOCK_STATE";
     field public static final int EXTRA_DOCK_STATE_CAR = 2; // 0x2
@@ -8621,6 +8625,7 @@
     method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
     method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
     method public android.graphics.drawable.Drawable loadLogo(android.content.pm.PackageManager);
+    method public android.graphics.drawable.Drawable loadUnbadgedIcon(android.content.pm.PackageManager);
     method public android.content.res.XmlResourceParser loadXmlMetaData(android.content.pm.PackageManager, java.lang.String);
     method public void writeToParcel(android.os.Parcel, int);
     field public int banner;
@@ -17030,6 +17035,7 @@
   }
 
   public class Network implements android.os.Parcelable {
+    method public void bindSocket(java.net.DatagramSocket) throws java.io.IOException;
     method public void bindSocket(java.net.Socket) throws java.io.IOException;
     method public int describeContents();
     method public java.net.InetAddress[] getAllByName(java.lang.String) throws java.net.UnknownHostException;
@@ -21399,6 +21405,7 @@
     field public static final int KITKAT = 19; // 0x13
     field public static final int KITKAT_WATCH = 20; // 0x14
     field public static final int LOLLIPOP = 21; // 0x15
+    field public static final int LOLLIPOP_MR1 = 22; // 0x16
   }
 
   public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
@@ -25582,6 +25589,10 @@
   public static final class Telephony.Mms.Intents {
     field public static final java.lang.String CONTENT_CHANGED_ACTION = "android.intent.action.CONTENT_CHANGED";
     field public static final java.lang.String DELETED_CONTENTS = "deleted_contents";
+    field public static final java.lang.String EXTRA_MMS_CONTENT_URI = "android.provider.Telephony.extra.MMS_CONTENT_URI";
+    field public static final java.lang.String EXTRA_MMS_LOCATION_URL = "android.provider.Telephony.extra.MMS_LOCATION_URL";
+    field public static final java.lang.String MMS_DOWNLOAD_ACTION = "android.provider.Telephony.MMS_DOWNLOAD";
+    field public static final java.lang.String MMS_SEND_ACTION = "android.provider.Telephony.MMS_SEND";
   }
 
   public static final class Telephony.Mms.Outbox implements android.provider.Telephony.BaseMmsColumns {
@@ -25686,8 +25697,10 @@
     field public static final java.lang.String SMS_CB_RECEIVED_ACTION = "android.provider.Telephony.SMS_CB_RECEIVED";
     field public static final java.lang.String SMS_DELIVER_ACTION = "android.provider.Telephony.SMS_DELIVER";
     field public static final java.lang.String SMS_EMERGENCY_CB_RECEIVED_ACTION = "android.provider.Telephony.SMS_EMERGENCY_CB_RECEIVED";
+    field public static final java.lang.String SMS_FILTER_ACTION = "android.provider.Telephony.SMS_FILTER";
     field public static final java.lang.String SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED";
     field public static final java.lang.String SMS_REJECTED_ACTION = "android.provider.Telephony.SMS_REJECTED";
+    field public static final java.lang.String SMS_SEND_ACTION = "android.provider.Telephony.SMS_SEND";
     field public static final java.lang.String SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION = "android.provider.Telephony.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED";
     field public static final java.lang.String WAP_PUSH_DELIVER_ACTION = "android.provider.Telephony.WAP_PUSH_DELIVER";
     field public static final java.lang.String WAP_PUSH_RECEIVED_ACTION = "android.provider.Telephony.WAP_PUSH_RECEIVED";
@@ -28041,16 +28054,335 @@
 
 package android.telecom {
 
+  public final class AudioState implements android.os.Parcelable {
+    ctor public AudioState(boolean, int, int);
+    ctor public AudioState(android.telecom.AudioState);
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final int ROUTE_BLUETOOTH = 2; // 0x2
+    field public static final int ROUTE_EARPIECE = 1; // 0x1
+    field public static final int ROUTE_SPEAKER = 8; // 0x8
+    field public static final int ROUTE_WIRED_HEADSET = 4; // 0x4
+    field public static final int ROUTE_WIRED_OR_EARPIECE = 5; // 0x5
+    field public final boolean isMuted;
+    field public final int route;
+    field public final int supportedRouteMask;
+  }
+
+  public abstract class Conference {
+    ctor public Conference(android.telecom.PhoneAccountHandle);
+    method public final boolean addConnection(android.telecom.Connection);
+    method public final void destroy();
+    method public final android.telecom.AudioState getAudioState();
+    method public final int getCapabilities();
+    method public final java.util.List<android.telecom.Connection> getConferenceableConnections();
+    method public final java.util.List<android.telecom.Connection> getConnections();
+    method public final android.telecom.PhoneAccountHandle getPhoneAccountHandle();
+    method public final int getState();
+    method public void onAudioStateChanged(android.telecom.AudioState);
+    method public void onDisconnect();
+    method public void onHold();
+    method public void onMerge(android.telecom.Connection);
+    method public void onMerge();
+    method public void onPlayDtmfTone(char);
+    method public void onSeparate(android.telecom.Connection);
+    method public void onStopDtmfTone();
+    method public void onSwap();
+    method public void onUnhold();
+    method public final void removeConnection(android.telecom.Connection);
+    method public final void setActive();
+    method public final void setCapabilities(int);
+    method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
+    method public final void setDisconnected(android.telecom.DisconnectCause);
+    method public final void setOnHold();
+  }
+
+  public abstract class Connection {
+    ctor public Connection();
+    method public static android.telecom.Connection createCanceledConnection();
+    method public static android.telecom.Connection createFailedConnection(android.telecom.DisconnectCause);
+    method public final void destroy();
+    method public final android.net.Uri getAddress();
+    method public final int getAddressPresentation();
+    method public final boolean getAudioModeIsVoip();
+    method public final android.telecom.AudioState getAudioState();
+    method public final int getCallCapabilities();
+    method public final java.lang.String getCallerDisplayName();
+    method public final int getCallerDisplayNamePresentation();
+    method public final android.telecom.Conference getConference();
+    method public final java.util.List<android.telecom.Connection> getConferenceableConnections();
+    method public final android.telecom.DisconnectCause getDisconnectCause();
+    method public final int getState();
+    method public final android.telecom.StatusHints getStatusHints();
+    method public final boolean isRingbackRequested();
+    method public void onAbort();
+    method public void onAnswer();
+    method public void onAudioStateChanged(android.telecom.AudioState);
+    method public void onConferenceChanged();
+    method public void onDisconnect();
+    method public void onHold();
+    method public void onPlayDtmfTone(char);
+    method public void onPostDialContinue(boolean);
+    method public void onReject();
+    method public void onSeparate();
+    method public void onStateChanged(int);
+    method public void onStopDtmfTone();
+    method public void onUnhold();
+    method public final void setActive();
+    method public final void setAddress(android.net.Uri, int);
+    method public final void setAudioModeIsVoip(boolean);
+    method public final void setCallCapabilities(int);
+    method public final void setCallerDisplayName(java.lang.String, int);
+    method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
+    method public final void setConnectionService(android.telecom.ConnectionService);
+    method public final void setDialing();
+    method public final void setDisconnected(android.telecom.DisconnectCause);
+    method public final void setInitialized();
+    method public final void setInitializing();
+    method public final void setOnHold();
+    method public final void setPostDialWait(java.lang.String);
+    method public final void setRingbackRequested(boolean);
+    method public final void setRinging();
+    method public final void setStatusHints(android.telecom.StatusHints);
+    method public static java.lang.String stateToString(int);
+    field public static final int STATE_ACTIVE = 4; // 0x4
+    field public static final int STATE_DIALING = 3; // 0x3
+    field public static final int STATE_DISCONNECTED = 6; // 0x6
+    field public static final int STATE_HOLDING = 5; // 0x5
+    field public static final int STATE_INITIALIZING = 0; // 0x0
+    field public static final int STATE_NEW = 1; // 0x1
+    field public static final int STATE_RINGING = 2; // 0x2
+  }
+
+  public final class ConnectionRequest implements android.os.Parcelable {
+    ctor public ConnectionRequest(android.telecom.PhoneAccountHandle, android.net.Uri, android.os.Bundle);
+    method public int describeContents();
+    method public android.telecom.PhoneAccountHandle getAccountHandle();
+    method public android.net.Uri getAddress();
+    method public android.os.Bundle getExtras();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public abstract class ConnectionService extends android.app.Service {
+    ctor public ConnectionService();
+    method public final void addConference(android.telecom.Conference);
+    method public final void conferenceRemoteConnections(android.telecom.RemoteConnection, android.telecom.RemoteConnection);
+    method public final android.telecom.RemoteConnection createRemoteIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public final android.telecom.RemoteConnection createRemoteOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public final java.util.Collection<android.telecom.Connection> getAllConnections();
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public void onConference(android.telecom.Connection, android.telecom.Connection);
+    method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public void onRemoteConferenceAdded(android.telecom.RemoteConference);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.ConnectionService";
+  }
+
+  public final class DisconnectCause implements android.os.Parcelable {
+    ctor public DisconnectCause(int);
+    ctor public DisconnectCause(int, java.lang.String);
+    ctor public DisconnectCause(int, java.lang.CharSequence, java.lang.CharSequence, java.lang.String);
+    ctor public DisconnectCause(int, java.lang.CharSequence, java.lang.CharSequence, java.lang.String, int);
+    method public int describeContents();
+    method public int getCode();
+    method public java.lang.CharSequence getDescription();
+    method public java.lang.CharSequence getLabel();
+    method public java.lang.String getReason();
+    method public int getTone();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int BUSY = 7; // 0x7
+    field public static final int CANCELED = 4; // 0x4
+    field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final int ERROR = 1; // 0x1
+    field public static final int LOCAL = 2; // 0x2
+    field public static final int MISSED = 5; // 0x5
+    field public static final int OTHER = 9; // 0x9
+    field public static final int REJECTED = 6; // 0x6
+    field public static final int REMOTE = 3; // 0x3
+    field public static final int RESTRICTED = 8; // 0x8
+    field public static final int UNKNOWN = 0; // 0x0
+  }
+
+  public class GatewayInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.net.Uri getGatewayAddress();
+    method public java.lang.String getGatewayProviderPackageName();
+    method public android.net.Uri getOriginalAddress();
+    method public boolean isEmpty();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public class PhoneAccount implements android.os.Parcelable {
+    method public static android.telecom.PhoneAccount.Builder builder(android.telecom.PhoneAccountHandle, java.lang.CharSequence);
+    method public int describeContents();
+    method public android.telecom.PhoneAccountHandle getAccountHandle();
+    method public android.net.Uri getAddress();
+    method public int getCapabilities();
+    method public android.graphics.drawable.Drawable getIcon(android.content.Context);
+    method public int getIconResId();
+    method public java.lang.CharSequence getLabel();
+    method public java.lang.CharSequence getShortDescription();
+    method public android.net.Uri getSubscriptionAddress();
+    method public java.util.List<java.lang.String> getSupportedUriSchemes();
+    method public boolean hasCapabilities(int);
+    method public boolean supportsUriScheme(java.lang.String);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1
+    field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10
+    field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
+    field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final java.lang.String SCHEME_SIP = "sip";
+    field public static final java.lang.String SCHEME_TEL = "tel";
+    field public static final java.lang.String SCHEME_VOICEMAIL = "voicemail";
+  }
+
+  public static class PhoneAccount.Builder {
+    ctor public PhoneAccount.Builder(android.telecom.PhoneAccountHandle, java.lang.CharSequence);
+    ctor public PhoneAccount.Builder(android.telecom.PhoneAccount);
+    method public android.telecom.PhoneAccount build();
+    method public android.telecom.PhoneAccount.Builder setAddress(android.net.Uri);
+    method public android.telecom.PhoneAccount.Builder setCapabilities(int);
+    method public android.telecom.PhoneAccount.Builder setIconResId(int);
+    method public android.telecom.PhoneAccount.Builder setShortDescription(java.lang.CharSequence);
+    method public android.telecom.PhoneAccount.Builder setSubscriptionAddress(android.net.Uri);
+    method public android.telecom.PhoneAccount.Builder setSupportedUriSchemes(java.util.List<java.lang.String>);
+  }
+
+  public class PhoneAccountHandle implements android.os.Parcelable {
+    ctor public PhoneAccountHandle(android.content.ComponentName, java.lang.String);
+    method public int describeContents();
+    method public android.content.ComponentName getComponentName();
+    method public java.lang.String getId();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public final class PhoneCapabilities {
+    method public static java.lang.String toString(int);
+    field public static final int ADD_CALL = 16; // 0x10
+    field public static final int ALL = 12543; // 0x30ff
+    field public static final int DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
+    field public static final int HOLD = 1; // 0x1
+    field public static final int MANAGE_CONFERENCE = 128; // 0x80
+    field public static final int MERGE_CONFERENCE = 4; // 0x4
+    field public static final int MUTE = 64; // 0x40
+    field public static final int RESPOND_VIA_TEXT = 32; // 0x20
+    field public static final int SEPARATE_FROM_CONFERENCE = 4096; // 0x1000
+    field public static final int SUPPORT_HOLD = 2; // 0x2
+    field public static final int SWAP_CONFERENCE = 8; // 0x8
+  }
+
+  public final class RemoteConference {
+    method public void disconnect();
+    method public final int getCallCapabilities();
+    method public java.util.List<android.telecom.RemoteConnection> getConferenceableConnections();
+    method public final java.util.List<android.telecom.RemoteConnection> getConnections();
+    method public android.telecom.DisconnectCause getDisconnectCause();
+    method public final int getState();
+    method public void hold();
+    method public void merge();
+    method public void playDtmfTone(char);
+    method public final void registerCallback(android.telecom.RemoteConference.Callback);
+    method public void separate(android.telecom.RemoteConnection);
+    method public void setAudioState(android.telecom.AudioState);
+    method public void stopDtmfTone();
+    method public void swap();
+    method public void unhold();
+    method public final void unregisterCallback(android.telecom.RemoteConference.Callback);
+  }
+
+  public static abstract class RemoteConference.Callback {
+    ctor public RemoteConference.Callback();
+    method public void onCapabilitiesChanged(android.telecom.RemoteConference, int);
+    method public void onConferenceableConnectionsChanged(android.telecom.RemoteConference, java.util.List<android.telecom.RemoteConnection>);
+    method public void onConnectionAdded(android.telecom.RemoteConference, android.telecom.RemoteConnection);
+    method public void onConnectionRemoved(android.telecom.RemoteConference, android.telecom.RemoteConnection);
+    method public void onDestroyed(android.telecom.RemoteConference);
+    method public void onDisconnected(android.telecom.RemoteConference, android.telecom.DisconnectCause);
+    method public void onStateChanged(android.telecom.RemoteConference, int, int);
+  }
+
+  public final class RemoteConnection {
+    method public void abort();
+    method public void answer();
+    method public void disconnect();
+    method public android.net.Uri getAddress();
+    method public int getAddressPresentation();
+    method public int getCallCapabilities();
+    method public java.lang.CharSequence getCallerDisplayName();
+    method public int getCallerDisplayNamePresentation();
+    method public android.telecom.RemoteConference getConference();
+    method public java.util.List<android.telecom.RemoteConnection> getConferenceableConnections();
+    method public android.telecom.DisconnectCause getDisconnectCause();
+    method public int getState();
+    method public android.telecom.StatusHints getStatusHints();
+    method public void hold();
+    method public boolean isRingbackRequested();
+    method public boolean isVoipAudioMode();
+    method public void playDtmfTone(char);
+    method public void postDialContinue(boolean);
+    method public void registerCallback(android.telecom.RemoteConnection.Callback);
+    method public void reject();
+    method public void setAudioState(android.telecom.AudioState);
+    method public void stopDtmfTone();
+    method public void unhold();
+    method public void unregisterCallback(android.telecom.RemoteConnection.Callback);
+  }
+
+  public static abstract class RemoteConnection.Callback {
+    ctor public RemoteConnection.Callback();
+    method public void onAddressChanged(android.telecom.RemoteConnection, android.net.Uri, int);
+    method public void onCallCapabilitiesChanged(android.telecom.RemoteConnection, int);
+    method public void onCallerDisplayNameChanged(android.telecom.RemoteConnection, java.lang.String, int);
+    method public void onConferenceChanged(android.telecom.RemoteConnection, android.telecom.RemoteConference);
+    method public void onConferenceableConnectionsChanged(android.telecom.RemoteConnection, java.util.List<android.telecom.RemoteConnection>);
+    method public void onDestroyed(android.telecom.RemoteConnection);
+    method public void onDisconnected(android.telecom.RemoteConnection, android.telecom.DisconnectCause);
+    method public void onPostDialWait(android.telecom.RemoteConnection, java.lang.String);
+    method public void onRingbackRequested(android.telecom.RemoteConnection, boolean);
+    method public void onStateChanged(android.telecom.RemoteConnection, int);
+    method public void onStatusHintsChanged(android.telecom.RemoteConnection, android.telecom.StatusHints);
+    method public void onVoipAudioChanged(android.telecom.RemoteConnection, boolean);
+  }
+
+  public final class StatusHints implements android.os.Parcelable {
+    ctor public StatusHints(android.content.ComponentName, java.lang.CharSequence, int, android.os.Bundle);
+    method public int describeContents();
+    method public android.os.Bundle getExtras();
+    method public android.graphics.drawable.Drawable getIcon(android.content.Context);
+    method public int getIconResId();
+    method public java.lang.CharSequence getLabel();
+    method public android.content.ComponentName getPackageName();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
   public class TelecomManager {
+    method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
     method public void cancelMissedCallsNotification();
+    method public void clearAccounts();
+    method public android.telecom.PhoneAccountHandle getConnectionManager();
+    method public android.telecom.PhoneAccount getPhoneAccount(android.telecom.PhoneAccountHandle);
+    method public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsForPackage();
     method public boolean handleMmi(java.lang.String);
+    method public boolean hasMultipleCallCapableAccounts();
     method public boolean isInCall();
+    method public void registerPhoneAccount(android.telecom.PhoneAccount);
     method public void showInCallScreen(boolean);
+    method public void unregisterPhoneAccount(android.telecom.PhoneAccountHandle);
+    field public static final java.lang.String ACTION_CHANGE_PHONE_ACCOUNTS = "android.telecom.action.CHANGE_PHONE_ACCOUNTS";
+    field public static final java.lang.String ACTION_CONNECTION_SERVICE_CONFIGURE = "android.telecom.action.CONNECTION_SERVICE_CONFIGURE";
     field public static final java.lang.String ACTION_SHOW_CALL_SETTINGS = "android.telecom.action.SHOW_CALL_SETTINGS";
     field public static final char DTMF_CHARACTER_PAUSE = 44; // 0x002c ','
     field public static final char DTMF_CHARACTER_WAIT = 59; // 0x003b ';'
+    field public static final java.lang.String EXTRA_CALL_BACK_NUMBER = "android.telecom.extra.CALL_BACK_NUMBER";
     field public static final java.lang.String EXTRA_CALL_DISCONNECT_CAUSE = "android.telecom.extra.CALL_DISCONNECT_CAUSE";
     field public static final java.lang.String EXTRA_CALL_DISCONNECT_MESSAGE = "android.telecom.extra.CALL_DISCONNECT_MESSAGE";
+    field public static final java.lang.String EXTRA_CONNECTION_SERVICE = "android.telecom.extra.CONNECTION_SERVICE";
+    field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.PHONE_ACCOUNT_HANDLE";
     field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE";
     field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
     field public static final java.lang.String GATEWAY_PROVIDER_PACKAGE = "android.telecom.extra.GATEWAY_PROVIDER_PACKAGE";
@@ -28372,11 +28704,16 @@
     method public static android.telephony.SmsManager getDefault();
     method public static android.telephony.SmsManager getSmsManagerForSubscriber(long);
     method public long getSubId();
+    method public void injectSmsPdu(byte[], java.lang.String, android.app.PendingIntent);
     method public void sendDataMessage(java.lang.String, java.lang.String, short, byte[], android.app.PendingIntent, android.app.PendingIntent);
     method public void sendMultimediaMessage(android.content.Context, android.net.Uri, java.lang.String, android.os.Bundle, android.app.PendingIntent);
     method public void sendMultipartTextMessage(java.lang.String, java.lang.String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>);
     method public void sendTextMessage(java.lang.String, java.lang.String, java.lang.String, android.app.PendingIntent, android.app.PendingIntent);
+    method public void updateMmsDownloadStatus(android.content.Context, int, int, android.net.Uri);
+    method public void updateMmsSendStatus(android.content.Context, int, byte[], int, android.net.Uri);
+    method public void updateSmsSendStatus(int, boolean);
     field public static final java.lang.String EXTRA_MMS_DATA = "android.telephony.extra.MMS_DATA";
+    field public static final java.lang.String EXTRA_MMS_HTTP_STATUS = "android.telephony.extra.MMS_HTTP_STATUS";
     field public static final java.lang.String MMS_CONFIG_ALIAS_ENABLED = "aliasEnabled";
     field public static final java.lang.String MMS_CONFIG_ALIAS_MAX_CHARS = "aliasMaxChars";
     field public static final java.lang.String MMS_CONFIG_ALIAS_MIN_CHARS = "aliasMinChars";
@@ -28549,6 +28886,7 @@
     method public java.lang.String getSubscriberId();
     method public java.lang.String getVoiceMailAlphaTag();
     method public java.lang.String getVoiceMailNumber();
+    method public int hasCarrierPrivileges();
     method public boolean hasIccCard();
     method public boolean iccCloseLogicalChannel(int);
     method public byte[] iccExchangeSimIO(int, int, int, int, int, java.lang.String);
@@ -28559,11 +28897,18 @@
     method public boolean isSmsCapable();
     method public void listen(android.telephony.PhoneStateListener, int);
     method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
+    method public boolean setGlobalPreferredNetworkType();
+    method public void setLine1NumberForDisplay(java.lang.String, java.lang.String);
+    method public boolean setOperatorBrandOverride(java.lang.String);
     field public static final java.lang.String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
     field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
     field public static final int CALL_STATE_IDLE = 0; // 0x0
     field public static final int CALL_STATE_OFFHOOK = 2; // 0x2
     field public static final int CALL_STATE_RINGING = 1; // 0x1
+    field public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2; // 0xfffffffe
+    field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1
+    field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0
+    field public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; // 0xffffffff
     field public static final int DATA_ACTIVITY_DORMANT = 4; // 0x4
     field public static final int DATA_ACTIVITY_IN = 1; // 0x1
     field public static final int DATA_ACTIVITY_INOUT = 3; // 0x3
@@ -34569,6 +34914,7 @@
     field public static final int FLAG_HARDWARE_ACCELERATED = 16777216; // 0x1000000
     field public static final int FLAG_IGNORE_CHEEK_PRESSES = 32768; // 0x8000
     field public static final int FLAG_KEEP_SCREEN_ON = 128; // 0x80
+    field public static final int FLAG_LAYOUT_ATTACHED_IN_DECOR = 1073741824; // 0x40000000
     field public static final int FLAG_LAYOUT_INSET_DECOR = 65536; // 0x10000
     field public static final int FLAG_LAYOUT_IN_OVERSCAN = 33554432; // 0x2000000
     field public static final int FLAG_LAYOUT_IN_SCREEN = 256; // 0x100
@@ -35083,13 +35429,13 @@
 
 package android.view.animation {
 
-  public class AccelerateDecelerateInterpolator implements android.view.animation.Interpolator {
+  public class AccelerateDecelerateInterpolator extends android.view.animation.BaseInterpolator {
     ctor public AccelerateDecelerateInterpolator();
     ctor public AccelerateDecelerateInterpolator(android.content.Context, android.util.AttributeSet);
     method public float getInterpolation(float);
   }
 
-  public class AccelerateInterpolator implements android.view.animation.Interpolator {
+  public class AccelerateInterpolator extends android.view.animation.BaseInterpolator {
     ctor public AccelerateInterpolator();
     ctor public AccelerateInterpolator(float);
     ctor public AccelerateInterpolator(android.content.Context, android.util.AttributeSet);
@@ -35191,14 +35537,14 @@
     method public static android.view.animation.Animation makeOutAnimation(android.content.Context, boolean);
   }
 
-  public class AnticipateInterpolator implements android.view.animation.Interpolator {
+  public class AnticipateInterpolator extends android.view.animation.BaseInterpolator {
     ctor public AnticipateInterpolator();
     ctor public AnticipateInterpolator(float);
     ctor public AnticipateInterpolator(android.content.Context, android.util.AttributeSet);
     method public float getInterpolation(float);
   }
 
-  public class AnticipateOvershootInterpolator implements android.view.animation.Interpolator {
+  public class AnticipateOvershootInterpolator extends android.view.animation.BaseInterpolator {
     ctor public AnticipateOvershootInterpolator();
     ctor public AnticipateOvershootInterpolator(float);
     ctor public AnticipateOvershootInterpolator(float, float);
@@ -35206,19 +35552,23 @@
     method public float getInterpolation(float);
   }
 
-  public class BounceInterpolator implements android.view.animation.Interpolator {
+  public abstract class BaseInterpolator implements android.view.animation.Interpolator {
+    ctor public BaseInterpolator();
+  }
+
+  public class BounceInterpolator extends android.view.animation.BaseInterpolator {
     ctor public BounceInterpolator();
     ctor public BounceInterpolator(android.content.Context, android.util.AttributeSet);
     method public float getInterpolation(float);
   }
 
-  public class CycleInterpolator implements android.view.animation.Interpolator {
+  public class CycleInterpolator extends android.view.animation.BaseInterpolator {
     ctor public CycleInterpolator(float);
     ctor public CycleInterpolator(android.content.Context, android.util.AttributeSet);
     method public float getInterpolation(float);
   }
 
-  public class DecelerateInterpolator implements android.view.animation.Interpolator {
+  public class DecelerateInterpolator extends android.view.animation.BaseInterpolator {
     ctor public DecelerateInterpolator();
     ctor public DecelerateInterpolator(float);
     ctor public DecelerateInterpolator(android.content.Context, android.util.AttributeSet);
@@ -35293,20 +35643,20 @@
     field public int index;
   }
 
-  public class LinearInterpolator implements android.view.animation.Interpolator {
+  public class LinearInterpolator extends android.view.animation.BaseInterpolator {
     ctor public LinearInterpolator();
     ctor public LinearInterpolator(android.content.Context, android.util.AttributeSet);
     method public float getInterpolation(float);
   }
 
-  public class OvershootInterpolator implements android.view.animation.Interpolator {
+  public class OvershootInterpolator extends android.view.animation.BaseInterpolator {
     ctor public OvershootInterpolator();
     ctor public OvershootInterpolator(float);
     ctor public OvershootInterpolator(android.content.Context, android.util.AttributeSet);
     method public float getInterpolation(float);
   }
 
-  public class PathInterpolator implements android.view.animation.Interpolator {
+  public class PathInterpolator extends android.view.animation.BaseInterpolator {
     ctor public PathInterpolator(android.graphics.Path);
     ctor public PathInterpolator(float, float);
     ctor public PathInterpolator(float, float, float, float);
@@ -37791,6 +38141,7 @@
   public class PopupMenu {
     ctor public PopupMenu(android.content.Context, android.view.View);
     ctor public PopupMenu(android.content.Context, android.view.View, int);
+    ctor public PopupMenu(android.content.Context, android.view.View, int, int, int);
     method public void dismiss();
     method public android.view.View.OnTouchListener getDragToOpenListener();
     method public android.view.Menu getMenu();
@@ -37831,6 +38182,7 @@
     method public int getSoftInputMode();
     method public int getWidth();
     method public boolean isAboveAnchor();
+    method public boolean isAttachedInDecor();
     method public boolean isClippingEnabled();
     method public boolean isFocusable();
     method public boolean isOutsideTouchable();
@@ -37838,6 +38190,7 @@
     method public boolean isSplitTouchEnabled();
     method public boolean isTouchable();
     method public void setAnimationStyle(int);
+    method public void setAttachedInDecor(boolean);
     method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
     method public void setClippingEnabled(boolean);
     method public void setContentView(android.view.View);
diff --git a/cmds/app_process/Android.mk b/cmds/app_process/Android.mk
index 74a2f7b..1ca14a6 100644
--- a/cmds/app_process/Android.mk
+++ b/cmds/app_process/Android.mk
@@ -2,10 +2,18 @@
 
 include $(CLEAR_VARS)
 
+# TODO: Trying to link libsigchain as a static library prevents
+# static linker from exporting necessary symbols. So as a workaround
+# we use sigchain.o
 LOCAL_SRC_FILES:= \
-	app_main.cpp
+	app_main.cpp \
+	sigchain_proxy.cpp
+
+LOCAL_LDFLAGS := -Wl,--version-script,art/sigchainlib/version-script.txt -Wl,--export-dynamic
+LOCAL_CPPFLAGS := -std=c++11 -Iart
 
 LOCAL_SHARED_LIBRARIES := \
+	libdl \
 	libcutils \
 	libutils \
 	liblog \
@@ -28,8 +36,10 @@
 
 include $(CLEAR_VARS)
 
+# see comment above (~l5)
 LOCAL_SRC_FILES:= \
-	app_main.cpp
+	app_main.cpp \
+	sigchain_proxy.cpp
 
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
@@ -38,6 +48,9 @@
 	libbinder \
 	libandroid_runtime
 
+LOCAL_LDFLAGS := -ldl -Wl,--version-script,art/sigchainlib/version-script.txt -Wl,--export-dynamic
+LOCAL_CPPFLAGS := -std=c++11 -Iart
+
 LOCAL_MODULE := app_process__asan
 LOCAL_MODULE_TAGS := eng
 LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)/asan
diff --git a/cmds/app_process/sigchain_proxy.cpp b/cmds/app_process/sigchain_proxy.cpp
new file mode 100644
index 0000000..bb7a678
--- /dev/null
+++ b/cmds/app_process/sigchain_proxy.cpp
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sigchainlib/sigchain.cc"
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index 3720c81..da48709 100644
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -16,6 +16,8 @@
 
 package android.animation;
 
+import android.content.res.ConstantState;
+
 import java.util.ArrayList;
 
 /**
@@ -41,6 +43,18 @@
     boolean mPaused = false;
 
     /**
+     * A set of flags which identify the type of configuration changes that can affect this
+     * Animator. Used by the Animator cache.
+     */
+    int mChangingConfigurations = 0;
+
+    /**
+     * If this animator is inflated from a constant state, keep a reference to it so that
+     * ConstantState will not be garbage collected until this animator is collected
+     */
+    private AnimatorConstantState mConstantState;
+
+    /**
      * Starts this animation. If the animation has a nonzero startDelay, the animation will start
      * running after that delay elapses. A non-delayed animation will have its initial
      * value(s) set immediately, followed by calls to
@@ -295,25 +309,71 @@
         }
     }
 
+    /**
+     * Return a mask of the configuration parameters for which this animator may change, requiring
+     * that it should be re-created from Resources. The default implementation returns whatever
+     * value was provided through setChangingConfigurations(int) or 0 by default.
+     *
+     * @return Returns a mask of the changing configuration parameters, as defined by
+     * {@link android.content.pm.ActivityInfo}.
+     * @see android.content.pm.ActivityInfo
+     * @hide
+     */
+    public int getChangingConfigurations() {
+        return mChangingConfigurations;
+    }
+
+    /**
+     * Set a mask of the configuration parameters for which this animator may change, requiring
+     * that it be re-created from resource.
+     *
+     * @param configs A mask of the changing configuration parameters, as
+     * defined by {@link android.content.pm.ActivityInfo}.
+     *
+     * @see android.content.pm.ActivityInfo
+     * @hide
+     */
+    public void setChangingConfigurations(int configs) {
+        mChangingConfigurations = configs;
+    }
+
+    /**
+     * Sets the changing configurations value to the union of the current changing configurations
+     * and the provided configs.
+     * This method is called while loading the animator.
+     * @hide
+     */
+    public void appendChangingConfigurations(int configs) {
+        mChangingConfigurations |= configs;
+    }
+
+    /**
+     * Return a {@link android.content.res.ConstantState} instance that holds the shared state of
+     * this Animator.
+     * <p>
+     * This constant state is used to create new instances of this animator when needed, instead
+     * of re-loading it from resources. Default implementation creates a new
+     * {@link AnimatorConstantState}. You can override this method to provide your custom logic or
+     * return null if you don't want this animator to be cached.
+     *
+     * @return The ConfigurationBoundResourceCache.BaseConstantState associated to this Animator.
+     * @see android.content.res.ConstantState
+     * @see #clone()
+     * @hide
+     */
+    public ConstantState<Animator> createConstantState() {
+        return new AnimatorConstantState(this);
+    }
+
     @Override
     public Animator clone() {
         try {
             final Animator anim = (Animator) super.clone();
             if (mListeners != null) {
-                ArrayList<AnimatorListener> oldListeners = mListeners;
-                anim.mListeners = new ArrayList<AnimatorListener>();
-                int numListeners = oldListeners.size();
-                for (int i = 0; i < numListeners; ++i) {
-                    anim.mListeners.add(oldListeners.get(i));
-                }
+                anim.mListeners = new ArrayList<AnimatorListener>(mListeners);
             }
             if (mPauseListeners != null) {
-                ArrayList<AnimatorPauseListener> oldListeners = mPauseListeners;
-                anim.mPauseListeners = new ArrayList<AnimatorPauseListener>();
-                int numListeners = oldListeners.size();
-                for (int i = 0; i < numListeners; ++i) {
-                    anim.mPauseListeners.add(oldListeners.get(i));
-                }
+                anim.mPauseListeners = new ArrayList<AnimatorPauseListener>(mPauseListeners);
             }
             return anim;
         } catch (CloneNotSupportedException e) {
@@ -469,4 +529,35 @@
     public void setAllowRunningAsynchronously(boolean mayRunAsync) {
         // It is up to subclasses to support this, if they can.
     }
+
+    /**
+     * Creates a {@link ConstantState} which holds changing configurations information associated
+     * with the given Animator.
+     * <p>
+     * When {@link #newInstance()} is called, default implementation clones the Animator.
+     */
+    private static class AnimatorConstantState extends ConstantState<Animator> {
+
+        final Animator mAnimator;
+        int mChangingConf;
+
+        public AnimatorConstantState(Animator animator) {
+            mAnimator = animator;
+            // ensure a reference back to here so that constante state is not gc'ed.
+            mAnimator.mConstantState = this;
+            mChangingConf = mAnimator.getChangingConfigurations();
+        }
+
+        @Override
+        public int getChangingConfigurations() {
+            return mChangingConf;
+        }
+
+        @Override
+        public Animator newInstance() {
+            final Animator clone = mAnimator.clone();
+            clone.mConstantState = this;
+            return clone;
+        }
+    }
 }
diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java
index 25417ed..688d7e4 100644
--- a/core/java/android/animation/AnimatorInflater.java
+++ b/core/java/android/animation/AnimatorInflater.java
@@ -16,6 +16,8 @@
 package android.animation;
 
 import android.content.Context;
+import android.content.res.ConfigurationBoundResourceCache;
+import android.content.res.ConstantState;
 import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
 import android.content.res.Resources.Theme;
@@ -30,6 +32,8 @@
 import android.util.Xml;
 import android.view.InflateException;
 import android.view.animation.AnimationUtils;
+import android.view.animation.BaseInterpolator;
+import android.view.animation.Interpolator;
 
 import com.android.internal.R;
 
@@ -67,6 +71,9 @@
 
     private static final boolean DBG_ANIMATOR_INFLATER = false;
 
+    // used to calculate changing configs for resource references
+    private static final TypedValue sTmpTypedValue = new TypedValue();
+
     /**
      * Loads an {@link Animator} object from a resource
      *
@@ -98,11 +105,34 @@
     /** @hide */
     public static Animator loadAnimator(Resources resources, Theme theme, int id,
             float pathErrorScale) throws NotFoundException {
-
+        final ConfigurationBoundResourceCache<Animator> animatorCache = resources
+                .getAnimatorCache();
+        Animator animator = animatorCache.get(id, theme);
+        if (animator != null) {
+            if (DBG_ANIMATOR_INFLATER) {
+                Log.d(TAG, "loaded animator from cache, " + resources.getResourceName(id));
+            }
+            return animator;
+        } else if (DBG_ANIMATOR_INFLATER) {
+            Log.d(TAG, "cache miss for animator " + resources.getResourceName(id));
+        }
         XmlResourceParser parser = null;
         try {
             parser = resources.getAnimation(id);
-            return createAnimatorFromXml(resources, theme, parser, pathErrorScale);
+            animator = createAnimatorFromXml(resources, theme, parser, pathErrorScale);
+            if (animator != null) {
+                animator.appendChangingConfigurations(getChangingConfigs(resources, id));
+                final ConstantState<Animator> constantState = animator.createConstantState();
+                if (constantState != null) {
+                    if (DBG_ANIMATOR_INFLATER) {
+                        Log.d(TAG, "caching animator for res " + resources.getResourceName(id));
+                    }
+                    animatorCache.put(id, theme, constantState);
+                    // create a new animator so that cached version is never used by the user
+                    animator = constantState.newInstance(resources, theme);
+                }
+            }
+            return animator;
         } catch (XmlPullParserException ex) {
             Resources.NotFoundException rnf =
                     new Resources.NotFoundException("Can't load animation resource ID #0x" +
@@ -122,10 +152,29 @@
 
     public static StateListAnimator loadStateListAnimator(Context context, int id)
             throws NotFoundException {
+        final Resources resources = context.getResources();
+        final ConfigurationBoundResourceCache<StateListAnimator> cache = resources
+                .getStateListAnimatorCache();
+        final Theme theme = context.getTheme();
+        StateListAnimator animator = cache.get(id, theme);
+        if (animator != null) {
+            return animator;
+        }
         XmlResourceParser parser = null;
         try {
-            parser = context.getResources().getAnimation(id);
-            return createStateListAnimatorFromXml(context, parser, Xml.asAttributeSet(parser));
+            parser = resources.getAnimation(id);
+            animator = createStateListAnimatorFromXml(context, parser, Xml.asAttributeSet(parser));
+            if (animator != null) {
+                animator.appendChangingConfigurations(getChangingConfigs(resources, id));
+                final ConstantState<StateListAnimator> constantState = animator
+                        .createConstantState();
+                if (constantState != null) {
+                    cache.put(id, theme, constantState);
+                    // return a clone so that the animator in constant state is never used.
+                    animator = constantState.newInstance(resources, theme);
+                }
+            }
+            return animator;
         } catch (XmlPullParserException ex) {
             Resources.NotFoundException rnf =
                     new Resources.NotFoundException(
@@ -172,14 +221,13 @@
                         for (int i = 0; i < attributeCount; i++) {
                             int attrName = attributeSet.getAttributeNameResource(i);
                             if (attrName == R.attr.animation) {
-                                animator = loadAnimator(context,
-                                        attributeSet.getAttributeResourceValue(i, 0));
+                                final int animId = attributeSet.getAttributeResourceValue(i, 0);
+                                animator = loadAnimator(context, animId);
                             } else {
                                 states[stateIndex++] =
                                         attributeSet.getAttributeBooleanValue(i, false) ?
                                                 attrName : -attrName;
                             }
-
                         }
                         if (animator == null) {
                             animator = createAnimatorFromXml(context.getResources(),
@@ -192,7 +240,6 @@
                         }
                         stateListAnimator
                                 .addState(StateSet.trimStateSet(states, stateIndex), animator);
-
                     }
                     break;
             }
@@ -508,7 +555,6 @@
     private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser,
             AttributeSet attrs, AnimatorSet parent, int sequenceOrdering, float pixelSize)
             throws XmlPullParserException, IOException {
-
         Animator anim = null;
         ArrayList<Animator> childAnims = null;
 
@@ -537,8 +583,8 @@
                 } else {
                     a = res.obtainAttributes(attrs, R.styleable.AnimatorSet);
                 }
-                int ordering = a.getInt(R.styleable.AnimatorSet_ordering,
-                        TOGETHER);
+                anim.appendChangingConfigurations(a.getChangingConfigurations());
+                int ordering = a.getInt(R.styleable.AnimatorSet_ordering, TOGETHER);
                 createAnimatorFromXml(res, theme, parser, attrs, (AnimatorSet) anim, ordering,
                         pixelSize);
                 a.recycle();
@@ -565,7 +611,6 @@
                 parent.playSequentially(animsArray);
             }
         }
-
         return anim;
 
     }
@@ -591,7 +636,6 @@
     private static ValueAnimator loadAnimator(Resources res, Theme theme,
             AttributeSet attrs, ValueAnimator anim, float pathErrorScale)
             throws NotFoundException {
-
         TypedArray arrayAnimator = null;
         TypedArray arrayObjectAnimator = null;
 
@@ -609,25 +653,37 @@
             } else {
                 arrayObjectAnimator = res.obtainAttributes(attrs, R.styleable.PropertyAnimator);
             }
+            anim.appendChangingConfigurations(arrayObjectAnimator.getChangingConfigurations());
         }
 
         if (anim == null) {
             anim = new ValueAnimator();
         }
+        anim.appendChangingConfigurations(arrayAnimator.getChangingConfigurations());
 
         parseAnimatorFromTypeArray(anim, arrayAnimator, arrayObjectAnimator, pathErrorScale);
 
-        final int resID =
-                arrayAnimator.getResourceId(R.styleable.Animator_interpolator, 0);
+        final int resID = arrayAnimator.getResourceId(R.styleable.Animator_interpolator, 0);
         if (resID > 0) {
-            anim.setInterpolator(AnimationUtils.loadInterpolator(res, theme, resID));
+            final Interpolator interpolator = AnimationUtils.loadInterpolator(res, theme, resID);
+            if (interpolator instanceof BaseInterpolator) {
+                anim.appendChangingConfigurations(
+                        ((BaseInterpolator) interpolator).getChangingConfiguration());
+            }
+            anim.setInterpolator(interpolator);
         }
 
         arrayAnimator.recycle();
         if (arrayObjectAnimator != null) {
             arrayObjectAnimator.recycle();
         }
-
         return anim;
     }
+
+    private static int getChangingConfigs(Resources resources, int id) {
+        synchronized (sTmpTypedValue) {
+            resources.getValue(id, sTmpTypedValue, true);
+            return sTmpTypedValue.changingConfigurations;
+        }
+    }
 }
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 0aa8fdd..92762c3 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -241,6 +241,19 @@
     }
 
     /**
+     * @hide
+     */
+    @Override
+    public int getChangingConfigurations() {
+        int conf = super.getChangingConfigurations();
+        final int nodeCount = mNodes.size();
+        for (int i = 0; i < nodeCount; i ++) {
+            conf |= mNodes.get(i).animation.getChangingConfigurations();
+        }
+        return conf;
+    }
+
+    /**
      * Sets the TimeInterpolator for all current {@link #getChildAnimations() child animations}
      * of this AnimatorSet. The default value is null, which means that no interpolator
      * is set on this AnimatorSet. Setting the interpolator to any non-null value
@@ -628,23 +641,25 @@
          * manually, as we clone each Node (and its animation). The clone will then be sorted,
          * and will populate any appropriate lists, when it is started.
          */
+        final int nodeCount = mNodes.size();
         anim.mNeedsSort = true;
         anim.mTerminated = false;
         anim.mStarted = false;
         anim.mPlayingSet = new ArrayList<Animator>();
         anim.mNodeMap = new HashMap<Animator, Node>();
-        anim.mNodes = new ArrayList<Node>();
-        anim.mSortedNodes = new ArrayList<Node>();
+        anim.mNodes = new ArrayList<Node>(nodeCount);
+        anim.mSortedNodes = new ArrayList<Node>(nodeCount);
         anim.mReversible = mReversible;
         anim.mSetListener = null;
 
         // Walk through the old nodes list, cloning each node and adding it to the new nodemap.
         // One problem is that the old node dependencies point to nodes in the old AnimatorSet.
         // We need to track the old/new nodes in order to reconstruct the dependencies in the clone.
-        HashMap<Node, Node> nodeCloneMap = new HashMap<Node, Node>(); // <old, new>
-        for (Node node : mNodes) {
+
+        for (int n = 0; n < nodeCount; n++) {
+            final Node node = mNodes.get(n);
             Node nodeClone = node.clone();
-            nodeCloneMap.put(node, nodeClone);
+            node.mTmpClone = nodeClone;
             anim.mNodes.add(nodeClone);
             anim.mNodeMap.put(nodeClone.animation, nodeClone);
             // Clear out the dependencies in the clone; we'll set these up manually later
@@ -652,40 +667,50 @@
             nodeClone.tmpDependencies = null;
             nodeClone.nodeDependents = null;
             nodeClone.nodeDependencies = null;
+
             // clear out any listeners that were set up by the AnimatorSet; these will
             // be set up when the clone's nodes are sorted
-            ArrayList<AnimatorListener> cloneListeners = nodeClone.animation.getListeners();
+            final ArrayList<AnimatorListener> cloneListeners = nodeClone.animation.getListeners();
             if (cloneListeners != null) {
-                ArrayList<AnimatorListener> listenersToRemove = null;
-                for (AnimatorListener listener : cloneListeners) {
+                for (int i = cloneListeners.size() - 1; i >= 0; i--) {
+                    final AnimatorListener listener = cloneListeners.get(i);
                     if (listener instanceof AnimatorSetListener) {
-                        if (listenersToRemove == null) {
-                            listenersToRemove = new ArrayList<AnimatorListener>();
-                        }
-                        listenersToRemove.add(listener);
-                    }
-                }
-                if (listenersToRemove != null) {
-                    for (AnimatorListener listener : listenersToRemove) {
-                        cloneListeners.remove(listener);
+                        cloneListeners.remove(i);
                     }
                 }
             }
         }
         // Now that we've cloned all of the nodes, we're ready to walk through their
         // dependencies, mapping the old dependencies to the new nodes
-        for (Node node : mNodes) {
-            Node nodeClone = nodeCloneMap.get(node);
+        for (int n = 0; n < nodeCount; n++) {
+            final Node node = mNodes.get(n);
+            final Node clone = node.mTmpClone;
             if (node.dependencies != null) {
-                for (Dependency dependency : node.dependencies) {
-                    Node clonedDependencyNode = nodeCloneMap.get(dependency.node);
-                    Dependency cloneDependency = new Dependency(clonedDependencyNode,
+                clone.dependencies = new ArrayList<Dependency>(node.dependencies.size());
+                final int depSize = node.dependencies.size();
+                for (int i = 0; i < depSize; i ++) {
+                    final Dependency dependency = node.dependencies.get(i);
+                    Dependency cloneDependency = new Dependency(dependency.node.mTmpClone,
                             dependency.rule);
-                    nodeClone.addDependency(cloneDependency);
+                    clone.dependencies.add(cloneDependency);
+                }
+            }
+            if (node.nodeDependents != null) {
+                clone.nodeDependents = new ArrayList<Node>(node.nodeDependents.size());
+                for (Node dep : node.nodeDependents) {
+                    clone.nodeDependents.add(dep.mTmpClone);
+                }
+            }
+            if (node.nodeDependencies != null) {
+                clone.nodeDependencies = new ArrayList<Node>(node.nodeDependencies.size());
+                for (Node dep : node.nodeDependencies) {
+                    clone.nodeDependencies.add(dep.mTmpClone);
                 }
             }
         }
-
+        for (int n = 0; n < nodeCount; n++) {
+            mNodes.get(n).mTmpClone = null;
+        }
         return anim;
     }
 
@@ -1017,6 +1042,11 @@
         public boolean done = false;
 
         /**
+         * Temporary field to hold the clone in AnimatorSet#clone. Cleaned after clone is complete
+         */
+        private Node mTmpClone = null;
+
+        /**
          * Constructs the Node with the animation that it encapsulates. A Node has no
          * dependencies by default; dependencies are added via the addDependency()
          * method.
diff --git a/core/java/android/animation/FloatKeyframeSet.java b/core/java/android/animation/FloatKeyframeSet.java
index 12e5862..abac246 100644
--- a/core/java/android/animation/FloatKeyframeSet.java
+++ b/core/java/android/animation/FloatKeyframeSet.java
@@ -19,6 +19,7 @@
 import android.animation.Keyframe.FloatKeyframe;
 
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * This class holds a collection of FloatKeyframe objects and is called by ValueAnimator to calculate
@@ -47,8 +48,8 @@
 
     @Override
     public FloatKeyframeSet clone() {
-        ArrayList<Keyframe> keyframes = mKeyframes;
-        int numKeyframes = mKeyframes.size();
+        final List<Keyframe> keyframes = mKeyframes;
+        final int numKeyframes = mKeyframes.size();
         FloatKeyframe[] newKeyframes = new FloatKeyframe[numKeyframes];
         for (int i = 0; i < numKeyframes; ++i) {
             newKeyframes[i] = (FloatKeyframe) keyframes.get(i).clone();
diff --git a/core/java/android/animation/IntKeyframeSet.java b/core/java/android/animation/IntKeyframeSet.java
index 7a5b0ec..0ec5138 100644
--- a/core/java/android/animation/IntKeyframeSet.java
+++ b/core/java/android/animation/IntKeyframeSet.java
@@ -19,6 +19,7 @@
 import android.animation.Keyframe.IntKeyframe;
 
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * This class holds a collection of IntKeyframe objects and is called by ValueAnimator to calculate
@@ -47,7 +48,7 @@
 
     @Override
     public IntKeyframeSet clone() {
-        ArrayList<Keyframe> keyframes = mKeyframes;
+        List<Keyframe> keyframes = mKeyframes;
         int numKeyframes = mKeyframes.size();
         IntKeyframe[] newKeyframes = new IntKeyframe[numKeyframes];
         for (int i = 0; i < numKeyframes; ++i) {
diff --git a/core/java/android/animation/KeyframeSet.java b/core/java/android/animation/KeyframeSet.java
index 8d15db2..0e99bff 100644
--- a/core/java/android/animation/KeyframeSet.java
+++ b/core/java/android/animation/KeyframeSet.java
@@ -18,6 +18,8 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
+
 import android.animation.Keyframe.IntKeyframe;
 import android.animation.Keyframe.FloatKeyframe;
 import android.animation.Keyframe.ObjectKeyframe;
@@ -36,16 +38,16 @@
     Keyframe mFirstKeyframe;
     Keyframe mLastKeyframe;
     TimeInterpolator mInterpolator; // only used in the 2-keyframe case
-    ArrayList<Keyframe> mKeyframes; // only used when there are not 2 keyframes
+    List<Keyframe> mKeyframes; // only used when there are not 2 keyframes
     TypeEvaluator mEvaluator;
 
 
     public KeyframeSet(Keyframe... keyframes) {
         mNumKeyframes = keyframes.length;
-        mKeyframes = new ArrayList<Keyframe>();
-        mKeyframes.addAll(Arrays.asList(keyframes));
-        mFirstKeyframe = mKeyframes.get(0);
-        mLastKeyframe = mKeyframes.get(mNumKeyframes - 1);
+        // immutable list
+        mKeyframes = Arrays.asList(keyframes);
+        mFirstKeyframe = keyframes[0];
+        mLastKeyframe = keyframes[mNumKeyframes - 1];
         mInterpolator = mLastKeyframe.getInterpolator();
     }
 
@@ -57,7 +59,7 @@
     public void invalidateCache() {
     }
 
-    public ArrayList<Keyframe> getKeyframes() {
+    public List<Keyframe> getKeyframes() {
         return mKeyframes;
     }
 
@@ -177,9 +179,9 @@
 
     @Override
     public KeyframeSet clone() {
-        ArrayList<Keyframe> keyframes = mKeyframes;
+        List<Keyframe> keyframes = mKeyframes;
         int numKeyframes = mKeyframes.size();
-        Keyframe[] newKeyframes = new Keyframe[numKeyframes];
+        final Keyframe[] newKeyframes = new Keyframe[numKeyframes];
         for (int i = 0; i < numKeyframes; ++i) {
             newKeyframes[i] = keyframes.get(i).clone();
         }
diff --git a/core/java/android/animation/Keyframes.java b/core/java/android/animation/Keyframes.java
index 6611c6c..c921466 100644
--- a/core/java/android/animation/Keyframes.java
+++ b/core/java/android/animation/Keyframes.java
@@ -16,6 +16,7 @@
 package android.animation;
 
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * This interface abstracts a collection of Keyframe objects and is called by
@@ -62,7 +63,7 @@
      * @return A list of all Keyframes contained by this. This may return null if this is
      * not made up of Keyframes.
      */
-    ArrayList<Keyframe> getKeyframes();
+    List<Keyframe> getKeyframes();
 
     Keyframes clone();
 
diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java
index d372933..97426c3 100644
--- a/core/java/android/animation/PropertyValuesHolder.java
+++ b/core/java/android/animation/PropertyValuesHolder.java
@@ -27,6 +27,7 @@
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 /**
@@ -791,7 +792,7 @@
             // check to make sure that mProperty is on the class of target
             try {
                 Object testValue = null;
-                ArrayList<Keyframe> keyframes = mKeyframes.getKeyframes();
+                List<Keyframe> keyframes = mKeyframes.getKeyframes();
                 int keyframeCount = keyframes == null ? 0 : keyframes.size();
                 for (int i = 0; i < keyframeCount; i++) {
                     Keyframe kf = keyframes.get(i);
@@ -814,7 +815,7 @@
         if (mSetter == null) {
             setupSetter(targetClass);
         }
-        ArrayList<Keyframe> keyframes = mKeyframes.getKeyframes();
+        List<Keyframe> keyframes = mKeyframes.getKeyframes();
         int keyframeCount = keyframes == null ? 0 : keyframes.size();
         for (int i = 0; i < keyframeCount; i++) {
             Keyframe kf = keyframes.get(i);
@@ -890,7 +891,7 @@
      * @param target The object which holds the start values that should be set.
      */
     void setupStartValue(Object target) {
-        ArrayList<Keyframe> keyframes = mKeyframes.getKeyframes();
+        List<Keyframe> keyframes = mKeyframes.getKeyframes();
         if (!keyframes.isEmpty()) {
             setupValue(target, keyframes.get(0));
         }
@@ -905,7 +906,7 @@
      * @param target The object which holds the start values that should be set.
      */
     void setupEndValue(Object target) {
-        ArrayList<Keyframe> keyframes = mKeyframes.getKeyframes();
+        List<Keyframe> keyframes = mKeyframes.getKeyframes();
         if (!keyframes.isEmpty()) {
             setupValue(target, keyframes.get(keyframes.size() - 1));
         }
diff --git a/core/java/android/animation/StateListAnimator.java b/core/java/android/animation/StateListAnimator.java
index 7256a06..d49e914 100644
--- a/core/java/android/animation/StateListAnimator.java
+++ b/core/java/android/animation/StateListAnimator.java
@@ -16,6 +16,7 @@
 
 package android.animation;
 
+import android.content.res.ConstantState;
 import android.util.StateSet;
 import android.view.View;
 
@@ -44,25 +45,31 @@
  * @attr ref android.R.styleable#DrawableStates_state_pressed
  * @attr ref android.R.styleable#StateListAnimatorItem_animation
  */
-public class StateListAnimator {
+public class StateListAnimator implements Cloneable {
 
-    private final ArrayList<Tuple> mTuples = new ArrayList<Tuple>();
-
+    private ArrayList<Tuple> mTuples = new ArrayList<Tuple>();
     private Tuple mLastMatch = null;
-
     private Animator mRunningAnimator = null;
-
     private WeakReference<View> mViewRef;
+    private StateListAnimatorConstantState mConstantState;
+    private AnimatorListenerAdapter mAnimatorListener;
+    private int mChangingConfigurations;
 
-    private AnimatorListenerAdapter mAnimatorListener = new AnimatorListenerAdapter() {
-        @Override
-        public void onAnimationEnd(Animator animation) {
-            animation.setTarget(null);
-            if (mRunningAnimator == animation) {
-                mRunningAnimator = null;
+    public StateListAnimator() {
+        initAnimatorListener();
+    }
+
+    private void initAnimatorListener() {
+        mAnimatorListener = new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                animation.setTarget(null);
+                if (mRunningAnimator == animation) {
+                    mRunningAnimator = null;
+                }
             }
-        }
-    };
+        };
+    }
 
     /**
      * Associates the given animator with the provided drawable state specs so that it will be run
@@ -75,6 +82,7 @@
         Tuple tuple = new Tuple(specs, animator);
         tuple.mAnimator.addListener(mAnimatorListener);
         mTuples.add(tuple);
+        mChangingConfigurations |= animator.getChangingConfigurations();
     }
 
     /**
@@ -118,12 +126,35 @@
         for (int i = 0; i < size; i++) {
             mTuples.get(i).mAnimator.setTarget(null);
         }
-
         mViewRef = null;
         mLastMatch = null;
         mRunningAnimator = null;
     }
 
+    @Override
+    public StateListAnimator clone() {
+        try {
+            StateListAnimator clone = (StateListAnimator) super.clone();
+            clone.mTuples = new ArrayList<Tuple>(mTuples.size());
+            clone.mLastMatch = null;
+            clone.mRunningAnimator = null;
+            clone.mViewRef = null;
+            clone.mAnimatorListener = null;
+            clone.initAnimatorListener();
+            final int tupleSize = mTuples.size();
+            for (int i = 0; i < tupleSize; i++) {
+                final Tuple tuple = mTuples.get(i);
+                final Animator animatorClone = tuple.mAnimator.clone();
+                animatorClone.removeListener(mAnimatorListener);
+                clone.addState(tuple.mSpecs, animatorClone);
+            }
+            clone.setChangingConfigurations(getChangingConfigurations());
+            return clone;
+        } catch (CloneNotSupportedException e) {
+            throw new AssertionError("cannot clone state list animator", e);
+        }
+    }
+
     /**
      * Called by View
      * @hide
@@ -182,6 +213,63 @@
     }
 
     /**
+     * Return a mask of the configuration parameters for which this animator may change, requiring
+     * that it be re-created.  The default implementation returns whatever was provided through
+     * {@link #setChangingConfigurations(int)} or 0 by default.
+     *
+     * @return Returns a mask of the changing configuration parameters, as defined by
+     * {@link android.content.pm.ActivityInfo}.
+     *
+     * @see android.content.pm.ActivityInfo
+     * @hide
+     */
+    public int getChangingConfigurations() {
+        return mChangingConfigurations;
+    }
+
+    /**
+     * Set a mask of the configuration parameters for which this animator may change, requiring
+     * that it should be recreated from resources instead of being cloned.
+     *
+     * @param configs A mask of the changing configuration parameters, as
+     * defined by {@link android.content.pm.ActivityInfo}.
+     *
+     * @see android.content.pm.ActivityInfo
+     * @hide
+     */
+    public void setChangingConfigurations(int configs) {
+        mChangingConfigurations = configs;
+    }
+
+    /**
+     * Sets the changing configurations value to the union of the current changing configurations
+     * and the provided configs.
+     * This method is called while loading the animator.
+     * @hide
+     */
+    public void appendChangingConfigurations(int configs) {
+        mChangingConfigurations |= configs;
+    }
+
+    /**
+     * Return a {@link android.content.res.ConstantState} instance that holds the shared state of
+     * this Animator.
+     * <p>
+     * This constant state is used to create new instances of this animator when needed. Default
+     * implementation creates a new {@link StateListAnimatorConstantState}. You can override this
+     * method to provide your custom logic or return null if you don't want this animator to be
+     * cached.
+     *
+     * @return The {@link android.content.res.ConstantState} associated to this Animator.
+     * @see android.content.res.ConstantState
+     * @see #clone()
+     * @hide
+     */
+    public ConstantState<StateListAnimator> createConstantState() {
+        return new StateListAnimatorConstantState(this);
+    }
+
+    /**
      * @hide
      */
     public static class Tuple {
@@ -209,4 +297,36 @@
             return mAnimator;
         }
     }
+
+    /**
+     * Creates a constant state which holds changing configurations information associated with the
+     * given Animator.
+     * <p>
+     * When new instance is called, default implementation clones the Animator.
+     */
+    private static class StateListAnimatorConstantState
+            extends ConstantState<StateListAnimator> {
+
+        final StateListAnimator mAnimator;
+
+        int mChangingConf;
+
+        public StateListAnimatorConstantState(StateListAnimator animator) {
+            mAnimator = animator;
+            mAnimator.mConstantState = this;
+            mChangingConf = mAnimator.getChangingConfigurations();
+        }
+
+        @Override
+        public int getChangingConfigurations() {
+            return mChangingConf;
+        }
+
+        @Override
+        public StateListAnimator newInstance() {
+            final StateListAnimator clone = mAnimator.clone();
+            clone.mConstantState = this;
+            return clone;
+        }
+    }
 }
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 0d17d67..07f79b8 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -16,6 +16,7 @@
 
 package android.animation;
 
+import android.content.res.ConfigurationBoundResourceCache;
 import android.os.Looper;
 import android.os.Trace;
 import android.util.AndroidRuntimeException;
@@ -1289,12 +1290,7 @@
     public ValueAnimator clone() {
         final ValueAnimator anim = (ValueAnimator) super.clone();
         if (mUpdateListeners != null) {
-            ArrayList<AnimatorUpdateListener> oldListeners = mUpdateListeners;
-            anim.mUpdateListeners = new ArrayList<AnimatorUpdateListener>();
-            int numListeners = oldListeners.size();
-            for (int i = 0; i < numListeners; ++i) {
-                anim.mUpdateListeners.add(oldListeners.get(i));
-            }
+            anim.mUpdateListeners = new ArrayList<AnimatorUpdateListener>(mUpdateListeners);
         }
         anim.mSeekTime = -1;
         anim.mPlayingBackwards = false;
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 540376e..d611058 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -222,8 +222,15 @@
         if (mListener != null) {
             mListener.onMapSharedElements(mAllSharedElementNames, sharedElements);
         }
-        mSharedElementNames.addAll(sharedElements.keySet());
-        mSharedElements.addAll(sharedElements.values());
+        int numSharedElements = sharedElements.size();
+        for (int i = 0; i < numSharedElements; i++) {
+            View sharedElement = sharedElements.valueAt(i);
+            String name = sharedElements.keyAt(i);
+            if (sharedElement != null && sharedElement.isAttachedToWindow() && name != null) {
+                mSharedElements.add(sharedElement);
+                mSharedElementNames.add(name);
+            }
+        }
         if (getViewsTransition() != null && mTransitioningViews != null) {
             ViewGroup decorView = getDecor();
             if (decorView != null) {
@@ -536,10 +543,10 @@
 
     protected ArrayList<View> createSnapshots(Bundle state, Collection<String> names) {
         int numSharedElements = names.size();
-        if (numSharedElements == 0) {
-            return null;
-        }
         ArrayList<View> snapshots = new ArrayList<View>(numSharedElements);
+        if (numSharedElements == 0) {
+            return snapshots;
+        }
         Context context = getWindow().getContext();
         int[] decorLoc = new int[2];
         ViewGroup decorView = getDecor();
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 1e1a613..854719d 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1664,6 +1664,17 @@
      * @hide
      */
     public Drawable loadItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo) {
+        Drawable dr = loadUnbadgedItemIcon(itemInfo, appInfo);
+        if (itemInfo.showUserIcon != UserHandle.USER_NULL) {
+            return dr;
+        }
+        return getUserBadgedIcon(dr, new UserHandle(mContext.getUserId()));
+    }
+
+    /**
+     * @hide
+     */
+    public Drawable loadUnbadgedItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo) {
         if (itemInfo.showUserIcon != UserHandle.USER_NULL) {
             Bitmap bitmap = getUserManager().getUserIcon(itemInfo.showUserIcon);
             if (bitmap == null) {
@@ -1678,7 +1689,7 @@
         if (dr == null) {
             dr = itemInfo.loadDefaultIcon(this);
         }
-        return getUserBadgedIcon(dr, new UserHandle(mContext.getUserId()));
+        return dr;
     }
 
     private Drawable getBadgedDrawable(Drawable drawable, Drawable badgeDrawable,
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index fb10e17..9849c51 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -23,6 +23,7 @@
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.ColorStateList;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.PorterDuff;
@@ -2773,6 +2774,14 @@
                     contentView.setViewVisibility(R.id.progress, View.VISIBLE);
                     contentView.setProgressBar(
                             R.id.progress, mProgressMax, mProgress, mProgressIndeterminate);
+                    contentView.setProgressBackgroundTintList(
+                            R.id.progress, ColorStateList.valueOf(mContext.getResources().getColor(
+                                    R.color.notification_progress_background_color)));
+                    if (mColor != COLOR_DEFAULT) {
+                        ColorStateList colorStateList = ColorStateList.valueOf(mColor);
+                        contentView.setProgressTintList(R.id.progress, colorStateList);
+                        contentView.setProgressIndeterminateTintList(R.id.progress, colorStateList);
+                    }
                     showLine2 = true;
                 } else {
                     contentView.setViewVisibility(R.id.progress, View.GONE);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index af6f181..7676e4b 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -876,12 +876,44 @@
      * related methods.
      */
     public static Intent createChooser(Intent target, CharSequence title) {
+        return createChooser(target, title, null);
+    }
+
+    /**
+     * Convenience function for creating a {@link #ACTION_CHOOSER} Intent.
+     *
+     * <p>Builds a new {@link #ACTION_CHOOSER} Intent that wraps the given
+     * target intent, also optionally supplying a title.  If the target
+     * intent has specified {@link #FLAG_GRANT_READ_URI_PERMISSION} or
+     * {@link #FLAG_GRANT_WRITE_URI_PERMISSION}, then these flags will also be
+     * set in the returned chooser intent, with its ClipData set appropriately:
+     * either a direct reflection of {@link #getClipData()} if that is non-null,
+     * or a new ClipData built from {@link #getData()}.</p>
+     *
+     * <p>The caller may optionally supply an {@link IntentSender} to receive a callback
+     * when the user makes a choice. This can be useful if the calling application wants
+     * to remember the last chosen target and surface it as a more prominent or one-touch
+     * affordance elsewhere in the UI for next time.</p>
+     *
+     * @param target The Intent that the user will be selecting an activity
+     * to perform.
+     * @param title Optional title that will be displayed in the chooser.
+     * @param sender Optional IntentSender to be called when a choice is made.
+     * @return Return a new Intent object that you can hand to
+     * {@link Context#startActivity(Intent) Context.startActivity()} and
+     * related methods.
+     */
+    public static Intent createChooser(Intent target, CharSequence title, IntentSender sender) {
         Intent intent = new Intent(ACTION_CHOOSER);
         intent.putExtra(EXTRA_INTENT, target);
         if (title != null) {
             intent.putExtra(EXTRA_TITLE, title);
         }
 
+        if (sender != null) {
+            intent.putExtra(EXTRA_CHOSEN_COMPONENT_INTENT_SENDER, sender);
+        }
+
         // Migrate any clip data and flags from target.
         int permFlags = target.getFlags() & (FLAG_GRANT_READ_URI_PERMISSION
                 | FLAG_GRANT_WRITE_URI_PERMISSION | FLAG_GRANT_PERSISTABLE_URI_PERMISSION
@@ -3140,6 +3172,26 @@
             "android.intent.extra.REPLACEMENT_EXTRAS";
 
     /**
+     * An {@link IntentSender} that will be notified if a user successfully chooses a target
+     * component to handle an action in an {@link #ACTION_CHOOSER} activity. The IntentSender
+     * will have the extra {@link #EXTRA_CHOSEN_COMPONENT} appended to it containing the
+     * {@link ComponentName} of the chosen component.
+     *
+     * <p>In some situations this callback may never come, for example if the user abandons
+     * the chooser, switches to another task or any number of other reasons. Apps should not
+     * be written assuming that this callback will always occur.</p>
+     */
+    public static final String EXTRA_CHOSEN_COMPONENT_INTENT_SENDER =
+            "android.intent.extra.CHOSEN_COMPONENT_INTENT_SENDER";
+
+    /**
+     * The {@link ComponentName} chosen by the user to complete an action.
+     *
+     * @see #EXTRA_CHOSEN_COMPONENT_INTENT_SENDER
+     */
+    public static final String EXTRA_CHOSEN_COMPONENT = "android.intent.extra.CHOSEN_COMPONENT";
+
+    /**
      * A {@link android.view.KeyEvent} object containing the event that
      * triggered the creation of the Intent it is in.
      */
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index cacdf8e..22a899c 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -138,7 +138,7 @@
         }
         return packageName;
     }
-    
+
     /**
      * Retrieve the current graphical icon associated with this item.  This
      * will call back on the given PackageManager to load the icon from
@@ -156,6 +156,23 @@
     }
 
     /**
+     * Retrieve the current graphical icon associated with this item without
+     * the addition of a work badge if applicable.
+     * This will call back on the given PackageManager to load the icon from
+     * the application.
+     *
+     * @param pm A PackageManager from which the icon can be loaded; usually
+     * the PackageManager from which you originally retrieved this item.
+     *
+     * @return Returns a Drawable containing the item's icon.  If the
+     * item does not have an icon, the item's default icon is returned
+     * such as the default activity icon.
+     */
+    public Drawable loadUnbadgedIcon(PackageManager pm) {
+        return pm.loadUnbadgedItemIcon(this, getApplicationInfo());
+    }
+
+    /**
      * Retrieve the current graphical banner associated with this item.  This
      * will call back on the given PackageManager to load the banner from
      * the application.
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index e519163..ab90b66 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3911,6 +3911,11 @@
      */
     public abstract Drawable loadItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo);
 
+    /**
+     * @hide
+     */
+    public abstract Drawable loadUnbadgedItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo);
+
     /** {@hide} */
     public abstract boolean isPackageAvailable(String packageName);
 
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 27bbb24..acdd87e 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -1365,9 +1365,9 @@
         ArrayList<String> parts = new ArrayList<String>();
 
         if (config.mcc != 0) {
-            parts.add(config.mcc + "mcc");
+            parts.add("mcc" + config.mcc);
             if (config.mnc != 0) {
-                parts.add(config.mnc + "mnc");
+                parts.add("mnc" + config.mnc);
             }
         }
 
diff --git a/core/java/android/content/res/ConfigurationBoundResourceCache.java b/core/java/android/content/res/ConfigurationBoundResourceCache.java
new file mode 100644
index 0000000..cde7e84
--- /dev/null
+++ b/core/java/android/content/res/ConfigurationBoundResourceCache.java
@@ -0,0 +1,138 @@
+/*
+* Copyright (C) 2014 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package android.content.res;
+
+import android.util.ArrayMap;
+import android.util.LongSparseArray;
+import java.lang.ref.WeakReference;
+
+/**
+ * A Cache class which can be used to cache resource objects that are easy to clone but more
+ * expensive to inflate.
+ * @hide
+ */
+public class ConfigurationBoundResourceCache<T> {
+
+    private final ArrayMap<String, LongSparseArray<WeakReference<ConstantState<T>>>> mCache =
+            new ArrayMap<String, LongSparseArray<WeakReference<ConstantState<T>>>>();
+
+    final Resources mResources;
+
+    /**
+     * Creates a Resource cache for the given Resources instance.
+     *
+     * @param resources The Resource which can be used when creating new instances.
+     */
+    public ConfigurationBoundResourceCache(Resources resources) {
+        mResources = resources;
+    }
+
+    /**
+     * Adds a new item to the cache.
+     *
+     * @param key A custom key that uniquely identifies the resource.
+     * @param theme The Theme instance where this resource was loaded.
+     * @param constantState The constant state that can create new instances of the resource.
+     *
+     */
+    public void put(long key, Resources.Theme theme, ConstantState<T> constantState) {
+        if (constantState == null) {
+            return;
+        }
+        final String themeKey = theme == null ? "" : theme.getKey();
+        LongSparseArray<WeakReference<ConstantState<T>>> themedCache;
+        synchronized (this) {
+            themedCache = mCache.get(themeKey);
+            if (themedCache == null) {
+                themedCache = new LongSparseArray<WeakReference<ConstantState<T>>>(1);
+                mCache.put(themeKey, themedCache);
+            }
+            themedCache.put(key, new WeakReference<ConstantState<T>>(constantState));
+        }
+    }
+
+    /**
+     * If the resource is cached, creates a new instance of it and returns.
+     *
+     * @param key The long key which can be used to uniquely identify the resource.
+     * @param theme The The Theme instance where we want to load this resource.
+     *
+     * @return If this resources was loaded before, returns a new instance of it. Otherwise, returns
+     *         null.
+     */
+    public T get(long key, Resources.Theme theme) {
+        final String themeKey = theme != null ? theme.getKey() : "";
+        final LongSparseArray<WeakReference<ConstantState<T>>> themedCache;
+        final WeakReference<ConstantState<T>> wr;
+        synchronized (this) {
+            themedCache = mCache.get(themeKey);
+            if (themedCache == null) {
+                return null;
+            }
+            wr = themedCache.get(key);
+        }
+        if (wr == null) {
+            return null;
+        }
+        final ConstantState entry = wr.get();
+        if (entry != null) {
+            return  (T) entry.newInstance(mResources, theme);
+        } else {  // our entry has been purged
+            synchronized (this) {
+                // there is a potential race condition here where this entry may be put in
+                // another thread. But we prefer it to minimize lock duration
+                themedCache.delete(key);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Users of ConfigurationBoundResourceCache must call this method whenever a configuration
+     * change happens. On this callback, the cache invalidates all resources that are not valid
+     * anymore.
+     *
+     * @param configChanges The configuration changes
+     */
+    public void onConfigurationChange(final int configChanges) {
+        synchronized (this) {
+            final int size = mCache.size();
+            for (int i = size - 1; i >= 0; i--) {
+                final LongSparseArray<WeakReference<ConstantState<T>>>
+                        themeCache = mCache.valueAt(i);
+                onConfigurationChangeInt(themeCache, configChanges);
+                if (themeCache.size() == 0) {
+                    mCache.removeAt(i);
+                }
+            }
+        }
+    }
+
+    private void onConfigurationChangeInt(
+            final LongSparseArray<WeakReference<ConstantState<T>>> themeCache,
+            final int configChanges) {
+        final int size = themeCache.size();
+        for (int i = size - 1; i >= 0; i--) {
+            final WeakReference<ConstantState<T>> wr = themeCache.valueAt(i);
+            final ConstantState<T> constantState = wr.get();
+            if (constantState == null || Configuration.needNewResources(
+                    configChanges, constantState.getChangingConfigurations())) {
+                themeCache.removeAt(i);
+            }
+        }
+    }
+
+}
diff --git a/core/java/android/content/res/ConstantState.java b/core/java/android/content/res/ConstantState.java
new file mode 100644
index 0000000..ee609df
--- /dev/null
+++ b/core/java/android/content/res/ConstantState.java
@@ -0,0 +1,61 @@
+/*
+* Copyright (C) 2014 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package android.content.res;
+
+/**
+ * A cache class that can provide new instances of a particular resource which may change
+ * depending on the current {@link Resources.Theme} or {@link Configuration}.
+ * <p>
+ * A constant state should be able to return a bitmask of changing configurations, which
+ * identifies the type of configuration changes that may invalidate this resource. These
+ * configuration changes can be obtained from {@link android.util.TypedValue}. Entities such as
+ * {@link android.animation.Animator} also provide a changing configuration method to include
+ * their dependencies (e.g. An AnimatorSet's changing configuration is the union of the
+ * changing configurations of each Animator in the set)
+ * @hide
+ */
+abstract public class ConstantState<T> {
+
+    /**
+     * Return a bit mask of configuration changes that will impact
+     * this resource (and thus require completely reloading it).
+     */
+    abstract public int getChangingConfigurations();
+
+    /**
+     * Create a new instance without supplying resources the caller
+     * is running in.
+     */
+    public abstract T newInstance();
+
+    /**
+     * Create a new instance from its constant state.  This
+     * must be implemented for resources that change based on the target
+     * density of their caller (that is depending on whether it is
+     * in compatibility mode).
+     */
+    public T newInstance(Resources res) {
+        return newInstance();
+    }
+
+    /**
+     * Create a new instance from its constant state.  This must be
+     * implemented for resources that can have a theme applied.
+     */
+    public T newInstance(Resources res, Resources.Theme theme) {
+        return newInstance(res);
+    }
+}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 7f276c2..6e9efe1 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -16,6 +16,8 @@
 
 package android.content.res;
 
+import android.animation.Animator;
+import android.animation.StateListAnimator;
 import android.util.Pools.SynchronizedPool;
 import android.view.ViewDebug;
 import com.android.internal.util.XmlUtils;
@@ -115,6 +117,10 @@
             new ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>>();
     private final LongSparseArray<WeakReference<ColorStateList>> mColorStateListCache =
             new LongSparseArray<WeakReference<ColorStateList>>();
+    private final ConfigurationBoundResourceCache<Animator> mAnimatorCache =
+            new ConfigurationBoundResourceCache<Animator>(this);
+    private final ConfigurationBoundResourceCache<StateListAnimator> mStateListAnimatorCache =
+            new ConfigurationBoundResourceCache<StateListAnimator>(this);
 
     private TypedValue mTmpValue = new TypedValue();
     private boolean mPreloading;
@@ -183,6 +189,24 @@
     }
 
     /**
+     * Used by AnimatorInflater.
+     *
+     * @hide
+     */
+    public ConfigurationBoundResourceCache<Animator> getAnimatorCache() {
+        return mAnimatorCache;
+    }
+
+    /**
+     * Used by AnimatorInflater.
+     *
+     * @hide
+     */
+    public ConfigurationBoundResourceCache<StateListAnimator> getStateListAnimatorCache() {
+        return mStateListAnimatorCache;
+    }
+
+    /**
      * This exception is thrown by the resource APIs when a requested resource
      * can not be found.
      */
@@ -1761,23 +1785,7 @@
             // the framework.
             mCompatibilityInfo.applyToDisplayMetrics(mMetrics);
 
-            int configChanges = 0xfffffff;
-            if (config != null) {
-                mTmpConfig.setTo(config);
-                int density = config.densityDpi;
-                if (density == Configuration.DENSITY_DPI_UNDEFINED) {
-                    density = mMetrics.noncompatDensityDpi;
-                }
-
-                mCompatibilityInfo.applyToConfiguration(density, mTmpConfig);
-
-                if (mTmpConfig.locale == null) {
-                    mTmpConfig.locale = Locale.getDefault();
-                    mTmpConfig.setLayoutDirection(mTmpConfig.locale);
-                }
-                configChanges = mConfiguration.updateFrom(mTmpConfig);
-                configChanges = ActivityInfo.activityInfoConfigToNative(configChanges);
-            }
+            int configChanges = calcConfigChanges(config);
             if (mConfiguration.locale == null) {
                 mConfiguration.locale = Locale.getDefault();
                 mConfiguration.setLayoutDirection(mConfiguration.locale);
@@ -1825,6 +1833,8 @@
 
             clearDrawableCachesLocked(mDrawableCache, configChanges);
             clearDrawableCachesLocked(mColorDrawableCache, configChanges);
+            mAnimatorCache.onConfigurationChange(configChanges);
+            mStateListAnimatorCache.onConfigurationChange(configChanges);
 
             mColorStateListCache.clear();
 
@@ -1837,6 +1847,30 @@
         }
     }
 
+    /**
+     * Called by ConfigurationBoundResourceCacheTest via reflection.
+     */
+    private int calcConfigChanges(Configuration config) {
+        int configChanges = 0xfffffff;
+        if (config != null) {
+            mTmpConfig.setTo(config);
+            int density = config.densityDpi;
+            if (density == Configuration.DENSITY_DPI_UNDEFINED) {
+                density = mMetrics.noncompatDensityDpi;
+            }
+
+            mCompatibilityInfo.applyToConfiguration(density, mTmpConfig);
+
+            if (mTmpConfig.locale == null) {
+                mTmpConfig.locale = Locale.getDefault();
+                mTmpConfig.setLayoutDirection(mTmpConfig.locale);
+            }
+            configChanges = mConfiguration.updateFrom(mTmpConfig);
+            configChanges = ActivityInfo.activityInfoConfigToNative(configChanges);
+        }
+        return configChanges;
+    }
+
     private void clearDrawableCachesLocked(
             ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> caches,
             int configChanges) {
@@ -2323,7 +2357,14 @@
 
         final Drawable dr;
         if (cs != null) {
-            dr = cs.newDrawable(this, theme);
+            final Drawable clonedDr = cs.newDrawable(this);
+            if (theme != null) {
+                dr = clonedDr.mutate();
+                dr.applyTheme(theme);
+                dr.clearMutated();
+            } else {
+                dr = clonedDr;
+            }
         } else if (isColorDrawable) {
             dr = new ColorDrawable(value.data);
         } else {
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index f514e42..cf6a779 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -329,7 +329,11 @@
      * A sensor of this type triggers an event each time a step is taken by the user. The only
      * allowed value to return is 1.0 and an event is generated for each step. Like with any other
      * event, the timestamp indicates when the event (here the step) occurred, this corresponds to
-     * when the foot hit the ground, generating a high variation in acceleration.
+     * when the foot hit the ground, generating a high variation in acceleration. This sensor is
+     * only for detecting every individual step as soon as it is taken, for example to perform dead
+     * reckoning. If you only need aggregate number of steps taken over a period of time, register
+     * for {@link #TYPE_STEP_COUNTER} instead. It is defined as a
+     * {@link Sensor#REPORTING_MODE_SPECIAL_TRIGGER} sensor.
      * <p>
      * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
      */
@@ -349,7 +353,12 @@
      * while activated. The value is returned as a float (with the fractional part set to zero) and
      * is reset to zero only on a system reboot. The timestamp of the event is set to the time when
      * the last step for that event was taken. This sensor is implemented in hardware and is
-     * expected to be low power.
+     * expected to be low power. If you want to continuously track the number of steps over a long
+     * period of time, do NOT unregister for this sensor, so that it keeps counting steps in the
+     * background even when the AP is in suspend mode and report the aggregate count when the AP
+     * is awake. Application needs to stay registered for this sensor because step counter does not
+     * count steps if it is not activated. This sensor is ideal for fitness tracking applications.
+     * It is defined as an {@link Sensor#REPORTING_MODE_ON_CHANGE} sensor.
      * <p>
      * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
      */
@@ -750,31 +759,41 @@
     }
 
     /**
-     * Returns whether this sensor is a wake-up sensor.
+     * Returns true if the sensor is a wake-up sensor.
      * <p>
-     * Wake up sensors wake the application processor up when they have events to deliver. When a
-     * wake up sensor is registered to without batching enabled, each event will wake the
-     * application processor up.
+     * <b>Application Processor Power modes</b> <p>
+     * Application Processor(AP), is the processor on which applications run.  When no wake lock is held
+     * and the user is not interacting with the device, this processor can enter a “Suspend” mode,
+     * reducing the power consumption by 10 times or more.
+     * </p>
      * <p>
-     * When a wake up sensor is registered to with batching enabled, it
-     * wakes the application processor up when maxReportingLatency has elapsed or when the hardware
-     * FIFO storing the events from wake up sensors is getting full.
+     * <b>Non-wake-up sensors</b> <p>
+     * Non-wake-up sensors are sensors that do not wake the AP out of suspend to report data. While
+     * the AP is in suspend mode, the sensors continue to function and generate events, which are
+     * put in a hardware FIFO. The events in the FIFO are delivered to the application when the AP
+     * wakes up. If the FIFO was too small to store all events generated while the AP was in
+     * suspend mode, the older events are lost: the oldest data is dropped to accommodate the newer
+     * data. In the extreme case where the FIFO is non-existent {@code maxFifoEventCount() == 0},
+     * all events generated while the AP was in suspend mode are lost. Applications using
+     * non-wake-up sensors should usually:
+     * <ul>
+     * <li>Either unregister from the sensors when they do not need them, usually in the activity’s
+     * {@code onPause} method. This is the most common case.
+     * <li>Or realize that the sensors are consuming some power while the AP is in suspend mode and
+     * that even then, some events might be lost.
+     * </ul>
+     * </p>
      * <p>
-     * Non-wake up sensors never wake the application processor up. Their events are only reported
-     * when the application processor is awake, for example because the application holds a wake
-     * lock, or another source woke the application processor up.
-     * <p>
-     * When a non-wake up sensor is registered to without batching enabled, the measurements made
-     * while the application processor is asleep might be lost and never returned.
-     * <p>
-     * When a non-wake up sensor is registered to with batching enabled, the measurements made while
-     * the application processor is asleep are stored in the hardware FIFO for non-wake up sensors.
-     * When this FIFO gets full, new events start overwriting older events. When the application
-     * then wakes up, the latest events are returned, and some old events might be lost. The number
-     * of events actually returned depends on the hardware FIFO size, as well as on what other
-     * sensors are activated. If losing sensor events is not acceptable during batching, you must
-     * use the wake-up version of the sensor.
-     * @return true if this is a wake up sensor, false otherwise.
+     * <b>Wake-up sensors</b> <p>
+     * In opposition to non-wake-up sensors, wake-up sensors ensure that their data is delivered
+     * independently of the state of the AP. While the AP is awake, the wake-up sensors behave
+     * like non-wake-up-sensors. When the AP is asleep, wake-up sensors wake up the AP to deliver
+     * events. That is, the AP will wake up and the sensor will deliver the events before the
+     * maximum reporting latency is elapsed or the hardware FIFO gets full. See {@link
+     * SensorManager#registerListener(SensorEventListener, Sensor, int, int)} for more details.
+     * </p>
+     *
+     * @return <code>true</code> if this is a wake-up sensor, <code>false</code> otherwise.
      */
     public boolean isWakeUpSensor() {
         return (mFlags & SENSOR_FLAG_WAKE_UP_SENSOR) != 0;
diff --git a/core/java/android/hardware/SensorEventListener2.java b/core/java/android/hardware/SensorEventListener2.java
index 70eff08..fd3e62b 100644
--- a/core/java/android/hardware/SensorEventListener2.java
+++ b/core/java/android/hardware/SensorEventListener2.java
@@ -21,15 +21,16 @@
  */
 public interface SensorEventListener2 extends SensorEventListener {
     /**
-     * Called after flush() is completed. All the events in the batch at the point when
-     * the flush was called have been delivered to the applications registered for those
-     * sensor events. Flush Complete Events are sent ONLY to the application that has
-     * explicitly called flush(). If the hardware FIFO is flushed due to some other
-     * application calling flush(), flush complete event is not delivered to this application.
+     * Called after flush() is completed. All the events in the batch at the point when the flush
+     * was called have been delivered to the applications registered for those sensor events. In
+     * {@link android.os.Build.VERSION_CODES#KITKAT}, applications may receive flush complete events
+     * even if some other application has called flush() on the same sensor. Starting with
+     * {@link android.os.Build.VERSION_CODES#LOLLIPOP}, flush Complete events are sent ONLY to the
+     * application that has explicitly called flush(). If the hardware FIFO is flushed due to some
+     * other application calling flush(), flush complete event is not delivered to this application.
      * <p>
      *
      * @param sensor The {@link android.hardware.Sensor Sensor} on which flush was called.
-     *
      * @see android.hardware.SensorManager#flush(SensorEventListener)
      */
     public void onFlushCompleted(Sensor sensor);
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index cccd624..e4e5a8c 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -626,73 +626,90 @@
     protected abstract void unregisterListenerImpl(SensorEventListener listener, Sensor sensor);
 
     /**
-     * Registers a {@link android.hardware.SensorEventListener
-     * SensorEventListener} for the given sensor.
-     *
-     * <p class="note"></p>
-     * Note: Don't use this method with a one shot trigger sensor such as
-     * {@link Sensor#TYPE_SIGNIFICANT_MOTION}.
-     * Use {@link #requestTriggerSensor(TriggerEventListener, Sensor)} instead.
+     * Registers a {@link android.hardware.SensorEventListener SensorEventListener} for the given
+     * sensor at the given sampling frequency.
+     * <p>
+     * The events will be delivered to the provided {@code SensorEventListener} as soon as they are
+     * available. To reduce the power consumption, applications can use
+     * {@link #registerListener(SensorEventListener, Sensor, int, int)} instead and specify a
+     * positive non-zero maximum reporting latency.
+     * </p>
+     * <p>
+     * In the case of non-wake-up sensors, the events are only delivered while the Application
+     * Processor (AP) is not in suspend mode. See {@link Sensor#isWakeUpSensor()} for more details.
+     * To ensure delivery of events from non-wake-up sensors even when the screen is OFF, the
+     * application registering to the sensor must hold a partial wake-lock to keep the AP awake,
+     * otherwise some events might be lost while the AP is asleep. Note that although events might
+     * be lost while the AP is asleep, the sensor will still consume power if it is not explicitly
+     * deactivated by the application. Applications must unregister their {@code
+     * SensorEventListener}s in their activity's {@code onPause()} method to avoid consuming power
+     * while the device is inactive.  See {@link #registerListener(SensorEventListener, Sensor, int,
+     * int)} for more details on hardware FIFO (queueing) capabilities and when some sensor events
+     * might be lost.
+     * </p>
+     * <p>
+     * In the case of wake-up sensors, each event generated by the sensor will cause the AP to
+     * wake-up, ensuring that each event can be delivered. Because of this, registering to a wake-up
+     * sensor has very significant power implications. Call {@link Sensor#isWakeUpSensor()} to check
+     * whether a sensor is a wake-up sensor. See
+     * {@link #registerListener(SensorEventListener, Sensor, int, int)} for information on how to
+     * reduce the power impact of registering to wake-up sensors.
+     * </p>
+     * <p class="note">
+     * Note: Don't use this method with one-shot trigger sensors such as
+     * {@link Sensor#TYPE_SIGNIFICANT_MOTION}. Use
+     * {@link #requestTriggerSensor(TriggerEventListener, Sensor)} instead. Use
+     * {@link Sensor#getReportingMode()} to obtain the reporting mode of a given sensor.
      * </p>
      *
-     * @param listener
-     *        A {@link android.hardware.SensorEventListener SensorEventListener}
-     *        object.
-     *
-     * @param sensor
-     *        The {@link android.hardware.Sensor Sensor} to register to.
-     *
-     * @param rateUs
-     *        The rate {@link android.hardware.SensorEvent sensor events} are
-     *        delivered at. This is only a hint to the system. Events may be
-     *        received faster or slower than the specified rate. Usually events
-     *        are received faster. The value must be one of
-     *        {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI},
-     *        {@link #SENSOR_DELAY_GAME}, or {@link #SENSOR_DELAY_FASTEST}
-     *        or, the desired delay between events in microseconds.
-     *        Specifying the delay in microseconds only works from Android
-     *        2.3 (API level 9) onwards. For earlier releases, you must use
-     *        one of the {@code SENSOR_DELAY_*} constants.
-     *
-     * @return <code>true</code> if the sensor is supported and successfully
-     *         enabled.
-     *
+     * @param listener A {@link android.hardware.SensorEventListener SensorEventListener} object.
+     * @param sensor The {@link android.hardware.Sensor Sensor} to register to.
+     * @param samplingPeriodUs The rate {@link android.hardware.SensorEvent sensor events} are
+     *            delivered at. This is only a hint to the system. Events may be received faster or
+     *            slower than the specified rate. Usually events are received faster. The value must
+     *            be one of {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI},
+     *            {@link #SENSOR_DELAY_GAME}, or {@link #SENSOR_DELAY_FASTEST} or, the desired delay
+     *            between events in microseconds. Specifying the delay in microseconds only works
+     *            from Android 2.3 (API level 9) onwards. For earlier releases, you must use one of
+     *            the {@code SENSOR_DELAY_*} constants.
+     * @return <code>true</code> if the sensor is supported and successfully enabled.
      * @see #registerListener(SensorEventListener, Sensor, int, Handler)
      * @see #unregisterListener(SensorEventListener)
      * @see #unregisterListener(SensorEventListener, Sensor)
-     *
      */
-    public boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs) {
-        return registerListener(listener, sensor, rateUs, null);
+    public boolean registerListener(SensorEventListener listener, Sensor sensor,
+            int samplingPeriodUs) {
+        return registerListener(listener, sensor, samplingPeriodUs, null);
     }
 
     /**
-     * Enables batch mode for a sensor with the given rate and maxBatchReportLatency. If the
-     * underlying hardware does not support batch mode, this defaults to
-     * {@link #registerListener(SensorEventListener, Sensor, int)} and other parameters are
-     * ignored. In non-batch mode, all sensor events must be reported as soon as they are detected.
-     * While in batch mode, sensor events do not need to be reported as soon as they are detected.
-     * They can be temporarily stored in batches and reported in batches, as long as no event is
-     * delayed by more than "maxBatchReportLatency" microseconds. That is, all events since the
-     * previous batch are recorded and returned all at once. This allows to reduce the amount of
-     * interrupts sent to the SoC, and allows the SoC to switch to a lower power state (Idle) while
-     * the sensor is capturing and batching data.
+     * Registers a {@link android.hardware.SensorEventListener SensorEventListener} for the given
+     * sensor at the given sampling frequency and the given maximum reporting latency.
      * <p>
-     * Registering to a sensor in batch mode will not prevent the SoC from going to suspend mode. In
-     * this case, the sensor will continue to gather events and store it in a hardware FIFO. If the
-     * FIFO gets full before the AP wakes up again, some events will be lost, as the older events
-     * get overwritten by new events in the hardware FIFO. This can be avoided by holding a wake
-     * lock. If the application holds a wake lock, the SoC will not go to suspend mode, so no events
-     * will be lost, as the events will be reported before the FIFO gets full.
-     * </p>
-     * <p>
-     * Batching is always best effort. If a different application requests updates in continuous
-     * mode, this application will also get events in continuous mode. Batch mode updates can be
-     * unregistered by calling {@link #unregisterListener(SensorEventListener)}.
+     * This function is similar to {@link #registerListener(SensorEventListener, Sensor, int)} but
+     * it allows events to stay temporarily in the hardware FIFO (queue) before being delivered. The
+     * events can be stored in the hardware FIFO up to {@code maxReportLatencyUs} microseconds. Once
+     * one of the events in the FIFO needs to be reported, all of the events in the FIFO are
+     * reported sequentially. This means that some events will be reported before the maximum
+     * reporting latency has elapsed.
+     * </p><p>
+     * When {@code maxReportLatencyUs} is 0, the call is equivalent to a call to
+     * {@link #registerListener(SensorEventListener, Sensor, int)}, as it requires the events to be
+     * delivered as soon as possible.
+     * </p><p>
+     * When {@code sensor.maxFifoEventCount()} is 0, the sensor does not use a FIFO, so the call
+     * will also be equivalent to {@link #registerListener(SensorEventListener, Sensor, int)}.
+     * </p><p>
+     * Setting {@code maxReportLatencyUs} to a positive value allows to reduce the number of
+     * interrupts the AP (Application Processor) receives, hence reducing power consumption, as the
+     * AP can switch to a lower power state while the sensor is capturing the data. This is
+     * especially important when registering to wake-up sensors, for which each interrupt causes the
+     * AP to wake up if it was in suspend mode. See {@link Sensor#isWakeUpSensor()} for more
+     * information on wake-up sensors.
      * </p>
      * <p class="note">
      * </p>
-     * Note: Don't use this method with a one shot trigger sensor such as
+     * Note: Don't use this method with one-shot trigger sensors such as
      * {@link Sensor#TYPE_SIGNIFICANT_MOTION}. Use
      * {@link #requestTriggerSensor(TriggerEventListener, Sensor)} instead. </p>
      *
@@ -701,118 +718,104 @@
      *            flush complete notifications, it should register with
      *            {@link android.hardware.SensorEventListener SensorEventListener2} instead.
      * @param sensor The {@link android.hardware.Sensor Sensor} to register to.
-     * @param rateUs The desired delay between two consecutive events in microseconds. This is only
-     *            a hint to the system. Events may be received faster or slower than the specified
-     *            rate. Usually events are received faster. Can be one of
+     * @param samplingPeriodUs The desired delay between two consecutive events in microseconds.
+     *            This is only a hint to the system. Events may be received faster or slower than
+     *            the specified rate. Usually events are received faster. Can be one of
      *            {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI},
      *            {@link #SENSOR_DELAY_GAME}, {@link #SENSOR_DELAY_FASTEST} or the delay in
      *            microseconds.
-     * @param maxBatchReportLatencyUs An event in the batch can be delayed by at most
-     *            maxBatchReportLatency microseconds. More events can be batched if this value is
-     *            large. If this is set to zero, batch mode is disabled and events are delivered in
-     *            continuous mode as soon as they are available which is equivalent to calling
+     * @param maxReportLatencyUs Maximum time in microseconds that events can be delayed before
+     *            being reported to the application. A large value allows reducing the power
+     *            consumption associated with the sensor. If maxReportLatencyUs is set to zero,
+     *            events are delivered as soon as they are available, which is equivalent to calling
      *            {@link #registerListener(SensorEventListener, Sensor, int)}.
-     * @return <code>true</code> if batch mode is successfully enabled for this sensor,
-     *         <code>false</code> otherwise.
+     * @return <code>true</code> if the sensor is supported and successfully enabled.
      * @see #registerListener(SensorEventListener, Sensor, int)
      * @see #unregisterListener(SensorEventListener)
      * @see #flush(SensorEventListener)
      */
-    public boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs,
-            int maxBatchReportLatencyUs) {
-        int delay = getDelay(rateUs);
-        return registerListenerImpl(listener, sensor, delay, null, maxBatchReportLatencyUs, 0);
+    public boolean registerListener(SensorEventListener listener, Sensor sensor,
+            int samplingPeriodUs, int maxReportLatencyUs) {
+        int delay = getDelay(samplingPeriodUs);
+        return registerListenerImpl(listener, sensor, delay, null, maxReportLatencyUs, 0);
     }
 
     /**
      * Registers a {@link android.hardware.SensorEventListener SensorEventListener} for the given
      * sensor. Events are delivered in continuous mode as soon as they are available. To reduce the
-     * battery usage, use {@link #registerListener(SensorEventListener, Sensor, int, int)} which
-     * enables batch mode for the sensor.
-     *
-     * <p class="note"></p>
-     * Note: Don't use this method with a one shot trigger sensor such as
-     * {@link Sensor#TYPE_SIGNIFICANT_MOTION}.
-     * Use {@link #requestTriggerSensor(TriggerEventListener, Sensor)} instead.
+     * power consumption, applications can use
+     * {@link #registerListener(SensorEventListener, Sensor, int, int)} instead and specify a
+     * positive non-zero maximum reporting latency.
+     * <p class="note">
      * </p>
+     * Note: Don't use this method with a one shot trigger sensor such as
+     * {@link Sensor#TYPE_SIGNIFICANT_MOTION}. Use
+     * {@link #requestTriggerSensor(TriggerEventListener, Sensor)} instead. </p>
      *
-     * @param listener
-     *        A {@link android.hardware.SensorEventListener SensorEventListener}
-     *        object.
-     *
-     * @param sensor
-     *        The {@link android.hardware.Sensor Sensor} to register to.
-     *
-     * @param rateUs
-     *        The rate {@link android.hardware.SensorEvent sensor events} are
-     *        delivered at. This is only a hint to the system. Events may be
-     *        received faster or slower than the specified rate. Usually events
-     *        are received faster. The value must be one of
-     *        {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI},
-     *        {@link #SENSOR_DELAY_GAME}, or {@link #SENSOR_DELAY_FASTEST}.
-     *        or, the desired delay between events in microseconds.
-     *        Specifying the delay in microseconds only works from Android
-     *        2.3 (API level 9) onwards. For earlier releases, you must use
-     *        one of the {@code SENSOR_DELAY_*} constants.
-     *
-     * @param handler
-     *        The {@link android.os.Handler Handler} the
-     *        {@link android.hardware.SensorEvent sensor events} will be
-     *        delivered to.
-     *
+     * @param listener A {@link android.hardware.SensorEventListener SensorEventListener} object.
+     * @param sensor The {@link android.hardware.Sensor Sensor} to register to.
+     * @param samplingPeriodUs The rate {@link android.hardware.SensorEvent sensor events} are
+     *            delivered at. This is only a hint to the system. Events may be received faster or
+     *            slower than the specified rate. Usually events are received faster. The value must
+     *            be one of {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI},
+     *            {@link #SENSOR_DELAY_GAME}, or {@link #SENSOR_DELAY_FASTEST} or, the desired
+     *            delay between events in microseconds. Specifying the delay in microseconds only
+     *            works from Android 2.3 (API level 9) onwards. For earlier releases, you must use
+     *            one of the {@code SENSOR_DELAY_*} constants.
+     * @param handler The {@link android.os.Handler Handler} the {@link android.hardware.SensorEvent
+     *            sensor events} will be delivered to.
      * @return <code>true</code> if the sensor is supported and successfully enabled.
-     *
      * @see #registerListener(SensorEventListener, Sensor, int)
      * @see #unregisterListener(SensorEventListener)
      * @see #unregisterListener(SensorEventListener, Sensor)
      */
-    public boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs,
-            Handler handler) {
-        int delay = getDelay(rateUs);
+    public boolean registerListener(SensorEventListener listener, Sensor sensor,
+            int samplingPeriodUs, Handler handler) {
+        int delay = getDelay(samplingPeriodUs);
         return registerListenerImpl(listener, sensor, delay, handler, 0, 0);
     }
 
     /**
-     * Enables batch mode for a sensor with the given rate and maxBatchReportLatency.
+     * Registers a {@link android.hardware.SensorEventListener SensorEventListener} for the given
+     * sensor at the given sampling frequency and the given maximum reporting latency.
+     *
      * @param listener A {@link android.hardware.SensorEventListener SensorEventListener} object
      *            that will receive the sensor events. If the application is interested in receiving
      *            flush complete notifications, it should register with
      *            {@link android.hardware.SensorEventListener SensorEventListener2} instead.
      * @param sensor The {@link android.hardware.Sensor Sensor} to register to.
-     * @param rateUs The desired delay between two consecutive events in microseconds. This is only
-     *            a hint to the system. Events may be received faster or slower than the specified
-     *            rate. Usually events are received faster. Can be one of
+     * @param samplingPeriodUs The desired delay between two consecutive events in microseconds.
+     *            This is only a hint to the system. Events may be received faster or slower than
+     *            the specified rate. Usually events are received faster. Can be one of
      *            {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI},
      *            {@link #SENSOR_DELAY_GAME}, {@link #SENSOR_DELAY_FASTEST} or the delay in
      *            microseconds.
-     * @param maxBatchReportLatencyUs An event in the batch can be delayed by at most
-     *            maxBatchReportLatency microseconds. More events can be batched if this value is
-     *            large. If this is set to zero, batch mode is disabled and events are delivered in
-     *            continuous mode as soon as they are available which is equivalent to calling
+     * @param maxReportLatencyUs Maximum time in microseconds that events can be delayed before
+     *            being reported to the application. A large value allows reducing the power
+     *            consumption associated with the sensor. If maxReportLatencyUs is set to zero,
+     *            events are delivered as soon as they are available, which is equivalent to calling
      *            {@link #registerListener(SensorEventListener, Sensor, int)}.
-     * @param handler The {@link android.os.Handler Handler} the
-     *        {@link android.hardware.SensorEvent sensor events} will be delivered to.
-     *
-     * @return <code>true</code> if batch mode is successfully enabled for this sensor,
-     *         <code>false</code> otherwise.
+     * @param handler The {@link android.os.Handler Handler} the {@link android.hardware.SensorEvent
+     *            sensor events} will be delivered to.
+     * @return <code>true</code> if the sensor is supported and successfully enabled.
      * @see #registerListener(SensorEventListener, Sensor, int, int)
      */
-    public boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs,
-            int maxBatchReportLatencyUs, Handler handler) {
-        int delayUs = getDelay(rateUs);
-        return registerListenerImpl(listener, sensor, delayUs, handler, maxBatchReportLatencyUs, 0);
+    public boolean registerListener(SensorEventListener listener, Sensor sensor, int samplingPeriodUs,
+            int maxReportLatencyUs, Handler handler) {
+        int delayUs = getDelay(samplingPeriodUs);
+        return registerListenerImpl(listener, sensor, delayUs, handler, maxReportLatencyUs, 0);
     }
 
     /** @hide */
     protected abstract boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
-            int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags);
+            int delayUs, Handler handler, int maxReportLatencyUs, int reservedFlags);
 
 
     /**
-     * Flushes the batch FIFO of all the sensors registered for this listener. If there are events
-     * in the FIFO of the sensor, they are returned as if the batch timeout in the FIFO of the
-     * sensors had expired. Events are returned in the usual way through the SensorEventListener.
-     * This call doesn't affect the batch timeout for this sensor. This call is asynchronous and
+     * Flushes the FIFO of all the sensors registered for this listener. If there are events
+     * in the FIFO of the sensor, they are returned as if the maxReportLantecy of the FIFO has
+     * expired. Events are returned in the usual way through the SensorEventListener.
+     * This call doesn't affect the maxReportLantecy for this sensor. This call is asynchronous and
      * returns immediately.
      * {@link android.hardware.SensorEventListener2#onFlushCompleted onFlushCompleted} is called
      * after all the events in the batch at the time of calling this method have been delivered
diff --git a/core/java/android/hardware/hdmi/HdmiClient.java b/core/java/android/hardware/hdmi/HdmiClient.java
index aba90e47..c2b9846 100644
--- a/core/java/android/hardware/hdmi/HdmiClient.java
+++ b/core/java/android/hardware/hdmi/HdmiClient.java
@@ -3,7 +3,6 @@
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.hardware.hdmi.HdmiControlManager.VendorCommandListener;
-import android.hardware.hdmi.IHdmiVendorCommandListener;
 import android.os.RemoteException;
 import android.util.Log;
 
@@ -91,8 +90,13 @@
             final VendorCommandListener listener) {
         return new IHdmiVendorCommandListener.Stub() {
             @Override
-            public void onReceived(int srcAddress, byte[] params, boolean hasVendorId) {
-                listener.onReceived(srcAddress, params, hasVendorId);
+            public void onReceived(int srcAddress, int destAddress, byte[] params,
+                    boolean hasVendorId) {
+                listener.onReceived(srcAddress, destAddress, params, hasVendorId);
+            }
+            @Override
+            public void onControlStateChanged(boolean enabled, int reason) {
+                listener.onControlStateChanged(enabled, reason);
             }
         };
     }
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index 30f3576..ff2ba1e 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -236,6 +236,15 @@
     /** Clear timer error - CEC is disabled. */
     public static final int CLEAR_TIMER_STATUS_CEC_DISABLE = 0xA2;
 
+    /** The HdmiControlService is started. */
+    public static final int CONTROL_STATE_CHANGED_REASON_START = 0;
+    /** The state of HdmiControlService is changed by changing of settings. */
+    public static final int CONTROL_STATE_CHANGED_REASON_SETTING = 1;
+    /** The HdmiControlService is enabled to wake up. */
+    public static final int CONTROL_STATE_CHANGED_REASON_WAKEUP = 2;
+    /** The HdmiControlService will be disabled to standby. */
+    public static final int CONTROL_STATE_CHANGED_REASON_STANDBY = 3;
+
     // True if we have a logical device of type playback hosted in the system.
     private final boolean mHasPlaybackDevice;
     // True if we have a logical device of type TV hosted in the system.
@@ -339,11 +348,29 @@
          * Called when a vendor command is received.
          *
          * @param srcAddress source logical address
+         * @param destAddress destination logical address
          * @param params vendor-specific parameters
          * @param hasVendorId {@code true} if the command is &lt;Vendor Command
          *        With ID&gt;. The first 3 bytes of params is vendor id.
          */
-        void onReceived(int srcAddress, byte[] params, boolean hasVendorId);
+        void onReceived(int srcAddress, int destAddress, byte[] params, boolean hasVendorId);
+
+        /**
+         * The callback is called:
+         * <ul>
+         *     <li> before HdmiControlService is disabled.
+         *     <li> after HdmiControlService is enabled and the local address is assigned.
+         * </ul>
+         * The client shouldn't hold the thread too long since this is a blocking call.
+         *
+         * @param enabled {@code true} if HdmiControlService is enabled.
+         * @param reason the reason code why the state of HdmiControlService is changed.
+         * @see #CONTROL_STATE_CHANGED_REASON_START
+         * @see #CONTROL_STATE_CHANGED_REASON_SETTING
+         * @see #CONTROL_STATE_CHANGED_REASON_WAKEUP
+         * @see #CONTROL_STATE_CHANGED_REASON_STANDBY
+         */
+        void onControlStateChanged(boolean enabled, int reason);
     }
 
     /**
diff --git a/core/java/android/hardware/hdmi/HdmiRecordSources.java b/core/java/android/hardware/hdmi/HdmiRecordSources.java
index dcc41fa..c294f72 100644
--- a/core/java/android/hardware/hdmi/HdmiRecordSources.java
+++ b/core/java/android/hardware/hdmi/HdmiRecordSources.java
@@ -55,8 +55,10 @@
 
     /**
      * Base class for each record source.
+     * @hide
      */
-    static abstract class RecordSource {
+    @SystemApi
+    public static abstract class RecordSource {
         protected final int mSourceType;
         protected final int mExtraDataSize;
 
diff --git a/core/java/android/hardware/hdmi/HdmiTvClient.java b/core/java/android/hardware/hdmi/HdmiTvClient.java
index 9d92fd9..683d04b 100644
--- a/core/java/android/hardware/hdmi/HdmiTvClient.java
+++ b/core/java/android/hardware/hdmi/HdmiTvClient.java
@@ -22,6 +22,9 @@
 import android.os.RemoteException;
 import android.util.Log;
 
+import java.util.Collections;
+import java.util.List;
+
 import libcore.util.EmptyArray;
 
 /**
@@ -150,6 +153,21 @@
     }
 
     /**
+     * Returns all the CEC devices connected to TV.
+     *
+     * @return list of {@link HdmiDeviceInfo} for connected CEC devices.
+     *         Empty list is returned if there is none.
+     */
+    public List<HdmiDeviceInfo> getDeviceList() {
+        try {
+            return mService.getDeviceList();
+        } catch (RemoteException e) {
+            Log.e("TAG", "Failed to call getDeviceList():", e);
+            return Collections.<HdmiDeviceInfo>emptyList();
+        }
+    }
+
+    /**
      * Set system audio volume
      *
      * @param oldIndex current volume index
diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
index 4866a9a..c1e924e 100644
--- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -59,6 +59,7 @@
     void setSystemAudioMute(boolean mute);
     void setInputChangeListener(IHdmiInputChangeListener listener);
     List<HdmiDeviceInfo> getInputDevices();
+    List<HdmiDeviceInfo> getDeviceList();
     void sendVendorCommand(int deviceType, int targetAddress, in byte[] params,
             boolean hasVendorId);
     void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType);
diff --git a/core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl b/core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl
index 55cc925..a16e878 100644
--- a/core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl
@@ -23,5 +23,6 @@
  * @hide
  */
 oneway interface IHdmiVendorCommandListener {
-    void onReceived(int logicalAddress, in byte[] operands, boolean hasVendorId);
+    void onReceived(int logicalAddress, int destAddress, in byte[] operands, boolean hasVendorId);
+    void onControlStateChanged(boolean enabled, int reason);
 }
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index 58f0fc0..4fa0593 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -21,7 +21,9 @@
 import android.os.Parcel;
 import android.system.ErrnoException;
 
+import java.io.FileDescriptor;
 import java.io.IOException;
+import java.net.DatagramSocket;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.MalformedURLException;
@@ -264,18 +266,40 @@
     }
 
     /**
+     * Binds the specified {@link DatagramSocket} to this {@code Network}. All data traffic on the
+     * socket will be sent on this {@code Network}, irrespective of any process-wide network binding
+     * set by {@link ConnectivityManager#setProcessDefaultNetwork}. The socket must not be
+     * connected.
+     */
+    public void bindSocket(DatagramSocket socket) throws IOException {
+        // Apparently, the kernel doesn't update a connected UDP socket's routing upon mark changes.
+        if (socket.isConnected()) {
+            throw new SocketException("Socket is connected");
+        }
+        // Query a property of the underlying socket to ensure that the socket's file descriptor
+        // exists, is available to bind to a network and is not closed.
+        socket.getReuseAddress();
+        bindSocketFd(socket.getFileDescriptor$());
+    }
+
+    /**
      * Binds the specified {@link Socket} to this {@code Network}. All data traffic on the socket
      * will be sent on this {@code Network}, irrespective of any process-wide network binding set by
      * {@link ConnectivityManager#setProcessDefaultNetwork}. The socket must not be connected.
      */
     public void bindSocket(Socket socket) throws IOException {
+        // Apparently, the kernel doesn't update a connected TCP socket's routing upon mark changes.
         if (socket.isConnected()) {
             throw new SocketException("Socket is connected");
         }
-        // Query a property of the underlying socket to ensure the underlying
-        // socket exists so a file descriptor is available to bind to a network.
+        // Query a property of the underlying socket to ensure that the socket's file descriptor
+        // exists, is available to bind to a network and is not closed.
         socket.getReuseAddress();
-        int err = NetworkUtils.bindSocketToNetwork(socket.getFileDescriptor$().getInt$(), netId);
+        bindSocketFd(socket.getFileDescriptor$());
+    }
+
+    private void bindSocketFd(FileDescriptor fd) throws IOException {
+        int err = NetworkUtils.bindSocketToNetwork(fd.getInt$(), netId);
         if (err != 0) {
             // bindSocketToNetwork returns negative errno.
             throw new ErrnoException("Binding socket to network " + netId, -err)
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 24cdd77..f361695b 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -588,6 +588,11 @@
          * </ul>
          */
         public static final int LOLLIPOP = 21;
+
+        /**
+         * Lollipop with an extra sugar coating on the outside!
+         */
+        public static final int LOLLIPOP_MR1 = 22;
     }
     
     /** The type of build, like "user" or "eng". */
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 18730b6..084ca30 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -1093,7 +1093,15 @@
     /** @hide */
     public static final int MEMINFO_ZRAM_TOTAL = 8;
     /** @hide */
-    public static final int MEMINFO_COUNT = 9;
+    public static final int MEMINFO_MAPPED = 9;
+    /** @hide */
+    public static final int MEMINFO_VM_ALLOC_USED = 10;
+    /** @hide */
+    public static final int MEMINFO_PAGE_TABLES = 11;
+    /** @hide */
+    public static final int MEMINFO_KERNEL_STACK = 12;
+    /** @hide */
+    public static final int MEMINFO_COUNT = 13;
 
     /**
      * Retrieves /proc/meminfo.  outSizes is filled with fields
diff --git a/core/java/android/preference/ListPreference.java b/core/java/android/preference/ListPreference.java
index 8081a54..9482a72 100644
--- a/core/java/android/preference/ListPreference.java
+++ b/core/java/android/preference/ListPreference.java
@@ -162,10 +162,10 @@
     @Override
     public CharSequence getSummary() {
         final CharSequence entry = getEntry();
-        if (mSummary == null || entry == null) {
+        if (mSummary == null) {
             return super.getSummary();
         } else {
-            return String.format(mSummary, entry);
+            return String.format(mSummary, entry == null ? "" : entry);
         }
     }
 
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index 671f722..3130b64 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -47,7 +47,6 @@
     }
 
     private final Context mContext;
-    private final Handler mHandler;
     private final H mUiHandler = new H();
     private final Callback mCallback;
     private final Uri mDefaultUri;
@@ -55,8 +54,9 @@
     private final int mStreamType;
     private final int mMaxStreamVolume;
     private final Receiver mReceiver = new Receiver();
-    private final Observer mVolumeObserver;
 
+    private Handler mHandler;
+    private Observer mVolumeObserver;
     private int mOriginalStreamVolume;
     private Ringtone mRingtone;
     private int mLastProgress = -1;
@@ -75,16 +75,8 @@
         mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
         mStreamType = streamType;
         mMaxStreamVolume = mAudioManager.getStreamMaxVolume(mStreamType);
-        HandlerThread thread = new HandlerThread(TAG + ".CallbackHandler");
-        thread.start();
-        mHandler = new Handler(thread.getLooper(), this);
         mCallback = callback;
         mOriginalStreamVolume = mAudioManager.getStreamVolume(mStreamType);
-        mVolumeObserver = new Observer(mHandler);
-        mContext.getContentResolver().registerContentObserver(
-                System.getUriFor(System.VOLUME_SETTINGS[mStreamType]),
-                false, mVolumeObserver);
-        mReceiver.setListening(true);
         if (defaultUri == null) {
             if (mStreamType == AudioManager.STREAM_RING) {
                 defaultUri = Settings.System.DEFAULT_RINGTONE_URI;
@@ -95,7 +87,6 @@
             }
         }
         mDefaultUri = defaultUri;
-        mHandler.sendEmptyMessage(MSG_INIT_SAMPLE);
     }
 
     public void setSeekBar(SeekBar seekBar) {
@@ -139,6 +130,7 @@
     }
 
     private void postStartSample() {
+        if (mHandler == null) return;
         mHandler.removeMessages(MSG_START_SAMPLE);
         mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_SAMPLE),
                 isSamplePlaying() ? CHECK_RINGTONE_PLAYBACK_DELAY_MS : 0);
@@ -159,7 +151,8 @@
         }
     }
 
-    void postStopSample() {
+    private void postStopSample() {
+        if (mHandler == null) return;
         // remove pending delayed start messages
         mHandler.removeMessages(MSG_START_SAMPLE);
         mHandler.removeMessages(MSG_STOP_SAMPLE);
@@ -173,11 +166,27 @@
     }
 
     public void stop() {
+        if (mHandler == null) return;  // already stopped
         postStopSample();
         mContext.getContentResolver().unregisterContentObserver(mVolumeObserver);
-        mSeekBar.setOnSeekBarChangeListener(null);
         mReceiver.setListening(false);
+        mSeekBar.setOnSeekBarChangeListener(null);
         mHandler.getLooper().quitSafely();
+        mHandler = null;
+        mVolumeObserver = null;
+    }
+
+    public void start() {
+        if (mHandler != null) return;  // already started
+        HandlerThread thread = new HandlerThread(TAG + ".CallbackHandler");
+        thread.start();
+        mHandler = new Handler(thread.getLooper(), this);
+        mHandler.sendEmptyMessage(MSG_INIT_SAMPLE);
+        mVolumeObserver = new Observer(mHandler);
+        mContext.getContentResolver().registerContentObserver(
+                System.getUriFor(System.VOLUME_SETTINGS[mStreamType]),
+                false, mVolumeObserver);
+        mReceiver.setListening(true);
     }
 
     public void revertVolume() {
@@ -193,7 +202,8 @@
         postSetVolume(progress);
     }
 
-    void postSetVolume(int progress) {
+    private void postSetVolume(int progress) {
+        if (mHandler == null) return;
         // Do the volume changing separately to give responsive UI
         mLastProgress = progress;
         mHandler.removeMessages(MSG_SET_STREAM_VOLUME);
diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java
index df9e10e..0d4c0b6 100644
--- a/core/java/android/preference/VolumePreference.java
+++ b/core/java/android/preference/VolumePreference.java
@@ -67,6 +67,7 @@
 
         final SeekBar seekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar);
         mSeekBarVolumizer = new SeekBarVolumizer(getContext(), mStreamType, null, this);
+        mSeekBarVolumizer.start();
         mSeekBarVolumizer.setSeekBar(seekBar);
 
         getPreferenceManager().registerOnActivityStopListener(this);
@@ -116,7 +117,7 @@
 
     public void onActivityStop() {
         if (mSeekBarVolumizer != null) {
-            mSeekBarVolumizer.postStopSample();
+            mSeekBarVolumizer.stopSample();
         }
     }
 
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b1c338e..98a1f05 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5013,10 +5013,19 @@
                     default:
                         throw new IllegalArgumentException("Invalid location mode: " + mode);
                 }
-                boolean gpsSuccess = Settings.Secure.setLocationProviderEnabledForUser(
-                        cr, LocationManager.GPS_PROVIDER, gps, userId);
+                // Note it's important that we set the NLP mode first. The Google implementation
+                // of NLP clears its NLP consent setting any time it receives a
+                // LocationManager.PROVIDERS_CHANGED_ACTION broadcast and NLP is disabled. Also,
+                // it shows an NLP consent dialog any time it receives the broadcast, NLP is
+                // enabled, and the NLP consent is not set. If 1) we were to enable GPS first,
+                // 2) a setup wizard has its own NLP consent UI that sets the NLP consent setting,
+                // and 3) the receiver happened to complete before we enabled NLP, then the Google
+                // NLP would detect the attempt to enable NLP and show a redundant NLP consent
+                // dialog. Then the people who wrote the setup wizard would be sad.
                 boolean nlpSuccess = Settings.Secure.setLocationProviderEnabledForUser(
                         cr, LocationManager.NETWORK_PROVIDER, network, userId);
+                boolean gpsSuccess = Settings.Secure.setLocationProviderEnabledForUser(
+                        cr, LocationManager.GPS_PROVIDER, gps, userId);
                 return gpsSuccess && nlpSuccess;
             }
         }
@@ -6585,6 +6594,14 @@
         public static final String REQUIRE_PASSWORD_TO_DECRYPT = "require_password_to_decrypt";
 
         /**
+         * Whether the Volte/VT is enabled
+         * <p>
+         * Type: int (0 for false, 1 for true)
+         * @hide
+         */
+        public static final String ENHANCED_4G_MODE_ENABLED = "volte_vt_enabled";
+
+        /**
          * Settings to backup. This is here so that it's in the same place as the settings
          * keys and easy to update.
          *
diff --git a/core/java/android/transition/ChangeBounds.java b/core/java/android/transition/ChangeBounds.java
index 0da5fb6..2c55141 100644
--- a/core/java/android/transition/ChangeBounds.java
+++ b/core/java/android/transition/ChangeBounds.java
@@ -16,6 +16,7 @@
 
 package android.transition;
 
+import android.animation.AnimatorSet;
 import android.content.Context;
 import android.graphics.PointF;
 
@@ -31,7 +32,6 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
-import android.util.IntProperty;
 import android.util.Property;
 import android.view.View;
 import android.view.ViewGroup;
@@ -77,6 +77,32 @@
                 }
     };
 
+    private static final Property<ViewBounds, PointF> TOP_LEFT_PROPERTY =
+            new Property<ViewBounds, PointF>(PointF.class, "topLeft") {
+                @Override
+                public void set(ViewBounds viewBounds, PointF topLeft) {
+                    viewBounds.setTopLeft(topLeft);
+                }
+
+                @Override
+                public PointF get(ViewBounds viewBounds) {
+                    return null;
+                }
+            };
+
+    private static final Property<ViewBounds, PointF> BOTTOM_RIGHT_PROPERTY =
+            new Property<ViewBounds, PointF>(PointF.class, "bottomRight") {
+                @Override
+                public void set(ViewBounds viewBounds, PointF bottomRight) {
+                    viewBounds.setBottomRight(bottomRight);
+                }
+
+                @Override
+                public PointF get(ViewBounds viewBounds) {
+                    return null;
+                }
+            };
+
     int[] tempLocation = new int[2];
     boolean mResizeClip = false;
     boolean mReparent = false;
@@ -189,36 +215,20 @@
             }
             if (numChanges > 0) {
                 if (!mResizeClip) {
-                    Animator anim;
-                    if (startWidth == endWidth && startHeight == endHeight) {
-                        view.offsetLeftAndRight(startLeft - view.getLeft());
-                        view.offsetTopAndBottom(startTop - view.getTop());
-                        Path positionPath = getPathMotion().getPath(0, 0, endLeft - startLeft,
-                                endTop - startTop);
-                        anim = ObjectAnimator.ofInt(view, new HorizontalOffsetProperty(),
-                                new VerticalOffsetProperty(), positionPath);
-                    } else {
-                        if (startLeft != endLeft) view.setLeft(startLeft);
-                        if (startTop != endTop) view.setTop(startTop);
-                        if (startRight != endRight) view.setRight(startRight);
-                        if (startBottom != endBottom) view.setBottom(startBottom);
-                        ObjectAnimator topLeftAnimator = null;
-                        if (startLeft != endLeft || startTop != endTop) {
-                            Path topLeftPath = getPathMotion().getPath(startLeft, startTop,
-                                    endLeft, endTop);
-                            topLeftAnimator = ObjectAnimator
-                                    .ofInt(view, "left", "top", topLeftPath);
-                        }
-                        ObjectAnimator bottomRightAnimator = null;
-                        if (startRight != endRight || startBottom != endBottom) {
-                            Path bottomRightPath = getPathMotion().getPath(startRight, startBottom,
-                                    endRight, endBottom);
-                            bottomRightAnimator = ObjectAnimator.ofInt(view, "right", "bottom",
-                                    bottomRightPath);
-                        }
-                        anim = TransitionUtils.mergeAnimators(topLeftAnimator,
-                                bottomRightAnimator);
-                    }
+                    view.setLeftTopRightBottom(startLeft, startTop, startRight, startBottom);
+                    ViewBounds viewBounds = new ViewBounds(view);
+                    Path topLeftPath = getPathMotion().getPath(startLeft, startTop,
+                            endLeft, endTop);
+                    ObjectAnimator topLeftAnimator = ObjectAnimator
+                            .ofObject(viewBounds, TOP_LEFT_PROPERTY, null, topLeftPath);
+
+                    Path bottomRightPath = getPathMotion().getPath(startRight, startBottom,
+                            endRight, endBottom);
+                    ObjectAnimator bottomRightAnimator = ObjectAnimator.ofObject(viewBounds,
+                            BOTTOM_RIGHT_PROPERTY, null, bottomRightPath);
+                    AnimatorSet anim = new AnimatorSet();
+                    anim.playTogether(topLeftAnimator, bottomRightAnimator);
+
                     if (view.getParent() instanceof ViewGroup) {
                         final ViewGroup parent = (ViewGroup) view.getParent();
                         parent.suppressLayout(true);
@@ -357,47 +367,41 @@
         return null;
     }
 
-    private abstract static class OffsetProperty extends IntProperty<View> {
-        int mPreviousValue;
+    private static class ViewBounds {
+        private int mLeft;
+        private int mTop;
+        private int mRight;
+        private int mBottom;
+        private boolean mIsTopLeftSet;
+        private boolean mIsBottomRightSet;
+        private View mView;
 
-        public OffsetProperty(String name) {
-            super(name);
+        public ViewBounds(View view) {
+            mView = view;
         }
 
-        @Override
-        public void setValue(View view, int value) {
-            int offset = value - mPreviousValue;
-            offsetBy(view, offset);
-            mPreviousValue = value;
+        public void setTopLeft(PointF topLeft) {
+            mLeft = Math.round(topLeft.x);
+            mTop = Math.round(topLeft.y);
+            mIsTopLeftSet = true;
+            if (mIsBottomRightSet) {
+                setLeftTopRightBottom();
+            }
         }
 
-        @Override
-        public Integer get(View object) {
-            return null;
+        public void setBottomRight(PointF bottomRight) {
+            mRight = Math.round(bottomRight.x);
+            mBottom = Math.round(bottomRight.y);
+            mIsBottomRightSet = true;
+            if (mIsTopLeftSet) {
+                setLeftTopRightBottom();
+            }
         }
 
-        protected abstract void offsetBy(View view, int by);
-    }
-
-    private static class HorizontalOffsetProperty extends OffsetProperty {
-        public HorizontalOffsetProperty() {
-            super("offsetLeftAndRight");
-        }
-
-        @Override
-        protected void offsetBy(View view, int by) {
-            view.offsetLeftAndRight(by);
-        }
-    }
-
-    private static class VerticalOffsetProperty extends OffsetProperty {
-        public VerticalOffsetProperty() {
-            super("offsetTopAndBottom");
-        }
-
-        @Override
-        protected void offsetBy(View view, int by) {
-            view.offsetTopAndBottom(by);
+        private void setLeftTopRightBottom() {
+            mView.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom);
+            mIsTopLeftSet = false;
+            mIsBottomRightSet = false;
         }
     }
 }
diff --git a/core/java/android/util/PathParser.java b/core/java/android/util/PathParser.java
index 6820f77..e5f3b2c 100644
--- a/core/java/android/util/PathParser.java
+++ b/core/java/android/util/PathParser.java
@@ -34,7 +34,11 @@
         Path path = new Path();
         PathDataNode[] nodes = createNodesFromPathData(pathData);
         if (nodes != null) {
-            PathDataNode.nodesToPath(nodes, path);
+            try {
+                PathDataNode.nodesToPath(nodes, path);
+            } catch (RuntimeException e) {
+                throw new RuntimeException("Error in parsing " + pathData, e);
+            }
             return path;
         }
         return null;
@@ -128,7 +132,12 @@
 
         while (end < s.length()) {
             c = s.charAt(end);
-            if (((c - 'A') * (c - 'Z') <= 0) || (((c - 'a') * (c - 'z') <= 0))) {
+            // Note that 'e' or 'E' are not valid path commands, but could be
+            // used for floating point numbers' scientific notation.
+            // Therefore, when searching for next command, we should ignore 'e'
+            // and 'E'.
+            if ((((c - 'A') * (c - 'Z') <= 0) || ((c - 'a') * (c - 'z') <= 0))
+                    && c != 'e' && c != 'E') {
                 return end;
             }
             end++;
@@ -142,9 +151,9 @@
 
     private static class ExtractFloatResult {
         // We need to return the position of the next separator and whether the
-        // next float starts with a '-'.
+        // next float starts with a '-' or a '.'.
         int mEndPosition;
-        boolean mEndWithNegSign;
+        boolean mEndWithNegOrDot;
     }
 
     /**
@@ -179,8 +188,8 @@
                             s.substring(startPosition, endPosition));
                 }
 
-                if (result.mEndWithNegSign) {
-                    // Keep the '-' sign with next number.
+                if (result.mEndWithNegOrDot) {
+                    // Keep the '-' or '.' sign with next number.
                     startPosition = endPosition;
                 } else {
                     startPosition = endPosition + 1;
@@ -188,8 +197,7 @@
             }
             return Arrays.copyOf(results, count);
         } catch (NumberFormatException e) {
-            Log.e(LOGTAG, "error in parsing \"" + s + "\"");
-            throw e;
+            throw new RuntimeException("error in parsing \"" + s + "\"", e);
         }
     }
 
@@ -201,11 +209,15 @@
      * the starting position of next number, whether it is ending with a '-'.
      */
     private static void extract(String s, int start, ExtractFloatResult result) {
-        // Now looking for ' ', ',' or '-' from the start.
+        // Now looking for ' ', ',', '.' or '-' from the start.
         int currentIndex = start;
         boolean foundSeparator = false;
-        result.mEndWithNegSign = false;
+        result.mEndWithNegOrDot = false;
+        boolean secondDot = false;
+        boolean isExponential = false;
         for (; currentIndex < s.length(); currentIndex++) {
+            boolean isPrevExponential = isExponential;
+            isExponential = false;
             char currentChar = s.charAt(currentIndex);
             switch (currentChar) {
                 case ' ':
@@ -213,11 +225,25 @@
                     foundSeparator = true;
                     break;
                 case '-':
-                    if (currentIndex != start) {
+                    // The negative sign following a 'e' or 'E' is not a separator.
+                    if (currentIndex != start && !isPrevExponential) {
                         foundSeparator = true;
-                        result.mEndWithNegSign = true;
+                        result.mEndWithNegOrDot = true;
                     }
                     break;
+                case '.':
+                    if (!secondDot) {
+                        secondDot = true;
+                    } else {
+                        // This is the second dot, and it is considered as a separator.
+                        foundSeparator = true;
+                        result.mEndWithNegOrDot = true;
+                    }
+                    break;
+                case 'e':
+                case 'E':
+                    isExponential = true;
+                    break;
             }
             if (foundSeparator) {
                 break;
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 132e25c..562d138 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -311,7 +311,10 @@
      * Unlike {@link #lockCanvas(Rect)} this will return a hardware-accelerated
      * canvas. See the <a href="{@docRoot}guide/topics/graphics/hardware-accel.html#unsupported">
      * unsupported drawing operations</a> for a list of what is and isn't
-     * supported in a hardware-accelerated canvas.
+     * supported in a hardware-accelerated canvas. It is also required to
+     * fully cover the surface every time {@link #lockHardwareCanvas()} is
+     * called as the buffer is not preserved between frames. Partial updates
+     * are not supported.
      *
      * @return A canvas for drawing into the surface.
      *
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 1ecc8d9..8664a24 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -15699,6 +15699,14 @@
         return changed;
     }
 
+    /**
+     * Same as setFrame, but public and hidden. For use in {@link android.transition.ChangeBounds}.
+     * @hide
+     */
+    public void setLeftTopRightBottom(int left, int top, int right, int bottom) {
+        setFrame(left, top, right, bottom);
+    }
+
     private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) {
         onSizeChanged(newWidth, newHeight, oldWidth, oldHeight);
         if (mOverlay != null) {
@@ -16617,8 +16625,12 @@
             invalidate(true);
             refreshDrawableState();
             dispatchSetSelected(selected);
-            notifyViewAccessibilityStateChangedIfNeeded(
-                    AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+            if (selected) {
+                sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
+            } else {
+                notifyViewAccessibilityStateChangedIfNeeded(
+                        AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+            }
         }
     }
 
@@ -17414,17 +17426,22 @@
         long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL;
         if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2);
 
-        if ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ||
-                widthMeasureSpec != mOldWidthMeasureSpec ||
-                heightMeasureSpec != mOldHeightMeasureSpec) {
+        final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT;
+        final boolean isExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY &&
+                MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY;
+        final boolean matchingSize = isExactly &&
+                getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec) &&
+                getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec);
+        if (forceLayout || !matchingSize &&
+                (widthMeasureSpec != mOldWidthMeasureSpec ||
+                        heightMeasureSpec != mOldHeightMeasureSpec)) {
 
             // first clears the measured dimension flag
             mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET;
 
             resolveRtlPropertiesIfNeeded();
 
-            int cacheIndex = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ? -1 :
-                    mMeasureCache.indexOfKey(key);
+            int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key);
             if (cacheIndex < 0 || sIgnoreMeasureCache) {
                 // measure ourselves, this should set the measured dimension flag back
                 onMeasure(widthMeasureSpec, heightMeasureSpec);
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 12a49d5..50e64c6 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -1005,12 +1005,21 @@
             return fields;
         }
 
-        final ArrayList<Field> foundFields = new ArrayList<Field>();
-        fields = klass.getDeclaredFields();
+        final ArrayList<Field> declaredFields = new ArrayList();
+        klass.getDeclaredFieldsUnchecked(false, declaredFields);
 
-        int count = fields.length;
+        final ArrayList<Field> foundFields = new ArrayList<Field>();
+        final int count = declaredFields.size();
         for (int i = 0; i < count; i++) {
-            final Field field = fields[i];
+            final Field field = declaredFields.get(i);
+
+            // Ensure the field type can be resolved.
+            try {
+                field.getType();
+            } catch (NoClassDefFoundError e) {
+                continue;
+            }
+
             if (field.isAnnotationPresent(ExportedProperty.class)) {
                 field.setAccessible(true);
                 foundFields.add(field);
@@ -1039,12 +1048,22 @@
             return methods;
         }
 
-        final ArrayList<Method> foundMethods = new ArrayList<Method>();
-        methods = klass.getDeclaredMethods();
+        final ArrayList<Method> declaredMethods = new ArrayList();
+        klass.getDeclaredMethodsUnchecked(false, declaredMethods);
 
-        int count = methods.length;
+        final ArrayList<Method> foundMethods = new ArrayList<Method>();
+        final int count = declaredMethods.size();
         for (int i = 0; i < count; i++) {
-            final Method method = methods[i];
+            final Method method = declaredMethods.get(i);
+
+            // Ensure the method return and parameter types can be resolved.
+            try {
+                method.getReturnType();
+                method.getParameterTypes();
+            } catch (NoClassDefFoundError e) {
+                continue;
+            }
+
             if (method.getParameterTypes().length == 0 &&
                     method.isAnnotationPresent(ExportedProperty.class) &&
                     method.getReturnType() != Void.class) {
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 4116b6b..134171a 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -864,6 +864,7 @@
             if (siblingBounds.intersect(bounds)) {
                 // If an interactive sibling completely covers the child, done.
                 if (siblingBounds.equals(bounds)) {
+                    if (orderedList != null) orderedList.clear();
                     return false;
                 }
                 // Keep track of the intersection rectangle.
@@ -871,6 +872,7 @@
                 intersections.add(intersection);
             }
         }
+        if (orderedList != null) orderedList.clear();
 
         if (mParent instanceof ViewGroup) {
             ViewGroup parentGroup = (ViewGroup) mParent;
@@ -3293,7 +3295,8 @@
 
     /**
      * Populates (and returns) mPreSortedChildren with a pre-ordered list of the View's children,
-     * sorted first by Z, then by child drawing order (if applicable).
+     * sorted first by Z, then by child drawing order (if applicable). This list must be cleared
+     * after use to avoid leaking child Views.
      *
      * Uses a stable, insertion sort which is commonly O(n) for ViewGroups with very few elevated
      * children.
@@ -3668,6 +3671,9 @@
      * @see #generateDefaultLayoutParams()
      */
     public void addView(View child, int index) {
+        if (child == null) {
+            throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
+        }
         LayoutParams params = child.getLayoutParams();
         if (params == null) {
             params = generateDefaultLayoutParams();
@@ -3725,6 +3731,10 @@
             System.out.println(this + " addView");
         }
 
+        if (child == null) {
+            throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
+        }
+
         // addViewInner() will call child.requestLayout() when setting the new LayoutParams
         // therefore, we call requestLayout() on ourselves before, so that the child's request
         // will be blocked at our level
@@ -3852,6 +3862,9 @@
      */
     protected boolean addViewInLayout(View child, int index, LayoutParams params,
             boolean preventRequestLayout) {
+        if (child == null) {
+            throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
+        }
         child.mParent = null;
         addViewInner(child, index, params, preventRequestLayout);
         child.mPrivateFlags = (child.mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
@@ -4065,9 +4078,10 @@
      * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
      */
     public void removeView(View view) {
-        removeViewInternal(view);
-        requestLayout();
-        invalidate(true);
+        if (removeViewInternal(view)) {
+            requestLayout();
+            invalidate(true);
+        }
     }
 
     /**
@@ -4130,11 +4144,13 @@
         invalidate(true);
     }
 
-    private void removeViewInternal(View view) {
+    private boolean removeViewInternal(View view) {
         final int index = indexOfChild(view);
         if (index >= 0) {
             removeViewInternal(index, view);
+            return true;
         }
+        return false;
     }
 
     private void removeViewInternal(int index, View view) {
@@ -6488,7 +6504,7 @@
      */
     public static class MarginLayoutParams extends ViewGroup.LayoutParams {
         /**
-         * The left margin in pixels of the child.
+         * The left margin in pixels of the child. Margin values should be positive.
          * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
          * to this field.
          */
@@ -6496,7 +6512,7 @@
         public int leftMargin;
 
         /**
-         * The top margin in pixels of the child.
+         * The top margin in pixels of the child. Margin values should be positive.
          * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
          * to this field.
          */
@@ -6504,7 +6520,7 @@
         public int topMargin;
 
         /**
-         * The right margin in pixels of the child.
+         * The right margin in pixels of the child. Margin values should be positive.
          * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
          * to this field.
          */
@@ -6512,7 +6528,7 @@
         public int rightMargin;
 
         /**
-         * The bottom margin in pixels of the child.
+         * The bottom margin in pixels of the child. Margin values should be positive.
          * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
          * to this field.
          */
@@ -6520,7 +6536,7 @@
         public int bottomMargin;
 
         /**
-         * The start margin in pixels of the child.
+         * The start margin in pixels of the child. Margin values should be positive.
          * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
          * to this field.
          */
@@ -6528,7 +6544,7 @@
         private int startMargin = DEFAULT_MARGIN_RELATIVE;
 
         /**
-         * The end margin in pixels of the child.
+         * The end margin in pixels of the child. Margin values should be positive.
          * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
          * to this field.
          */
@@ -6709,6 +6725,7 @@
          * Sets the margins, in pixels. A call to {@link android.view.View#requestLayout()} needs
          * to be done so that the new margins are taken into account. Left and right margins may be
          * overriden by {@link android.view.View#requestLayout()} depending on layout direction.
+         * Margin values should be positive.
          *
          * @param left the left margin size
          * @param top the top margin size
@@ -6738,7 +6755,7 @@
          * Sets the relative margins, in pixels. A call to {@link android.view.View#requestLayout()}
          * needs to be done so that the new relative margins are taken into account. Left and right
          * margins may be overriden by {@link android.view.View#requestLayout()} depending on layout
-         * direction.
+         * direction. Margin values should be positive.
          *
          * @param start the start margin size
          * @param top the top margin size
@@ -6761,7 +6778,7 @@
         }
 
         /**
-         * Sets the relative start margin.
+         * Sets the relative start margin. Margin values should be positive.
          *
          * @param start the start margin size
          *
@@ -6794,7 +6811,7 @@
         }
 
         /**
-         * Sets the relative end margin.
+         * Sets the relative end margin. Margin values should be positive.
          *
          * @param end the end margin size
          *
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 63ab7d2..ef073b5 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -24,7 +24,6 @@
 import android.graphics.PixelFormat;
 import android.graphics.drawable.Drawable;
 import android.media.session.MediaController;
-import android.media.session.MediaSession;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -801,9 +800,6 @@
     public void setFlags(int flags, int mask) {
         final WindowManager.LayoutParams attrs = getAttributes();
         attrs.flags = (attrs.flags&~mask) | (flags&mask);
-        if ((mask&WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY) != 0) {
-            attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SET_NEEDS_MENU_KEY;
-        }
         mForcedWindowFlags |= mask;
         dispatchWindowAttributesChanged(attrs);
     }
@@ -817,6 +813,15 @@
     /**
      * {@hide}
      */
+    protected void setNeedsMenuKey(int value) {
+        final WindowManager.LayoutParams attrs = getAttributes();
+        attrs.needsMenuKey = value;
+        dispatchWindowAttributesChanged(attrs);
+    }
+
+    /**
+     * {@hide}
+     */
     protected void dispatchWindowAttributesChanged(WindowManager.LayoutParams attrs) {
         if (mCallback != null) {
             mCallback.onWindowAttributesChanged(attrs);
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 47ee52e..3f84c9b 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -523,15 +523,6 @@
         public static final int TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27;
 
         /**
-         * Window type: Recents. Same layer as {@link #TYPE_SYSTEM_DIALOG} but only appears on
-         * one user's screen.
-         * In multiuser systems shows on all users' windows.
-         * @hide
-         */
-        public static final int TYPE_RECENTS_OVERLAY = FIRST_SYSTEM_WINDOW+28;
-
-
-        /**
          * Window type: keyguard scrim window. Shows if keyguard needs to be restarted.
          * In multiuser systems shows on all users' windows.
          * @hide
@@ -887,9 +878,6 @@
          */
         public static final int FLAG_TRANSLUCENT_NAVIGATION = 0x08000000;
 
-        // ----- HIDDEN FLAGS.
-        // These start at the high bit and go down.
-
         /**
          * Flag for a window in local focus mode.
          * Window in local focus mode can control focus independent of window manager using
@@ -912,17 +900,12 @@
         public static final int FLAG_SLIPPERY = 0x20000000;
 
         /**
-         * Flag for a window belonging to an activity that responds to {@link KeyEvent#KEYCODE_MENU}
-         * and therefore needs a Menu key. For devices where Menu is a physical button this flag is
-         * ignored, but on devices where the Menu key is drawn in software it may be hidden unless
-         * this flag is set.
-         *
-         * (Note that Action Bars, when available, are the preferred way to offer additional
-         * functions otherwise accessed via an options menu.)
-         *
-         * {@hide}
+         * Window flag: When requesting layout with an attached window, the attached window may
+         * overlap with the screen decorations of the parent window such as the navigation bar. By
+         * including this flag, the window manager will layout the attached window within the decor
+         * frame of the parent window such that it doesn't overlap with screen decorations.
          */
-        public static final int FLAG_NEEDS_MENU_KEY = 0x40000000;
+        public static final int FLAG_LAYOUT_ATTACHED_IN_DECOR = 0x40000000;
 
         /**
          * Flag indicating that this Window is responsible for drawing the background for the
@@ -1065,16 +1048,6 @@
          */
         public static final int PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS = 0x00000004;
 
-        /**
-         * This is set for a window that has explicitly specified its
-         * FLAG_NEEDS_MENU_KEY, so we know the value on this window is the
-         * appropriate one to use.  If this is not set, we should look at
-         * windows behind it to determine the appropriate value.
-         *
-         * @hide
-         */
-        public static final int PRIVATE_FLAG_SET_NEEDS_MENU_KEY = 0x00000008;
-
         /** In a multiuser system if this flag is set and the owner is a system process then this
          * window will appear on all user screens. This overrides the default behavior of window
          * types that normally only appear on the owning user's screen. Refer to each window type
@@ -1122,6 +1095,45 @@
         public int privateFlags;
 
         /**
+         * Value for {@link #needsMenuKey} for a window that has not explicitly specified if it
+         * needs {@link #NEEDS_MENU_SET_TRUE} or doesn't need {@link #NEEDS_MENU_SET_FALSE} a menu
+         * key. For this case, we should look at windows behind it to determine the appropriate
+         * value.
+         *
+         * @hide
+         */
+        public static final int NEEDS_MENU_UNSET = 0;
+
+        /**
+         * Value for {@link #needsMenuKey} for a window that has explicitly specified it needs a
+         * menu key.
+         *
+         * @hide
+         */
+        public static final int NEEDS_MENU_SET_TRUE = 1;
+
+        /**
+         * Value for {@link #needsMenuKey} for a window that has explicitly specified it doesn't
+         * needs a menu key.
+         *
+         * @hide
+         */
+        public static final int NEEDS_MENU_SET_FALSE = 2;
+
+        /**
+         * State variable for a window belonging to an activity that responds to
+         * {@link KeyEvent#KEYCODE_MENU} and therefore needs a Menu key. For devices where Menu is a
+         * physical button this variable is ignored, but on devices where the Menu key is drawn in
+         * software it may be hidden unless this variable is set to {@link #NEEDS_MENU_SET_TRUE}.
+         *
+         *  (Note that Action Bars, when available, are the preferred way to offer additional
+         * functions otherwise accessed via an options menu.)
+         *
+         * {@hide}
+         */
+        public int needsMenuKey = NEEDS_MENU_UNSET;
+
+        /**
          * Given a particular set of window manager flags, determine whether
          * such a window may be a target for an input method when it has
          * focus.  In particular, this checks the
@@ -1129,9 +1141,9 @@
          * flags and returns true if the combination of the two corresponds
          * to a window that needs to be behind the input method so that the
          * user can type into it.
-         * 
+         *
          * @param flags The current window manager flags.
-         * 
+         *
          * @return Returns true if such a window should be behind/interact
          * with an input method, false if not.
          */
@@ -1596,14 +1608,15 @@
             out.writeInt(surfaceInsets.top);
             out.writeInt(surfaceInsets.right);
             out.writeInt(surfaceInsets.bottom);
+            out.writeInt(needsMenuKey);
         }
-        
+
         public static final Parcelable.Creator<LayoutParams> CREATOR
                     = new Parcelable.Creator<LayoutParams>() {
             public LayoutParams createFromParcel(Parcel in) {
                 return new LayoutParams(in);
             }
-    
+
             public LayoutParams[] newArray(int size) {
                 return new LayoutParams[size];
             }
@@ -1643,8 +1656,9 @@
             surfaceInsets.top = in.readInt();
             surfaceInsets.right = in.readInt();
             surfaceInsets.bottom = in.readInt();
+            needsMenuKey = in.readInt();
         }
-    
+
         @SuppressWarnings({"PointlessBitwiseExpression"})
         public static final int LAYOUT_CHANGED = 1<<0;
         public static final int TYPE_CHANGED = 1<<1;
@@ -1678,14 +1692,16 @@
         /** {@hide} */
         public static final int PREFERRED_REFRESH_RATE_CHANGED = 1 << 21;
         /** {@hide} */
+        public static final int NEEDS_MENU_KEY_CHANGED = 1 << 22;
+        /** {@hide} */
         public static final int EVERYTHING_CHANGED = 0xffffffff;
 
         // internal buffer to backup/restore parameters under compatibility mode.
         private int[] mCompatibilityParamsBackup = null;
-        
+
         public final int copyFrom(LayoutParams o) {
             int changes = 0;
-    
+
             if (width != o.width) {
                 width = o.width;
                 changes |= LAYOUT_CHANGED;
@@ -1822,9 +1838,14 @@
                 changes |= SURFACE_INSETS_CHANGED;
             }
 
+            if (needsMenuKey != o.needsMenuKey) {
+                needsMenuKey = o.needsMenuKey;
+                changes |= NEEDS_MENU_KEY_CHANGED;
+            }
+
             return changes;
         }
-    
+
         @Override
         public String debug(String output) {
             output += "Contents of " + this + ":";
@@ -1928,6 +1949,10 @@
             if (!surfaceInsets.equals(Insets.NONE)) {
                 sb.append(" surfaceInsets=").append(surfaceInsets);
             }
+            if (needsMenuKey != NEEDS_MENU_UNSET) {
+                sb.append(" needsMenuKey=");
+                sb.append(needsMenuKey);
+            }
             sb.append('}');
             return sb.toString();
         }
diff --git a/core/java/android/view/animation/AccelerateDecelerateInterpolator.java b/core/java/android/view/animation/AccelerateDecelerateInterpolator.java
index ed6949a..21d5a5b 100644
--- a/core/java/android/view/animation/AccelerateDecelerateInterpolator.java
+++ b/core/java/android/view/animation/AccelerateDecelerateInterpolator.java
@@ -26,17 +26,17 @@
 /**
  * An interpolator where the rate of change starts and ends slowly but
  * accelerates through the middle.
- * 
  */
 @HasNativeInterpolator
-public class AccelerateDecelerateInterpolator implements Interpolator, NativeInterpolatorFactory {
+public class AccelerateDecelerateInterpolator extends BaseInterpolator
+        implements NativeInterpolatorFactory {
     public AccelerateDecelerateInterpolator() {
     }
-    
+
     @SuppressWarnings({"UnusedDeclaration"})
     public AccelerateDecelerateInterpolator(Context context, AttributeSet attrs) {
     }
-    
+
     public float getInterpolation(float input) {
         return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
     }
diff --git a/core/java/android/view/animation/AccelerateInterpolator.java b/core/java/android/view/animation/AccelerateInterpolator.java
index 1c75f16..6c8d7b1 100644
--- a/core/java/android/view/animation/AccelerateInterpolator.java
+++ b/core/java/android/view/animation/AccelerateInterpolator.java
@@ -33,7 +33,7 @@
  *
  */
 @HasNativeInterpolator
-public class AccelerateInterpolator implements Interpolator, NativeInterpolatorFactory {
+public class AccelerateInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
     private final float mFactor;
     private final double mDoubleFactor;
 
@@ -70,7 +70,7 @@
 
         mFactor = a.getFloat(R.styleable.AccelerateInterpolator_factor, 1.0f);
         mDoubleFactor = 2 * mFactor;
-
+        setChangingConfiguration(a.getChangingConfigurations());
         a.recycle();
     }
 
diff --git a/core/java/android/view/animation/AnimationUtils.java b/core/java/android/view/animation/AnimationUtils.java
index af4e04f..606c83e 100644
--- a/core/java/android/view/animation/AnimationUtils.java
+++ b/core/java/android/view/animation/AnimationUtils.java
@@ -321,7 +321,7 @@
     private static Interpolator createInterpolatorFromXml(Resources res, Theme theme, XmlPullParser parser)
             throws XmlPullParserException, IOException {
 
-        Interpolator interpolator = null;
+        BaseInterpolator interpolator = null;
 
         // Make sure we are on a start tag.
         int type;
@@ -361,10 +361,7 @@
             } else {
                 throw new RuntimeException("Unknown interpolator name: " + parser.getName());
             }
-
         }
-
         return interpolator;
-
     }
 }
diff --git a/core/java/android/view/animation/AnticipateInterpolator.java b/core/java/android/view/animation/AnticipateInterpolator.java
index fe756bd..fb66c31 100644
--- a/core/java/android/view/animation/AnticipateInterpolator.java
+++ b/core/java/android/view/animation/AnticipateInterpolator.java
@@ -31,7 +31,7 @@
  * An interpolator where the change starts backward then flings forward.
  */
 @HasNativeInterpolator
-public class AnticipateInterpolator implements Interpolator, NativeInterpolatorFactory {
+public class AnticipateInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
     private final float mTension;
 
     public AnticipateInterpolator() {
@@ -60,9 +60,8 @@
             a = res.obtainAttributes(attrs, R.styleable.AnticipateInterpolator);
         }
 
-        mTension =
-                a.getFloat(R.styleable.AnticipateInterpolator_tension, 2.0f);
-
+        mTension = a.getFloat(R.styleable.AnticipateInterpolator_tension, 2.0f);
+        setChangingConfiguration(a.getChangingConfigurations());
         a.recycle();
     }
 
diff --git a/core/java/android/view/animation/AnticipateOvershootInterpolator.java b/core/java/android/view/animation/AnticipateOvershootInterpolator.java
index 78e5acf..1af72da 100644
--- a/core/java/android/view/animation/AnticipateOvershootInterpolator.java
+++ b/core/java/android/view/animation/AnticipateOvershootInterpolator.java
@@ -35,7 +35,8 @@
  * the target value and finally goes back to the final value.
  */
 @HasNativeInterpolator
-public class AnticipateOvershootInterpolator implements Interpolator, NativeInterpolatorFactory {
+public class AnticipateOvershootInterpolator extends BaseInterpolator
+        implements NativeInterpolatorFactory {
     private final float mTension;
 
     public AnticipateOvershootInterpolator() {
@@ -78,7 +79,7 @@
 
         mTension = a.getFloat(AnticipateOvershootInterpolator_tension, 2.0f) *
                 a.getFloat(AnticipateOvershootInterpolator_extraTension, 1.5f);
-
+        setChangingConfiguration(a.getChangingConfigurations());
         a.recycle();
     }
 
diff --git a/core/java/android/view/animation/BaseInterpolator.java b/core/java/android/view/animation/BaseInterpolator.java
new file mode 100644
index 0000000..9c0014c
--- /dev/null
+++ b/core/java/android/view/animation/BaseInterpolator.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.animation;
+
+/**
+ * An abstract class which is extended by default interpolators.
+ */
+abstract public class BaseInterpolator implements Interpolator {
+    private int mChangingConfiguration;
+    /**
+     * @hide
+     */
+    public int getChangingConfiguration() {
+        return mChangingConfiguration;
+    }
+
+    /**
+     * @hide
+     */
+    void setChangingConfiguration(int changingConfiguration) {
+        mChangingConfiguration = changingConfiguration;
+    }
+}
diff --git a/core/java/android/view/animation/BounceInterpolator.java b/core/java/android/view/animation/BounceInterpolator.java
index 9d8ca90..909eaa4 100644
--- a/core/java/android/view/animation/BounceInterpolator.java
+++ b/core/java/android/view/animation/BounceInterpolator.java
@@ -27,7 +27,7 @@
  * An interpolator where the change bounces at the end.
  */
 @HasNativeInterpolator
-public class BounceInterpolator implements Interpolator, NativeInterpolatorFactory {
+public class BounceInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
     public BounceInterpolator() {
     }
 
diff --git a/core/java/android/view/animation/CycleInterpolator.java b/core/java/android/view/animation/CycleInterpolator.java
index 3114aa3..663c109 100644
--- a/core/java/android/view/animation/CycleInterpolator.java
+++ b/core/java/android/view/animation/CycleInterpolator.java
@@ -33,7 +33,7 @@
  *
  */
 @HasNativeInterpolator
-public class CycleInterpolator implements Interpolator, NativeInterpolatorFactory {
+public class CycleInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
     public CycleInterpolator(float cycles) {
         mCycles = cycles;
     }
@@ -52,7 +52,7 @@
         }
 
         mCycles = a.getFloat(R.styleable.CycleInterpolator_cycles, 1.0f);
-
+        setChangingConfiguration(a.getChangingConfigurations());
         a.recycle();
     }
 
diff --git a/core/java/android/view/animation/DecelerateInterpolator.java b/core/java/android/view/animation/DecelerateInterpolator.java
index 674207c..f426f60 100644
--- a/core/java/android/view/animation/DecelerateInterpolator.java
+++ b/core/java/android/view/animation/DecelerateInterpolator.java
@@ -33,7 +33,7 @@
  *
  */
 @HasNativeInterpolator
-public class DecelerateInterpolator implements Interpolator, NativeInterpolatorFactory {
+public class DecelerateInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
     public DecelerateInterpolator() {
     }
 
@@ -62,7 +62,7 @@
         }
 
         mFactor = a.getFloat(R.styleable.DecelerateInterpolator_factor, 1.0f);
-
+        setChangingConfiguration(a.getChangingConfigurations());
         a.recycle();
     }
 
diff --git a/core/java/android/view/animation/LinearInterpolator.java b/core/java/android/view/animation/LinearInterpolator.java
index 552c611..2a047b4 100644
--- a/core/java/android/view/animation/LinearInterpolator.java
+++ b/core/java/android/view/animation/LinearInterpolator.java
@@ -25,17 +25,16 @@
 
 /**
  * An interpolator where the rate of change is constant
- *
  */
 @HasNativeInterpolator
-public class LinearInterpolator implements Interpolator, NativeInterpolatorFactory {
+public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
 
     public LinearInterpolator() {
     }
-    
+
     public LinearInterpolator(Context context, AttributeSet attrs) {
     }
-    
+
     public float getInterpolation(float input) {
         return input;
     }
diff --git a/core/java/android/view/animation/OvershootInterpolator.java b/core/java/android/view/animation/OvershootInterpolator.java
index d6c2808..306688a 100644
--- a/core/java/android/view/animation/OvershootInterpolator.java
+++ b/core/java/android/view/animation/OvershootInterpolator.java
@@ -32,7 +32,7 @@
  * then comes back.
  */
 @HasNativeInterpolator
-public class OvershootInterpolator implements Interpolator, NativeInterpolatorFactory {
+public class OvershootInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
     private final float mTension;
 
     public OvershootInterpolator() {
@@ -61,9 +61,8 @@
             a = res.obtainAttributes(attrs, R.styleable.OvershootInterpolator);
         }
 
-        mTension =
-                a.getFloat(R.styleable.OvershootInterpolator_tension, 2.0f);
-
+        mTension = a.getFloat(R.styleable.OvershootInterpolator_tension, 2.0f);
+        setChangingConfiguration(a.getChangingConfigurations());
         a.recycle();
     }
 
diff --git a/core/java/android/view/animation/PathInterpolator.java b/core/java/android/view/animation/PathInterpolator.java
index 945ecf0..eec5555 100644
--- a/core/java/android/view/animation/PathInterpolator.java
+++ b/core/java/android/view/animation/PathInterpolator.java
@@ -42,7 +42,7 @@
  *     path.lineTo(1f, 1f);
  * </pre></blockquote></p>
  */
-public class PathInterpolator implements Interpolator {
+public class PathInterpolator extends BaseInterpolator {
 
     // This governs how accurate the approximation of the Path is.
     private static final float PRECISION = 0.002f;
@@ -98,7 +98,7 @@
             a = res.obtainAttributes(attrs, R.styleable.PathInterpolator);
         }
         parseInterpolatorFromTypeArray(a);
-
+        setChangingConfiguration(a.getChangingConfigurations());
         a.recycle();
     }
 
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 0439168..4aebaae 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -4653,7 +4653,7 @@
         if (mPositionScroller == null) {
             mPositionScroller = createPositionScroller();
         }
-        mPositionScroller.startWithOffset(position, offset, offset);
+        mPositionScroller.startWithOffset(position, offset);
     }
 
     /**
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index b9f891c..5fa6e60 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -215,7 +215,12 @@
     private boolean mDesiredFocusableState;
     private boolean mDesiredFocusableInTouchModeState;
 
+    /** Lazily-constructed runnable for dispatching selection events. */
     private SelectionNotifier mSelectionNotifier;
+
+    /** Selection notifier that's waiting for the next layout pass. */
+    private SelectionNotifier mPendingSelectionNotifier;
+
     /**
      * When set to true, calls to requestLayout() will not propagate up the parent hierarchy.
      * This is used to layout the children during a layout pass.
@@ -854,39 +859,50 @@
 
     private class SelectionNotifier implements Runnable {
         public void run() {
+            mPendingSelectionNotifier = null;
+
             if (mDataChanged) {
-                // Data has changed between when this SelectionNotifier
-                // was posted and now. We need to wait until the AdapterView
-                // has been synched to the new data.
+                // Data has changed between when this SelectionNotifier was
+                // posted and now. Postpone the notification until the next
+                // layout is complete and we run checkSelectionChanged().
                 if (getAdapter() != null) {
-                    post(this);
+                    mPendingSelectionNotifier = this;
                 }
             } else {
-                fireOnSelected();
-                performAccessibilityActionsOnSelected();
+                dispatchOnItemSelected();
             }
         }
     }
 
     void selectionChanged() {
+        // We're about to post or run the selection notifier, so we don't need
+        // a pending notifier.
+        mPendingSelectionNotifier = 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
-                // in a consistent state and is able to accomodate
+                // in a consistent state and is able to accommodate
                 // new layout or invalidate requests.
                 if (mSelectionNotifier == null) {
                     mSelectionNotifier = new SelectionNotifier();
+                } else {
+                    removeCallbacks(mSelectionNotifier);
                 }
                 post(mSelectionNotifier);
             } else {
-                fireOnSelected();
-                performAccessibilityActionsOnSelected();
+                dispatchOnItemSelected();
             }
         }
     }
 
+    private void dispatchOnItemSelected() {
+        fireOnSelected();
+        performAccessibilityActionsOnSelected();
+    }
+
     private void fireOnSelected() {
         if (mOnItemSelectedListener == null) {
             return;
@@ -1042,12 +1058,22 @@
         notifySubtreeAccessibilityStateChangedIfNeeded();
     }
 
+    /**
+     * Called after layout to determine whether the selection position needs to
+     * be updated. Also used to fire any pending selection events.
+     */
     void checkSelectionChanged() {
         if ((mSelectedPosition != mOldSelectedPosition) || (mSelectedRowId != mOldSelectedRowId)) {
             selectionChanged();
             mOldSelectedPosition = mSelectedPosition;
             mOldSelectedRowId = mSelectedRowId;
         }
+
+        // If we have a pending selection notification -- and we won't if we
+        // just fired one in selectionChanged() -- run it now.
+        if (mPendingSelectionNotifier != null) {
+            mPendingSelectionNotifier.run();
+        }
     }
 
     /**
diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java
index 10e56c7..5c05b5a 100644
--- a/core/java/android/widget/AppSecurityPermissions.java
+++ b/core/java/android/widget/AppSecurityPermissions.java
@@ -99,12 +99,12 @@
 
         public Drawable loadGroupIcon(PackageManager pm) {
             if (icon != 0) {
-                return loadIcon(pm);
+                return loadUnbadgedIcon(pm);
             } else {
                 ApplicationInfo appInfo;
                 try {
                     appInfo = pm.getApplicationInfo(packageName, 0);
-                    return appInfo.loadIcon(pm);
+                    return appInfo.loadUnbadgedIcon(pm);
                 } catch (NameNotFoundException e) {
                 }
             }
diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java
index ea60abb..f380d68 100644
--- a/core/java/android/widget/CalendarView.java
+++ b/core/java/android/widget/CalendarView.java
@@ -775,9 +775,14 @@
         private ViewGroup mDayNamesHeader;
 
         /**
-         * Cached labels for the week names header.
+         * Cached abbreviations for day of week names.
          */
-        private String[] mDayLabels;
+        private String[] mDayNamesShort;
+
+        /**
+         * Cached full-length day of week names.
+         */
+        private String[] mDayNamesLong;
 
         /**
          * The first day of the week.
@@ -1306,11 +1311,14 @@
          * Sets up the strings to be used by the header.
          */
         private void setUpHeader() {
-            mDayLabels = new String[mDaysPerWeek];
+            mDayNamesShort = new String[mDaysPerWeek];
+            mDayNamesLong = new String[mDaysPerWeek];
             for (int i = mFirstDayOfWeek, count = mFirstDayOfWeek + mDaysPerWeek; i < count; i++) {
                 int calendarDay = (i > Calendar.SATURDAY) ? i - Calendar.SATURDAY : i;
-                mDayLabels[i - mFirstDayOfWeek] = DateUtils.getDayOfWeekString(calendarDay,
+                mDayNamesShort[i - mFirstDayOfWeek] = DateUtils.getDayOfWeekString(calendarDay,
                         DateUtils.LENGTH_SHORTEST);
+                mDayNamesLong[i - mFirstDayOfWeek] = DateUtils.getDayOfWeekString(calendarDay,
+                        DateUtils.LENGTH_LONG);
             }
 
             TextView label = (TextView) mDayNamesHeader.getChildAt(0);
@@ -1325,7 +1333,8 @@
                     label.setTextAppearance(mContext, mWeekDayTextAppearanceResId);
                 }
                 if (i < mDaysPerWeek + 1) {
-                    label.setText(mDayLabels[i - 1]);
+                    label.setText(mDayNamesShort[i - 1]);
+                    label.setContentDescription(mDayNamesLong[i - 1]);
                     label.setVisibility(View.VISIBLE);
                 } else {
                     label.setVisibility(View.GONE);
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index f90a9fe..75dfcca 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -1120,6 +1120,9 @@
 
     /** @hide */
     public void animateTransform(Matrix matrix) {
+        if (mDrawable == null) {
+            return;
+        }
         if (matrix == null) {
             mDrawable.setBounds(0, 0, getWidth(), getHeight());
         } else {
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 3c186e3..9f540c02 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -1639,6 +1639,11 @@
             setPressed(false);
             updateSelectorState();
 
+            final View motionView = getChildAt(mMotionPosition - mFirstPosition);
+            if (motionView != null) {
+                motionView.setPressed(false);
+            }
+
             if (mClickAnimation != null) {
                 mClickAnimation.cancel();
                 mClickAnimation = null;
@@ -1653,6 +1658,15 @@
             setPressed(true);
             layoutChildren();
 
+            // Manage the pressed view based on motion position. This allows us to
+            // play nicely with actual touch and scroll events.
+            final View motionView = getChildAt(mMotionPosition - mFirstPosition);
+            if (motionView != null) {
+                motionView.setPressed(false);
+            }
+            mMotionPosition = position;
+            child.setPressed(true);
+
             // Ensure that keyboard focus starts from the last touched position.
             setSelectedPositionInt(position);
             positionSelectorLikeTouch(position, child, x, y);
diff --git a/core/java/android/widget/PopupMenu.java b/core/java/android/widget/PopupMenu.java
index 111dadc..2708398 100644
--- a/core/java/android/widget/PopupMenu.java
+++ b/core/java/android/widget/PopupMenu.java
@@ -16,6 +16,7 @@
 
 package android.widget;
 
+import com.android.internal.R;
 import com.android.internal.view.menu.MenuBuilder;
 import com.android.internal.view.menu.MenuPopupHelper;
 import com.android.internal.view.menu.MenuPresenter;
@@ -37,10 +38,11 @@
  * of the popup will dismiss it.
  */
 public class PopupMenu implements MenuBuilder.Callback, MenuPresenter.Callback {
-    private Context mContext;
-    private MenuBuilder mMenu;
-    private View mAnchor;
-    private MenuPopupHelper mPopup;
+    private final Context mContext;
+    private final MenuBuilder mMenu;
+    private final View mAnchor;
+    private final MenuPopupHelper mPopup;
+
     private OnMenuItemClickListener mMenuItemClickListener;
     private OnDismissListener mDismissListener;
     private OnTouchListener mDragListener;
@@ -58,31 +60,56 @@
     }
 
     /**
-     * Construct a new PopupMenu.
+     * Constructor to create a new popup menu with an anchor view.
      *
-     * @param context Context for the PopupMenu.
-     * @param anchor Anchor view for this popup. The popup will appear below the anchor if there
-     *               is room, or above it if there is not.
+     * @param context Context the popup menu is running in, through which it
+     *        can access the current theme, resources, etc.
+     * @param anchor Anchor view for this popup. The popup will appear below
+     *        the anchor if there is room, or above it if there is not.
      */
     public PopupMenu(Context context, View anchor) {
         this(context, anchor, Gravity.NO_GRAVITY);
     }
 
     /**
-     * Construct a new PopupMenu.
+     * Constructor to create a new popup menu with an anchor view and alignment
+     * gravity.
      *
-     * @param context Context for the PopupMenu.
-     * @param anchor Anchor view for this popup. The popup will appear below the anchor if there
-     *               is room, or above it if there is not.
-     * @param gravity The {@link Gravity} value for aligning the popup with its anchor
+     * @param context Context the popup menu is running in, through which it
+     *        can access the current theme, resources, etc.
+     * @param anchor Anchor view for this popup. The popup will appear below
+     *        the anchor if there is room, or above it if there is not.
+     * @param gravity The {@link Gravity} value for aligning the popup with its
+     *        anchor.
      */
     public PopupMenu(Context context, View anchor, int gravity) {
-        // TODO Theme?
+        this(context, anchor, gravity, R.attr.popupMenuStyle, 0);
+    }
+
+    /**
+     * Constructor a create a new popup menu with a specific style.
+     *
+     * @param context Context the popup menu is running in, through which it
+     *        can access the current theme, resources, etc.
+     * @param anchor Anchor view for this popup. The popup will appear below
+     *        the anchor if there is room, or above it if there is not.
+     * @param gravity The {@link Gravity} value for aligning the popup with its
+     *        anchor.
+     * @param popupStyleAttr An attribute in the current theme that contains a
+     *        reference to a style resource that supplies default values for
+     *        the popup window. Can be 0 to not look for defaults.
+     * @param popupStyleRes A resource identifier of a style resource that
+     *        supplies default values for the popup window, used only if
+     *        popupStyleAttr is 0 or can not be found in the theme. Can be 0
+     *        to not look for defaults.
+     */
+    public PopupMenu(Context context, View anchor, int gravity, int popupStyleAttr,
+            int popupStyleRes) {
         mContext = context;
         mMenu = new MenuBuilder(context);
         mMenu.setCallback(this);
         mAnchor = anchor;
-        mPopup = new MenuPopupHelper(context, mMenu, anchor);
+        mPopup = new MenuPopupHelper(context, mMenu, anchor, false, popupStyleAttr, popupStyleRes);
         mPopup.setGravity(gravity);
         mPopup.setCallback(this);
     }
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 41d3e320..54a7940 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -97,9 +97,11 @@
     private boolean mAllowScrollingAnchorParent = true;
     private boolean mLayoutInsetDecor = false;
     private boolean mNotTouchModal;
+    private boolean mAttachedInDecor = true;
+    private boolean mAttachedInDecorSet = false;
 
     private OnTouchListener mTouchInterceptor;
-    
+
     private int mWidthMode;
     private int mWidth;
     private int mLastWidth;
@@ -316,6 +318,7 @@
             mContext = contentView.getContext();
             mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
         }
+
         setContentView(contentView);
         setWidth(width);
         setHeight(height);
@@ -373,16 +376,16 @@
     public int getAnimationStyle() {
         return mAnimationStyle;
     }
-    
+
     /**
-     * Set the flag on popup to ignore cheek press eventt; by default this flag
+     * Set the flag on popup to ignore cheek press event; by default this flag
      * is set to false
      * which means the pop wont ignore cheek press dispatch events.
-     * 
+     *
      * <p>If the popup is showing, calling this method will take effect only
      * the next time the popup is shown or through a manual call to one of
      * the {@link #update()} methods.</p>
-     * 
+     *
      * @see #update()
      */
     public void setIgnoreCheekPress() {
@@ -443,6 +446,19 @@
         if (mWindowManager == null && mContentView != null) {
             mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
         }
+
+        // Setting the default for attachedInDecor based on SDK version here
+        // instead of in the constructor since we might not have the context
+        // object in the constructor. We only want to set default here if the
+        // app hasn't already set the attachedInDecor.
+        if (mContext != null && !mAttachedInDecorSet) {
+            // Attach popup window in decor frame of parent window by default for
+            // {@link Build.VERSION_CODES.LOLLIPOP_MR1} or greater. Keep current
+            // behavior of not attaching to decor frame for older SDKs.
+            setAttachedInDecor(mContext.getApplicationInfo().targetSdkVersion
+                    >= Build.VERSION_CODES.LOLLIPOP_MR1);
+        }
+
     }
 
     /**
@@ -452,7 +468,7 @@
     public void setTouchInterceptor(OnTouchListener l) {
         mTouchInterceptor = l;
     }
-    
+
     /**
      * <p>Indicate whether the popup window can grab the focus.</p>
      *
@@ -702,6 +718,36 @@
     }
 
     /**
+     * <p>Indicates whether the popup window will be attached in the decor frame of its parent
+     * window.
+     *
+     * @return true if the window will be attached to the decor frame of its parent window.
+     *
+     * @see #setAttachedInDecor(boolean)
+     * @see WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR
+     */
+    public boolean isAttachedInDecor() {
+        return mAttachedInDecor;
+    }
+
+    /**
+     * <p>This will attach the popup window to the decor frame of the parent window to avoid
+     * overlaping with screen decorations like the navigation bar. Overrides the default behavior of
+     * the flag {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR}.
+     *
+     * <p>By default the flag is set on SDK version {@link Build.VERSION_CODES#LOLLIPOP_MR1} or
+     * greater and cleared on lesser SDK versions.
+     *
+     * @param enabled true if the popup should be attached to the decor frame of its parent window.
+     *
+     * @see WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR
+     */
+    public void setAttachedInDecor(boolean enabled) {
+        mAttachedInDecor = enabled;
+        mAttachedInDecorSet = true;
+    }
+
+    /**
      * Allows the popup window to force the flag
      * {@link WindowManager.LayoutParams#FLAG_LAYOUT_INSET_DECOR}, overriding default behavior.
      * This will cause the popup to inset its content to account for system windows overlaying
@@ -1140,9 +1186,12 @@
         if (mNotTouchModal) {
             curFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
         }
+        if (mAttachedInDecor) {
+          curFlags |= WindowManager.LayoutParams.FLAG_LAYOUT_ATTACHED_IN_DECOR;
+        }
         return curFlags;
     }
-    
+
     private int computeAnimationResource() {
         if (mAnimationStyle == -1) {
             if (mIsDropdown) {
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index e9298c2..1c190c3 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -604,6 +604,7 @@
      * @see #getIndeterminateTintList()
      * @see Drawable#setTintList(ColorStateList)
      */
+    @RemotableViewMethod
     public void setIndeterminateTintList(@Nullable ColorStateList tint) {
         if (mProgressTintInfo == null) {
             mProgressTintInfo = new ProgressTintInfo();
@@ -842,6 +843,7 @@
      * @see #getProgressTintList()
      * @see Drawable#setTintList(ColorStateList)
      */
+    @RemotableViewMethod
     public void setProgressTintList(@Nullable ColorStateList tint) {
         if (mProgressTintInfo == null) {
             mProgressTintInfo = new ProgressTintInfo();
@@ -923,6 +925,7 @@
      * @see #getProgressBackgroundTintList()
      * @see Drawable#setTintList(ColorStateList)
      */
+    @RemotableViewMethod
     public void setProgressBackgroundTintList(@Nullable ColorStateList tint) {
         if (mProgressTintInfo == null) {
             mProgressTintInfo = new ProgressTintInfo();
diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java
index 56f126c..d15f2d6 100644
--- a/core/java/android/widget/RadialTimePickerView.java
+++ b/core/java/android/widget/RadialTimePickerView.java
@@ -22,9 +22,7 @@
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
 import android.animation.ValueAnimator;
-import android.annotation.SuppressLint;
 import android.content.Context;
-import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
@@ -47,7 +45,6 @@
 
 import com.android.internal.R;
 
-import java.text.DateFormatSymbols;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Locale;
@@ -69,7 +66,6 @@
     private static final int HOURS = 0;
     private static final int MINUTES = 1;
     private static final int HOURS_INNER = 2;
-    private static final int AMPM = 3;
 
     private static final int SELECTOR_CIRCLE = 0;
     private static final int SELECTOR_DOT = 1;
@@ -87,12 +83,6 @@
     // Alpha level of color for selector.
     private static final int ALPHA_SELECTOR = 60; // was 51
 
-    // Alpha level of color for selected circle.
-    private static final int ALPHA_AMPM_SELECTED = ALPHA_SELECTOR;
-
-    // Alpha level of color for pressed circle.
-    private static final int ALPHA_AMPM_PRESSED = 255; // was 175
-
     private static final float COSINE_30_DEGREES = ((float) Math.sqrt(3)) * 0.5f;
     private static final float SINE_30_DEGREES = 0.5f;
 
@@ -105,8 +95,6 @@
 
     private static final int CENTER_RADIUS = 2;
 
-    private static final int[] STATE_SET_SELECTED = new int[] {R.attr.state_selected};
-
     private static int[] sSnapPrefer30sMap = new int[361];
 
     private final String[] mHours12Texts = new String[12];
@@ -114,8 +102,6 @@
     private final String[] mInnerHours24Texts = new String[12];
     private final String[] mMinutesTexts = new String[12];
 
-    private final String[] mAmPmText = new String[2];
-
     private final Paint[] mPaint = new Paint[2];
     private final int[] mColor = new int[2];
     private final IntHolder[] mAlpha = new IntHolder[2];
@@ -126,11 +112,7 @@
     private final int[][] mColorSelector = new int[2][3];
     private final IntHolder[][] mAlphaSelector = new IntHolder[2][3];
 
-    private final Paint mPaintAmPmText = new Paint();
-    private final Paint[] mPaintAmPmCircle = new Paint[2];
-
     private final Paint mPaintBackground = new Paint();
-    private final Paint mPaintDisabled = new Paint();
     private final Paint mPaintDebug = new Paint();
 
     private Typeface mTypeface;
@@ -184,21 +166,7 @@
     private float mSelectionRadiusMultiplier;
     private int[] mSelectionDegrees = new int[3];
 
-    private int mAmPmCircleRadius;
-    private float mAmPmYCenter;
-
-    private float mAmPmCircleRadiusMultiplier;
-    private int mAmPmTextColor;
-
-    private float mLeftIndicatorXCenter;
-    private float mRightIndicatorXCenter;
-
-    private int mAmPmUnselectedColor;
-    private int mAmPmSelectedColor;
-
     private int mAmOrPm;
-    private int mAmOrPmPressed;
-
     private int mDisabledAlpha;
 
     private RectF mRectF = new RectF();
@@ -331,27 +299,6 @@
         final TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.TimePicker,
                 defStyle, 0);
 
-        ColorStateList amPmBackgroundColor = a.getColorStateList(
-                R.styleable.TimePicker_amPmBackgroundColor);
-        if (amPmBackgroundColor == null) {
-            amPmBackgroundColor = res.getColorStateList(
-                    R.color.timepicker_default_ampm_unselected_background_color_material);
-        }
-
-        // Obtain the backup selected color. If the background color state
-        // list doesn't have a state for selected, we'll use this color.
-        final int amPmSelectedColor = a.getColor(R.styleable.TimePicker_amPmSelectedBackgroundColor,
-                res.getColor(R.color.timepicker_default_ampm_selected_background_color_material));
-        amPmBackgroundColor = ColorStateList.addFirstIfMissing(
-                amPmBackgroundColor, R.attr.state_selected, amPmSelectedColor);
-
-        mAmPmSelectedColor = amPmBackgroundColor.getColorForState(
-                STATE_SET_SELECTED, amPmSelectedColor);
-        mAmPmUnselectedColor = amPmBackgroundColor.getDefaultColor();
-
-        mAmPmTextColor = a.getColor(R.styleable.TimePicker_amPmTextColor,
-                res.getColor(R.color.timepicker_default_text_color_material));
-
         mTypeface = Typeface.create("sans-serif", Typeface.NORMAL);
 
         // Initialize all alpha values to opaque.
@@ -419,16 +366,6 @@
                 R.styleable.TimePicker_numbersSelectorColor,
                 R.color.timepicker_default_selector_color_material);
 
-        mPaintAmPmText.setColor(mAmPmTextColor);
-        mPaintAmPmText.setTypeface(mTypeface);
-        mPaintAmPmText.setAntiAlias(true);
-        mPaintAmPmText.setTextAlign(Paint.Align.CENTER);
-
-        mPaintAmPmCircle[AM] = new Paint();
-        mPaintAmPmCircle[AM].setAntiAlias(true);
-        mPaintAmPmCircle[PM] = new Paint();
-        mPaintAmPmCircle[PM].setAntiAlias(true);
-
         mPaintBackground.setColor(a.getColor(R.styleable.TimePicker_numbersBackgroundColor,
                 res.getColor(R.color.timepicker_default_numbers_background_color_material)));
         mPaintBackground.setAntiAlias(true);
@@ -444,7 +381,6 @@
         mShowHours = true;
         mIs24HourMode = false;
         mAmOrPm = AM;
-        mAmOrPmPressed = -1;
 
         initHoursAndMinutesText();
         initData();
@@ -530,13 +466,7 @@
 
         // 0 is 12 AM (midnight) and 12 is 12 PM (noon).
         mAmOrPm = (hour == 0 || (hour % 24) < 12) ? AM : PM;
-
-        if (mIs24HourMode) {
-            // Inner circle is 1 through 12.
-            mIsOnInnerCircle = hour >= 1 && hour <= 12;
-        } else {
-            mIsOnInnerCircle = false;
-        }
+        mIsOnInnerCircle = mIs24HourMode && hour >= 1 && hour <= 12;
 
         initData();
         updateLayoutData();
@@ -586,11 +516,6 @@
         return mAmOrPm;
     }
 
-    public void swapAmPm() {
-        mAmOrPm = (mAmOrPm == AM) ? PM : AM;
-        invalidate();
-    }
-
     public void showHours(boolean animate) {
         if (mShowHours) return;
         mShowHours = true;
@@ -621,10 +546,6 @@
             mInnerHours24Texts[i] = String.format("%d", HOURS_NUMBERS[i]);
             mMinutesTexts[i] = String.format("%02d", MINUTES_NUMBERS[i]);
         }
-
-        String[] amPmStrings = TimePickerClockDelegate.getAmPmStrings(mContext);
-        mAmPmText[AM] = amPmStrings[0];
-        mAmPmText[PM] = amPmStrings[1];
     }
 
     private void initData() {
@@ -674,9 +595,6 @@
         mAnimationRadiusMultiplier[HOURS_INNER] = 1;
         mAnimationRadiusMultiplier[MINUTES] = 1;
 
-        mAmPmCircleRadiusMultiplier = Float.parseFloat(
-                res.getString(R.string.timepicker_ampm_circle_radius_multiplier));
-
         mAlpha[HOURS].setValue(mShowHours ? ALPHA_OPAQUE : ALPHA_TRANSPARENT);
         mAlpha[MINUTES].setValue(mShowHours ? ALPHA_TRANSPARENT : ALPHA_OPAQUE);
 
@@ -710,14 +628,6 @@
         mCircleRadius[HOURS_INNER] = min * mCircleRadiusMultiplier[HOURS];
         mCircleRadius[MINUTES] = min * mCircleRadiusMultiplier[MINUTES];
 
-        if (!mIs24HourMode) {
-            // We'll need to draw the AM/PM circles, so the main circle will need to have
-            // a slightly higher center. To keep the entire view centered vertically, we'll
-            // have to push it up by half the radius of the AM/PM circles.
-            int amPmCircleRadius = (int) (mCircleRadius[HOURS] * mAmPmCircleRadiusMultiplier);
-            mYCenter -= amPmCircleRadius / 2;
-        }
-
         mMinHypotenuseForInnerNumber = (int) (mCircleRadius[HOURS]
                 * mNumbersRadiusMultiplier[HOURS_INNER]) - mSelectionRadius[HOURS];
         mMaxHypotenuseForOuterNumber = (int) (mCircleRadius[HOURS]
@@ -738,17 +648,6 @@
         mSelectionRadius[HOURS] = (int) (mCircleRadius[HOURS] * mSelectionRadiusMultiplier);
         mSelectionRadius[HOURS_INNER] = mSelectionRadius[HOURS];
         mSelectionRadius[MINUTES] = (int) (mCircleRadius[MINUTES] * mSelectionRadiusMultiplier);
-
-        mAmPmCircleRadius = (int) (mCircleRadius[HOURS] * mAmPmCircleRadiusMultiplier);
-        mPaintAmPmText.setTextSize(mAmPmCircleRadius * 3 / 4);
-
-        // Line up the vertical center of the AM/PM circles with the bottom of the main circle.
-        mAmPmYCenter = mYCenter + mCircleRadius[HOURS];
-
-        // Line up the horizontal edges of the AM/PM circles with the horizontal edges
-        // of the main circle
-        mLeftIndicatorXCenter = mXCenter - mCircleRadius[HOURS] + mAmPmCircleRadius;
-        mRightIndicatorXCenter = mXCenter + mCircleRadius[HOURS] - mAmPmCircleRadius;
     }
 
     @Override
@@ -780,9 +679,6 @@
                 mColor[MINUTES], mAlpha[MINUTES].getValue());
 
         drawCenter(canvas);
-        if (!mIs24HourMode) {
-            drawAmPm(canvas);
-        }
 
         if (DEBUG) {
             drawDebug(canvas);
@@ -804,50 +700,6 @@
         drawSelector(canvas, MINUTES);
     }
 
-    private void drawAmPm(Canvas canvas) {
-        final boolean isLayoutRtl = isLayoutRtl();
-
-        int amColor = mAmPmUnselectedColor;
-        int amAlpha = ALPHA_OPAQUE;
-        int pmColor = mAmPmUnselectedColor;
-        int pmAlpha = ALPHA_OPAQUE;
-        if (mAmOrPm == AM) {
-            amColor = mAmPmSelectedColor;
-            amAlpha = ALPHA_AMPM_SELECTED;
-        } else if (mAmOrPm == PM) {
-            pmColor = mAmPmSelectedColor;
-            pmAlpha = ALPHA_AMPM_SELECTED;
-        }
-        if (mAmOrPmPressed == AM) {
-            amColor = mAmPmSelectedColor;
-            amAlpha = ALPHA_AMPM_PRESSED;
-        } else if (mAmOrPmPressed == PM) {
-            pmColor = mAmPmSelectedColor;
-            pmAlpha = ALPHA_AMPM_PRESSED;
-        }
-
-        // Draw the two circles
-        mPaintAmPmCircle[AM].setColor(amColor);
-        mPaintAmPmCircle[AM].setAlpha(getMultipliedAlpha(amColor, amAlpha));
-        canvas.drawCircle(isLayoutRtl ? mRightIndicatorXCenter : mLeftIndicatorXCenter,
-                mAmPmYCenter, mAmPmCircleRadius, mPaintAmPmCircle[AM]);
-
-        mPaintAmPmCircle[PM].setColor(pmColor);
-        mPaintAmPmCircle[PM].setAlpha(getMultipliedAlpha(pmColor, pmAlpha));
-        canvas.drawCircle(isLayoutRtl ? mLeftIndicatorXCenter : mRightIndicatorXCenter,
-                mAmPmYCenter, mAmPmCircleRadius, mPaintAmPmCircle[PM]);
-
-        // Draw the AM/PM texts on top
-        mPaintAmPmText.setColor(mAmPmTextColor);
-        float textYCenter = mAmPmYCenter -
-                (int) (mPaintAmPmText.descent() + mPaintAmPmText.ascent()) / 2;
-
-        canvas.drawText(isLayoutRtl ? mAmPmText[PM] : mAmPmText[AM], mLeftIndicatorXCenter,
-                textYCenter, mPaintAmPmText);
-        canvas.drawText(isLayoutRtl ? mAmPmText[AM] : mAmPmText[PM], mRightIndicatorXCenter,
-                textYCenter, mPaintAmPmText);
-    }
-
     private int getMultipliedAlpha(int argb, int alpha) {
         return (int) (Color.alpha(argb) * (alpha / 255.0) + 0.5);
     }
@@ -950,7 +802,7 @@
         float x = mXCenter - width / 2;
         float y = mYCenter + 1.5f * height;
 
-        canvas.drawText(selected.toString(), x, y, paint);
+        canvas.drawText(selected, x, y, paint);
     }
 
     private void calculateGridSizesHours() {
@@ -1259,26 +1111,6 @@
         return (int) degrees;
     }
 
-    private int getIsTouchingAmOrPm(float x, float y) {
-        final boolean isLayoutRtl = isLayoutRtl();
-        int squaredYDistance = (int) ((y - mAmPmYCenter) * (y - mAmPmYCenter));
-
-        int distanceToAmCenter = (int) Math.sqrt(
-                (x - mLeftIndicatorXCenter) * (x - mLeftIndicatorXCenter) + squaredYDistance);
-        if (distanceToAmCenter <= mAmPmCircleRadius) {
-            return (isLayoutRtl ? PM : AM);
-        }
-
-        int distanceToPmCenter = (int) Math.sqrt(
-                (x - mRightIndicatorXCenter) * (x - mRightIndicatorXCenter) + squaredYDistance);
-        if (distanceToPmCenter <= mAmPmCircleRadius) {
-            return (isLayoutRtl ? AM : PM);
-        }
-
-        // Neither was close enough.
-        return -1;
-    }
-
     @Override
     public boolean onTouch(View v, MotionEvent event) {
         if(!mInputEnabled) {
@@ -1295,75 +1127,53 @@
         switch(event.getAction()) {
             case MotionEvent.ACTION_DOWN:
             case MotionEvent.ACTION_MOVE:
-                mAmOrPmPressed = getIsTouchingAmOrPm(eventX, eventY);
-                if (mAmOrPmPressed != -1) {
-                    result = true;
-                } else {
-                    degrees = getDegreesFromXY(eventX, eventY);
-                    if (degrees != -1) {
-                        snapDegrees = (mShowHours ?
-                                snapOnly30s(degrees, 0) : snapPrefer30s(degrees)) % 360;
-                        if (mShowHours) {
-                            mSelectionDegrees[HOURS] = snapDegrees;
-                            mSelectionDegrees[HOURS_INNER] = snapDegrees;
-                        } else {
-                            mSelectionDegrees[MINUTES] = snapDegrees;
-                        }
-                        performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);
-                        if (mListener != null) {
-                            if (mShowHours) {
-                                mListener.onValueSelected(HOURS, getCurrentHour(), false);
-                            } else  {
-                                mListener.onValueSelected(MINUTES, getCurrentMinute(), false);
-                            }
-                        }
-                        result = true;
+                degrees = getDegreesFromXY(eventX, eventY);
+                if (degrees != -1) {
+                    snapDegrees = (mShowHours ?
+                            snapOnly30s(degrees, 0) : snapPrefer30s(degrees)) % 360;
+                    if (mShowHours) {
+                        mSelectionDegrees[HOURS] = snapDegrees;
+                        mSelectionDegrees[HOURS_INNER] = snapDegrees;
+                    } else {
+                        mSelectionDegrees[MINUTES] = snapDegrees;
                     }
-                }
-                invalidate();
-                return result;
-
-            case MotionEvent.ACTION_UP:
-                mAmOrPmPressed = getIsTouchingAmOrPm(eventX, eventY);
-                if (mAmOrPmPressed != -1) {
-                    if (mAmOrPm != mAmOrPmPressed) {
-                        swapAmPm();
-                    }
-                    mAmOrPmPressed = -1;
+                    performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);
                     if (mListener != null) {
-                        mListener.onValueSelected(AMPM, getCurrentHour(), true);
+                        if (mShowHours) {
+                            mListener.onValueSelected(HOURS, getCurrentHour(), false);
+                        } else  {
+                            mListener.onValueSelected(MINUTES, getCurrentMinute(), false);
+                        }
                     }
                     result = true;
-                } else {
-                    degrees = getDegreesFromXY(eventX, eventY);
-                    if (degrees != -1) {
-                        snapDegrees = (mShowHours ?
-                                snapOnly30s(degrees, 0) : snapPrefer30s(degrees)) % 360;
-                        if (mShowHours) {
-                            mSelectionDegrees[HOURS] = snapDegrees;
-                            mSelectionDegrees[HOURS_INNER] = snapDegrees;
-                        } else {
-                            mSelectionDegrees[MINUTES] = snapDegrees;
-                        }
-                        if (mListener != null) {
-                            if (mShowHours) {
-                                mListener.onValueSelected(HOURS, getCurrentHour(), true);
-                            } else  {
-                                mListener.onValueSelected(MINUTES, getCurrentMinute(), true);
-                            }
-                        }
-                        result = true;
-                    }
-                }
-                if (result) {
                     invalidate();
                 }
-                return result;
+                break;
 
-            default:
+            case MotionEvent.ACTION_UP:
+                degrees = getDegreesFromXY(eventX, eventY);
+                if (degrees != -1) {
+                    snapDegrees = (mShowHours ?
+                            snapOnly30s(degrees, 0) : snapPrefer30s(degrees)) % 360;
+                    if (mShowHours) {
+                        mSelectionDegrees[HOURS] = snapDegrees;
+                        mSelectionDegrees[HOURS_INNER] = snapDegrees;
+                    } else {
+                        mSelectionDegrees[MINUTES] = snapDegrees;
+                    }
+                    if (mListener != null) {
+                        if (mShowHours) {
+                            mListener.onValueSelected(HOURS, getCurrentHour(), true);
+                        } else  {
+                            mListener.onValueSelected(MINUTES, getCurrentMinute(), true);
+                        }
+                    }
+                    invalidate();
+                    result = true;
+                }
                 break;
         }
-        return false;
+        return result;
     }
 
     /**
@@ -1373,8 +1183,8 @@
     @Override
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfo(info);
-        info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
-        info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+        info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD);
+        info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD);
     }
 
     /**
@@ -1404,7 +1214,6 @@
      * When scroll forward/backward events are received, jump the time to the higher/lower
      * discrete, visible value on the circle.
      */
-    @SuppressLint("NewApi")
     @Override
     public boolean performAccessibilityAction(int action, Bundle arguments) {
         if (super.performAccessibilityAction(action, arguments)) {
@@ -1418,8 +1227,8 @@
             changeMultiplier = -1;
         }
         if (changeMultiplier != 0) {
-            int value = 0;
-            int stepSize = 0;
+            int value;
+            final int stepSize;
             if (mShowHours) {
                 stepSize = DEGREES_FOR_ONE_HOUR;
                 value = getCurrentHour() % 12;
@@ -1431,7 +1240,7 @@
             int degrees = value * stepSize;
             degrees = snapOnly30s(degrees, changeMultiplier);
             value = degrees / stepSize;
-            int maxValue = 0;
+            final int maxValue;
             int minValue = 0;
             if (mShowHours) {
                 if (mIs24HourMode) {
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 7cb3c37..80f364b 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -27,6 +27,7 @@
 import android.content.IntentSender;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.ColorStateList;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
@@ -1069,6 +1070,7 @@
         static final int BITMAP = 12;
         static final int BUNDLE = 13;
         static final int INTENT = 14;
+        static final int COLOR_STATE_LIST = 15;
 
         String methodName;
         int type;
@@ -1142,6 +1144,11 @@
                         this.value = Intent.CREATOR.createFromParcel(in);
                     }
                     break;
+                case COLOR_STATE_LIST:
+                    if (in.readInt() != 0) {
+                        this.value = ColorStateList.CREATOR.createFromParcel(in);
+                    }
+                    break;
                 default:
                     break;
             }
@@ -1212,6 +1219,11 @@
                         ((Intent)this.value).writeToParcel(out, flags);
                     }
                     break;
+                case COLOR_STATE_LIST:
+                    out.writeInt(this.value != null ? 1 : 0);
+                    if (this.value != null) {
+                        ((ColorStateList)this.value).writeToParcel(out, flags);
+                    }
                 default:
                     break;
             }
@@ -1247,6 +1259,8 @@
                     return Bundle.class;
                 case INTENT:
                     return Intent.class;
+                case COLOR_STATE_LIST:
+                    return ColorStateList.class;
                 default:
                     return null;
             }
@@ -2207,6 +2221,42 @@
     }
 
     /**
+     * @hide
+     * Equivalent to calling {@link android.widget.ProgressBar#setProgressTintList}.
+     *
+     * @param viewId The id of the view whose tint should change
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     */
+    public void setProgressTintList(int viewId, ColorStateList tint) {
+        addAction(new ReflectionAction(viewId, "setProgressTintList",
+                ReflectionAction.COLOR_STATE_LIST, tint));
+    }
+
+    /**
+     * @hide
+     * Equivalent to calling {@link android.widget.ProgressBar#setProgressBackgroundTintList}.
+     *
+     * @param viewId The id of the view whose tint should change
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     */
+    public void setProgressBackgroundTintList(int viewId, ColorStateList tint) {
+        addAction(new ReflectionAction(viewId, "setProgressBackgroundTintList",
+                ReflectionAction.COLOR_STATE_LIST, tint));
+    }
+
+    /**
+     * @hide
+     * Equivalent to calling {@link android.widget.ProgressBar#setIndeterminateTintList}.
+     *
+     * @param viewId The id of the view whose tint should change
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     */
+    public void setProgressIndeterminateTintList(int viewId, ColorStateList tint) {
+        addAction(new ReflectionAction(viewId, "setIndeterminateTintList",
+                ReflectionAction.COLOR_STATE_LIST, tint));
+    }
+
+    /**
      * Equivalent to calling {@link android.widget.TextView#setTextColor(int)}.
      *
      * @param viewId The id of the view whose text color should change
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 5cdee53..0917b32 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -8518,6 +8518,7 @@
             } return false;
             case AccessibilityNodeInfo.ACTION_SET_SELECTION: {
                 if (isFocused() && canSelectText()) {
+                    ensureIterableTextForAccessibilitySelectable();
                     CharSequence text = getIterableTextForAccessibility();
                     if (text == null) {
                         return false;
@@ -8543,6 +8544,11 @@
                     }
                 }
             } return false;
+            case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY:
+            case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: {
+                ensureIterableTextForAccessibilitySelectable();
+                return super.performAccessibilityAction(action, arguments);
+            }
             default: {
                 return super.performAccessibilityAction(action, arguments);
             }
@@ -9032,10 +9038,13 @@
      */
     @Override
     public CharSequence getIterableTextForAccessibility() {
+        return mText;
+    }
+
+    private void ensureIterableTextForAccessibilitySelectable() {
         if (!(mText instanceof Spannable)) {
             setText(mText, BufferType.SPANNABLE);
         }
-        return mText;
     }
 
     /**
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index 85cf67b..26e02f8 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -86,12 +86,12 @@
 
         switch (mode) {
             case MODE_CLOCK:
-                mDelegate = new TimePickerSpinnerDelegate(
+                mDelegate = new TimePickerClockDelegate(
                         this, context, attrs, defStyleAttr, defStyleRes);
                 break;
             case MODE_SPINNER:
             default:
-                mDelegate = new TimePickerClockDelegate(
+                mDelegate = new TimePickerSpinnerDelegate(
                         this, context, attrs, defStyleAttr, defStyleRes);
                 break;
         }
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 8917f39..eca3048 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -17,365 +17,376 @@
 package android.widget;
 
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.TextUtils;
 import android.text.format.DateFormat;
 import android.text.format.DateUtils;
 import android.util.AttributeSet;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.HapticFeedbackConstants;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodManager;
+
 import com.android.internal.R;
 
-import java.text.DateFormatSymbols;
+import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Locale;
 
-import libcore.icu.LocaleData;
-
-import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
-import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
-
 /**
- * A delegate implementing the basic TimePicker
+ * A delegate implementing the radial clock-based TimePicker.
  */
-class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
+class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate implements
+        RadialTimePickerView.OnValueSelectedListener {
+
+    private static final String TAG = "TimePickerClockDelegate";
+
+    // Index used by RadialPickerLayout
+    private static final int HOUR_INDEX = 0;
+    private static final int MINUTE_INDEX = 1;
+
+    // NOT a real index for the purpose of what's showing.
+    private static final int AMPM_INDEX = 2;
+
+    // Also NOT a real index, just used for keyboard mode.
+    private static final int ENABLE_PICKER_INDEX = 3;
+
+    static final int AM = 0;
+    static final int PM = 1;
+
     private static final boolean DEFAULT_ENABLED_STATE = true;
+    private boolean mIsEnabled = DEFAULT_ENABLED_STATE;
+
     private static final int HOURS_IN_HALF_DAY = 12;
 
-    // state
+    private final View mHeaderView;
+    private final TextView mHourView;
+    private final TextView mMinuteView;
+    private final View mAmPmLayout;
+    private final CheckedTextView mAmLabel;
+    private final CheckedTextView mPmLabel;
+    private final RadialTimePickerView mRadialTimePickerView;
+    private final TextView mSeparatorView;
+
+    private final String mAmText;
+    private final String mPmText;
+
+    private final float mDisabledAlpha;
+
+    private boolean mAllowAutoAdvance;
+    private int mInitialHourOfDay;
+    private int mInitialMinute;
     private boolean mIs24HourView;
-    private boolean mIsAm;
 
-    // ui components
-    private final NumberPicker mHourSpinner;
-    private final NumberPicker mMinuteSpinner;
-    private final NumberPicker mAmPmSpinner;
-    private final EditText mHourSpinnerInput;
-    private final EditText mMinuteSpinnerInput;
-    private final EditText mAmPmSpinnerInput;
-    private final TextView mDivider;
+    // For hardware IME input.
+    private char mPlaceholderText;
+    private String mDoublePlaceholderText;
+    private String mDeletedKeyFormat;
+    private boolean mInKbMode;
+    private ArrayList<Integer> mTypedTimes = new ArrayList<Integer>();
+    private Node mLegalTimesTree;
+    private int mAmKeyCode;
+    private int mPmKeyCode;
 
-    // Note that the legacy implementation of the TimePicker is
-    // using a button for toggling between AM/PM while the new
-    // version uses a NumberPicker spinner. Therefore the code
-    // accommodates these two cases to be backwards compatible.
-    private final Button mAmPmButton;
+    // Accessibility strings.
+    private String mHourPickerDescription;
+    private String mSelectHours;
+    private String mMinutePickerDescription;
+    private String mSelectMinutes;
 
-    private final String[] mAmPmStrings;
+    // Most recent time announcement values for accessibility.
+    private CharSequence mLastAnnouncedText;
+    private boolean mLastAnnouncedIsHour;
 
-    private boolean mIsEnabled = DEFAULT_ENABLED_STATE;
     private Calendar mTempCalendar;
-    private boolean mHourWithTwoDigit;
-    private char mHourFormat;
 
     public TimePickerClockDelegate(TimePicker delegator, Context context, AttributeSet attrs,
             int defStyleAttr, int defStyleRes) {
         super(delegator, context);
 
         // process style attributes
-        final TypedArray a = mContext.obtainStyledAttributes(
-                attrs, R.styleable.TimePicker, defStyleAttr, defStyleRes);
-        final int layoutResourceId = a.getResourceId(
-                R.styleable.TimePicker_legacyLayout, R.layout.time_picker_legacy);
+        final TypedArray a = mContext.obtainStyledAttributes(attrs,
+                R.styleable.TimePicker, defStyleAttr, defStyleRes);
+        final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
+                Context.LAYOUT_INFLATER_SERVICE);
+        final Resources res = mContext.getResources();
+
+        mHourPickerDescription = res.getString(R.string.hour_picker_description);
+        mSelectHours = res.getString(R.string.select_hours);
+        mMinutePickerDescription = res.getString(R.string.minute_picker_description);
+        mSelectMinutes = res.getString(R.string.select_minutes);
+
+        String[] amPmStrings = TimePickerSpinnerDelegate.getAmPmStrings(context);
+        mAmText = amPmStrings[0];
+        mPmText = amPmStrings[1];
+
+        final int layoutResourceId = a.getResourceId(R.styleable.TimePicker_internalLayout,
+                R.layout.time_picker_holo);
+        final View mainView = inflater.inflate(layoutResourceId, delegator);
+
+        mHeaderView = mainView.findViewById(R.id.time_header);
+        mHeaderView.setBackground(a.getDrawable(R.styleable.TimePicker_headerBackground));
+
+        // Set up hour/minute labels.
+        mHourView = (TextView) mHeaderView.findViewById(R.id.hours);
+        mHourView.setOnClickListener(mClickListener);
+        mSeparatorView = (TextView) mHeaderView.findViewById(R.id.separator);
+        mMinuteView = (TextView) mHeaderView.findViewById(R.id.minutes);
+        mMinuteView.setOnClickListener(mClickListener);
+
+        final int headerTimeTextAppearance = a.getResourceId(
+                R.styleable.TimePicker_headerTimeTextAppearance, 0);
+        if (headerTimeTextAppearance != 0) {
+            mHourView.setTextAppearance(context, headerTimeTextAppearance);
+            mSeparatorView.setTextAppearance(context, headerTimeTextAppearance);
+            mMinuteView.setTextAppearance(context, headerTimeTextAppearance);
+        }
+
+        // TODO: This can be removed once we support themed color state lists.
+        final int headerSelectedTextColor = a.getColor(
+                R.styleable.TimePicker_headerSelectedTextColor,
+                res.getColor(R.color.timepicker_default_selector_color_material));
+        mHourView.setTextColor(ColorStateList.addFirstIfMissing(mHourView.getTextColors(),
+                R.attr.state_selected, headerSelectedTextColor));
+        mMinuteView.setTextColor(ColorStateList.addFirstIfMissing(mMinuteView.getTextColors(),
+                R.attr.state_selected, headerSelectedTextColor));
+
+        // Set up AM/PM labels.
+        mAmPmLayout = mHeaderView.findViewById(R.id.ampm_layout);
+        mAmLabel = (CheckedTextView) mAmPmLayout.findViewById(R.id.am_label);
+        mAmLabel.setText(amPmStrings[0]);
+        mAmLabel.setOnClickListener(mClickListener);
+        mPmLabel = (CheckedTextView) mAmPmLayout.findViewById(R.id.pm_label);
+        mPmLabel.setText(amPmStrings[1]);
+        mPmLabel.setOnClickListener(mClickListener);
+
+        final int headerAmPmTextAppearance = a.getResourceId(
+                R.styleable.TimePicker_headerAmPmTextAppearance, 0);
+        if (headerAmPmTextAppearance != 0) {
+            mAmLabel.setTextAppearance(context, headerAmPmTextAppearance);
+            mPmLabel.setTextAppearance(context, headerAmPmTextAppearance);
+        }
+
         a.recycle();
 
-        final LayoutInflater inflater = LayoutInflater.from(mContext);
-        inflater.inflate(layoutResourceId, mDelegator, true);
+        // Pull disabled alpha from theme.
+        final TypedValue outValue = new TypedValue();
+        context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, outValue, true);
+        mDisabledAlpha = outValue.getFloat();
 
-        // hour
-        mHourSpinner = (NumberPicker) delegator.findViewById(R.id.hour);
-        mHourSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
-            public void onValueChange(NumberPicker spinner, int oldVal, int newVal) {
-                updateInputState();
-                if (!is24HourView()) {
-                    if ((oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY) ||
-                            (oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1)) {
-                        mIsAm = !mIsAm;
-                        updateAmPmControl();
-                    }
-                }
-                onTimeChanged();
-            }
-        });
-        mHourSpinnerInput = (EditText) mHourSpinner.findViewById(R.id.numberpicker_input);
-        mHourSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
+        mRadialTimePickerView = (RadialTimePickerView) mainView.findViewById(
+                R.id.radial_picker);
 
-        // divider (only for the new widget style)
-        mDivider = (TextView) mDelegator.findViewById(R.id.divider);
-        if (mDivider != null) {
-            setDividerText();
+        setupListeners();
+
+        mAllowAutoAdvance = true;
+
+        // Set up for keyboard mode.
+        mDoublePlaceholderText = res.getString(R.string.time_placeholder);
+        mDeletedKeyFormat = res.getString(R.string.deleted_key);
+        mPlaceholderText = mDoublePlaceholderText.charAt(0);
+        mAmKeyCode = mPmKeyCode = -1;
+        generateLegalTimesTree();
+
+        // Initialize with current time
+        final Calendar calendar = Calendar.getInstance(mCurrentLocale);
+        final int currentHour = calendar.get(Calendar.HOUR_OF_DAY);
+        final int currentMinute = calendar.get(Calendar.MINUTE);
+        initialize(currentHour, currentMinute, false /* 12h */, HOUR_INDEX);
+    }
+
+    private void initialize(int hourOfDay, int minute, boolean is24HourView, int index) {
+        mInitialHourOfDay = hourOfDay;
+        mInitialMinute = minute;
+        mIs24HourView = is24HourView;
+        mInKbMode = false;
+        updateUI(index);
+    }
+
+    private void setupListeners() {
+        mHeaderView.setOnKeyListener(mKeyListener);
+        mHeaderView.setOnFocusChangeListener(mFocusListener);
+        mHeaderView.setFocusable(true);
+
+        mRadialTimePickerView.setOnValueSelectedListener(this);
+    }
+
+    private void updateUI(int index) {
+        // Update RadialPicker values
+        updateRadialPicker(index);
+        // Enable or disable the AM/PM view.
+        updateHeaderAmPm();
+        // Update Hour and Minutes
+        updateHeaderHour(mInitialHourOfDay, false);
+        // Update time separator
+        updateHeaderSeparator();
+        // Update Minutes
+        updateHeaderMinute(mInitialMinute, false);
+        // Invalidate everything
+        mDelegator.invalidate();
+    }
+
+    private void updateRadialPicker(int index) {
+        mRadialTimePickerView.initialize(mInitialHourOfDay, mInitialMinute, mIs24HourView);
+        setCurrentItemShowing(index, false, true);
+    }
+
+    private int computeMaxWidthOfNumbers(int max) {
+        TextView tempView = new TextView(mContext);
+        tempView.setTextAppearance(mContext, R.style.TextAppearance_Material_TimePicker_TimeLabel);
+        ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT);
+        tempView.setLayoutParams(lp);
+        int maxWidth = 0;
+        for (int minutes = 0; minutes < max; minutes++) {
+            final String text = String.format("%02d", minutes);
+            tempView.setText(text);
+            tempView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+            maxWidth = Math.max(maxWidth, tempView.getMeasuredWidth());
         }
+        return maxWidth;
+    }
 
-        // minute
-        mMinuteSpinner = (NumberPicker) mDelegator.findViewById(R.id.minute);
-        mMinuteSpinner.setMinValue(0);
-        mMinuteSpinner.setMaxValue(59);
-        mMinuteSpinner.setOnLongPressUpdateInterval(100);
-        mMinuteSpinner.setFormatter(NumberPicker.getTwoDigitFormatter());
-        mMinuteSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
-            public void onValueChange(NumberPicker spinner, int oldVal, int newVal) {
-                updateInputState();
-                int minValue = mMinuteSpinner.getMinValue();
-                int maxValue = mMinuteSpinner.getMaxValue();
-                if (oldVal == maxValue && newVal == minValue) {
-                    int newHour = mHourSpinner.getValue() + 1;
-                    if (!is24HourView() && newHour == HOURS_IN_HALF_DAY) {
-                        mIsAm = !mIsAm;
-                        updateAmPmControl();
-                    }
-                    mHourSpinner.setValue(newHour);
-                } else if (oldVal == minValue && newVal == maxValue) {
-                    int newHour = mHourSpinner.getValue() - 1;
-                    if (!is24HourView() && newHour == HOURS_IN_HALF_DAY - 1) {
-                        mIsAm = !mIsAm;
-                        updateAmPmControl();
-                    }
-                    mHourSpinner.setValue(newHour);
-                }
-                onTimeChanged();
-            }
-        });
-        mMinuteSpinnerInput = (EditText) mMinuteSpinner.findViewById(R.id.numberpicker_input);
-        mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
-
-        // Get the localized am/pm strings and use them in the spinner.
-        mAmPmStrings = getAmPmStrings(context);
-
-        // am/pm
-        final View amPmView = mDelegator.findViewById(R.id.amPm);
-        if (amPmView instanceof Button) {
-            mAmPmSpinner = null;
-            mAmPmSpinnerInput = null;
-            mAmPmButton = (Button) amPmView;
-            mAmPmButton.setOnClickListener(new View.OnClickListener() {
-                public void onClick(View button) {
-                    button.requestFocus();
-                    mIsAm = !mIsAm;
-                    updateAmPmControl();
-                    onTimeChanged();
-                }
-            });
+    private void updateHeaderAmPm() {
+        if (mIs24HourView) {
+            mAmPmLayout.setVisibility(View.GONE);
         } else {
-            mAmPmButton = null;
-            mAmPmSpinner = (NumberPicker) amPmView;
-            mAmPmSpinner.setMinValue(0);
-            mAmPmSpinner.setMaxValue(1);
-            mAmPmSpinner.setDisplayedValues(mAmPmStrings);
-            mAmPmSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
-                public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
-                    updateInputState();
-                    picker.requestFocus();
-                    mIsAm = !mIsAm;
-                    updateAmPmControl();
-                    onTimeChanged();
-                }
-            });
-            mAmPmSpinnerInput = (EditText) mAmPmSpinner.findViewById(R.id.numberpicker_input);
-            mAmPmSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_DONE);
-        }
-
-        if (isAmPmAtStart()) {
-            // Move the am/pm view to the beginning
-            ViewGroup amPmParent = (ViewGroup) delegator.findViewById(R.id.timePickerLayout);
-            amPmParent.removeView(amPmView);
-            amPmParent.addView(amPmView, 0);
-            // Swap layout margins if needed. They may be not symmetrical (Old Standard Theme
-            // for example and not for Holo Theme)
-            ViewGroup.MarginLayoutParams lp =
-                    (ViewGroup.MarginLayoutParams) amPmView.getLayoutParams();
-            final int startMargin = lp.getMarginStart();
-            final int endMargin = lp.getMarginEnd();
-            if (startMargin != endMargin) {
-                lp.setMarginStart(endMargin);
-                lp.setMarginEnd(startMargin);
+            final String bestDateTimePattern = DateFormat.getBestDateTimePattern(
+                    mCurrentLocale, "hm");
+            boolean amPmOnLeft = bestDateTimePattern.startsWith("a");
+            if (TextUtils.getLayoutDirectionFromLocale(mCurrentLocale) ==
+                    View.LAYOUT_DIRECTION_RTL) {
+                amPmOnLeft = !amPmOnLeft;
             }
-        }
 
-        getHourFormatData();
+            final ViewGroup.MarginLayoutParams params =
+                    (ViewGroup.MarginLayoutParams) mAmPmLayout.getLayoutParams();
 
-        // update controls to initial state
-        updateHourControl();
-        updateMinuteControl();
-        updateAmPmControl();
-
-        // set to current time
-        setCurrentHour(mTempCalendar.get(Calendar.HOUR_OF_DAY));
-        setCurrentMinute(mTempCalendar.get(Calendar.MINUTE));
-
-        if (!isEnabled()) {
-            setEnabled(false);
-        }
-
-        // set the content descriptions
-        setContentDescriptions();
-
-        // If not explicitly specified this view is important for accessibility.
-        if (mDelegator.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
-            mDelegator.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
-        }
-    }
-
-    private void getHourFormatData() {
-        final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale,
-                (mIs24HourView) ? "Hm" : "hm");
-        final int lengthPattern = bestDateTimePattern.length();
-        mHourWithTwoDigit = false;
-        char hourFormat = '\0';
-        // Check if the returned pattern is single or double 'H', 'h', 'K', 'k'. We also save
-        // the hour format that we found.
-        for (int i = 0; i < lengthPattern; i++) {
-            final char c = bestDateTimePattern.charAt(i);
-            if (c == 'H' || c == 'h' || c == 'K' || c == 'k') {
-                mHourFormat = c;
-                if (i + 1 < lengthPattern && c == bestDateTimePattern.charAt(i + 1)) {
-                    mHourWithTwoDigit = true;
-                }
-                break;
+            if (amPmOnLeft) {
+                params.leftMargin = 0;
+                params.rightMargin = computeMaxWidthOfNumbers(12 /* for hours */);
+            } else {
+                params.leftMargin = computeMaxWidthOfNumbers(60 /* for minutes */);
+                params.rightMargin = 0;
             }
+
+            mAmPmLayout.setLayoutParams(params);
+            mAmPmLayout.setVisibility(View.VISIBLE);
+
+            updateAmPmLabelStates(mInitialHourOfDay < 12 ? AM : PM);
         }
     }
 
-    private boolean isAmPmAtStart() {
-        final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale,
-                "hm" /* skeleton */);
-
-        return bestDateTimePattern.startsWith("a");
-    }
-
     /**
-     * The time separator is defined in the Unicode CLDR and cannot be supposed to be ":".
-     *
-     * See http://unicode.org/cldr/trac/browser/trunk/common/main
-     *
-     * We pass the correct "skeleton" depending on 12 or 24 hours view and then extract the
-     * separator as the character which is just after the hour marker in the returned pattern.
+     * Set the current hour.
      */
-    private void setDividerText() {
-        final String skeleton = (mIs24HourView) ? "Hm" : "hm";
-        final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale,
-                skeleton);
-        final String separatorText;
-        int hourIndex = bestDateTimePattern.lastIndexOf('H');
-        if (hourIndex == -1) {
-            hourIndex = bestDateTimePattern.lastIndexOf('h');
-        }
-        if (hourIndex == -1) {
-            // Default case
-            separatorText = ":";
-        } else {
-            int minuteIndex = bestDateTimePattern.indexOf('m', hourIndex + 1);
-            if  (minuteIndex == -1) {
-                separatorText = Character.toString(bestDateTimePattern.charAt(hourIndex + 1));
-            } else {
-                separatorText = bestDateTimePattern.substring(hourIndex + 1, minuteIndex);
-            }
-        }
-        mDivider.setText(separatorText);
-    }
-
     @Override
     public void setCurrentHour(Integer currentHour) {
-        setCurrentHour(currentHour, true);
-    }
-
-    private void setCurrentHour(Integer currentHour, boolean notifyTimeChanged) {
-        // why was Integer used in the first place?
-        if (currentHour == null || currentHour == getCurrentHour()) {
+        if (mInitialHourOfDay == currentHour) {
             return;
         }
-        if (!is24HourView()) {
-            // convert [0,23] ordinal to wall clock display
-            if (currentHour >= HOURS_IN_HALF_DAY) {
-                mIsAm = false;
-                if (currentHour > HOURS_IN_HALF_DAY) {
-                    currentHour = currentHour - HOURS_IN_HALF_DAY;
-                }
-            } else {
-                mIsAm = true;
-                if (currentHour == 0) {
-                    currentHour = HOURS_IN_HALF_DAY;
-                }
-            }
-            updateAmPmControl();
-        }
-        mHourSpinner.setValue(currentHour);
-        if (notifyTimeChanged) {
-            onTimeChanged();
-        }
-    }
-
-    @Override
-    public Integer getCurrentHour() {
-        int currentHour = mHourSpinner.getValue();
-        if (is24HourView()) {
-            return currentHour;
-        } else if (mIsAm) {
-            return currentHour % HOURS_IN_HALF_DAY;
-        } else {
-            return (currentHour % HOURS_IN_HALF_DAY) + HOURS_IN_HALF_DAY;
-        }
-    }
-
-    @Override
-    public void setCurrentMinute(Integer currentMinute) {
-        if (currentMinute == getCurrentMinute()) {
-            return;
-        }
-        mMinuteSpinner.setValue(currentMinute);
+        mInitialHourOfDay = currentHour;
+        updateHeaderHour(currentHour, true);
+        updateHeaderAmPm();
+        mRadialTimePickerView.setCurrentHour(currentHour);
+        mRadialTimePickerView.setAmOrPm(mInitialHourOfDay < 12 ? AM : PM);
+        mDelegator.invalidate();
         onTimeChanged();
     }
 
+    /**
+     * @return The current hour in the range (0-23).
+     */
     @Override
-    public Integer getCurrentMinute() {
-        return mMinuteSpinner.getValue();
+    public Integer getCurrentHour() {
+        int currentHour = mRadialTimePickerView.getCurrentHour();
+        if (mIs24HourView) {
+            return currentHour;
+        } else {
+            switch(mRadialTimePickerView.getAmOrPm()) {
+                case PM:
+                    return (currentHour % HOURS_IN_HALF_DAY) + HOURS_IN_HALF_DAY;
+                case AM:
+                default:
+                    return currentHour % HOURS_IN_HALF_DAY;
+            }
+        }
     }
 
+    /**
+     * Set the current minute (0-59).
+     */
     @Override
-    public void setIs24HourView(Boolean is24HourView) {
-        if (mIs24HourView == is24HourView) {
+    public void setCurrentMinute(Integer currentMinute) {
+        if (mInitialMinute == currentMinute) {
             return;
         }
-        // cache the current hour since spinner range changes and BEFORE changing mIs24HourView!!
-        int currentHour = getCurrentHour();
-        // Order is important here.
-        mIs24HourView = is24HourView;
-        getHourFormatData();
-        updateHourControl();
-        // set value after spinner range is updated
-        setCurrentHour(currentHour, false);
-        updateMinuteControl();
-        updateAmPmControl();
+        mInitialMinute = currentMinute;
+        updateHeaderMinute(currentMinute, true);
+        mRadialTimePickerView.setCurrentMinute(currentMinute);
+        mDelegator.invalidate();
+        onTimeChanged();
     }
 
+    /**
+     * @return The current minute.
+     */
+    @Override
+    public Integer getCurrentMinute() {
+        return mRadialTimePickerView.getCurrentMinute();
+    }
+
+    /**
+     * Set whether in 24 hour or AM/PM mode.
+     *
+     * @param is24HourView True = 24 hour mode. False = AM/PM.
+     */
+    @Override
+    public void setIs24HourView(Boolean is24HourView) {
+        if (is24HourView == mIs24HourView) {
+            return;
+        }
+        mIs24HourView = is24HourView;
+        generateLegalTimesTree();
+        int hour = mRadialTimePickerView.getCurrentHour();
+        mInitialHourOfDay = hour;
+        updateHeaderHour(hour, false);
+        updateHeaderAmPm();
+        updateRadialPicker(mRadialTimePickerView.getCurrentItemShowing());
+        mDelegator.invalidate();
+    }
+
+    /**
+     * @return true if this is in 24 hour view else false.
+     */
     @Override
     public boolean is24HourView() {
         return mIs24HourView;
     }
 
     @Override
-    public void setOnTimeChangedListener(TimePicker.OnTimeChangedListener onTimeChangedListener) {
-        mOnTimeChangedListener = onTimeChangedListener;
+    public void setOnTimeChangedListener(TimePicker.OnTimeChangedListener callback) {
+        mOnTimeChangedListener = callback;
     }
 
     @Override
     public void setEnabled(boolean enabled) {
-        mMinuteSpinner.setEnabled(enabled);
-        if (mDivider != null) {
-            mDivider.setEnabled(enabled);
-        }
-        mHourSpinner.setEnabled(enabled);
-        if (mAmPmSpinner != null) {
-            mAmPmSpinner.setEnabled(enabled);
-        } else {
-            mAmPmButton.setEnabled(enabled);
-        }
+        mHourView.setEnabled(enabled);
+        mMinuteView.setEnabled(enabled);
+        mAmLabel.setEnabled(enabled);
+        mPmLabel.setEnabled(enabled);
+        mRadialTimePickerView.setEnabled(enabled);
         mIsEnabled = enabled;
     }
 
@@ -386,24 +397,38 @@
 
     @Override
     public int getBaseline() {
-        return mHourSpinner.getBaseline();
+        // does not support baseline alignment
+        return -1;
     }
 
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
-        setCurrentLocale(newConfig.locale);
+        updateUI(mRadialTimePickerView.getCurrentItemShowing());
     }
 
     @Override
     public Parcelable onSaveInstanceState(Parcelable superState) {
-        return new SavedState(superState, getCurrentHour(), getCurrentMinute());
+        return new SavedState(superState, getCurrentHour(), getCurrentMinute(),
+                is24HourView(), inKbMode(), getTypedTimes(), getCurrentItemShowing());
     }
 
     @Override
     public void onRestoreInstanceState(Parcelable state) {
         SavedState ss = (SavedState) state;
-        setCurrentHour(ss.getHour());
-        setCurrentMinute(ss.getMinute());
+        setInKbMode(ss.inKbMode());
+        setTypedTimes(ss.getTypesTimes());
+        initialize(ss.getHour(), ss.getMinute(), ss.is24HourMode(), ss.getCurrentItemShowing());
+        mRadialTimePickerView.invalidate();
+        if (mInKbMode) {
+            tryStartingKbMode(-1);
+            mHourView.invalidate();
+        }
+    }
+
+    @Override
+    public void setCurrentLocale(Locale locale) {
+        super.setCurrentLocale(locale);
+        mTempCalendar = Calendar.getInstance(locale);
     }
 
     @Override
@@ -422,9 +447,9 @@
         }
         mTempCalendar.set(Calendar.HOUR_OF_DAY, getCurrentHour());
         mTempCalendar.set(Calendar.MINUTE, getCurrentMinute());
-        String selectedDateUtterance = DateUtils.formatDateTime(mContext,
+        String selectedDate = DateUtils.formatDateTime(mContext,
                 mTempCalendar.getTimeInMillis(), flags);
-        event.getText().add(selectedDateUtterance);
+        event.getText().add(selectedDate);
     }
 
     @Override
@@ -437,121 +462,48 @@
         info.setClassName(TimePicker.class.getName());
     }
 
-    private void updateInputState() {
-        // Make sure that if the user changes the value and the IME is active
-        // for one of the inputs if this widget, the IME is closed. If the user
-        // changed the value via the IME and there is a next input the IME will
-        // be shown, otherwise the user chose another means of changing the
-        // value and having the IME up makes no sense.
-        InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
-        if (inputMethodManager != null) {
-            if (inputMethodManager.isActive(mHourSpinnerInput)) {
-                mHourSpinnerInput.clearFocus();
-                inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
-            } else if (inputMethodManager.isActive(mMinuteSpinnerInput)) {
-                mMinuteSpinnerInput.clearFocus();
-                inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
-            } else if (inputMethodManager.isActive(mAmPmSpinnerInput)) {
-                mAmPmSpinnerInput.clearFocus();
-                inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
-            }
-        }
-    }
-
-    private void updateAmPmControl() {
-        if (is24HourView()) {
-            if (mAmPmSpinner != null) {
-                mAmPmSpinner.setVisibility(View.GONE);
-            } else {
-                mAmPmButton.setVisibility(View.GONE);
-            }
-        } else {
-            int index = mIsAm ? Calendar.AM : Calendar.PM;
-            if (mAmPmSpinner != null) {
-                mAmPmSpinner.setValue(index);
-                mAmPmSpinner.setVisibility(View.VISIBLE);
-            } else {
-                mAmPmButton.setText(mAmPmStrings[index]);
-                mAmPmButton.setVisibility(View.VISIBLE);
-            }
-        }
-        mDelegator.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
+    /**
+     * Set whether in keyboard mode or not.
+     *
+     * @param inKbMode True means in keyboard mode.
+     */
+    private void setInKbMode(boolean inKbMode) {
+        mInKbMode = inKbMode;
     }
 
     /**
-     * Sets the current locale.
-     *
-     * @param locale The current locale.
+     * @return true if in keyboard mode
      */
-    @Override
-    public void setCurrentLocale(Locale locale) {
-        super.setCurrentLocale(locale);
-        mTempCalendar = Calendar.getInstance(locale);
+    private boolean inKbMode() {
+        return mInKbMode;
     }
 
+    private void setTypedTimes(ArrayList<Integer> typeTimes) {
+        mTypedTimes = typeTimes;
+    }
+
+    /**
+     * @return an array of typed times
+     */
+    private ArrayList<Integer> getTypedTimes() {
+        return mTypedTimes;
+    }
+
+    /**
+     * @return the index of the current item showing
+     */
+    private int getCurrentItemShowing() {
+        return mRadialTimePickerView.getCurrentItemShowing();
+    }
+
+    /**
+     * Propagate the time change
+     */
     private void onTimeChanged() {
         mDelegator.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
         if (mOnTimeChangedListener != null) {
-            mOnTimeChangedListener.onTimeChanged(mDelegator, getCurrentHour(),
-                    getCurrentMinute());
-        }
-    }
-
-    private void updateHourControl() {
-        if (is24HourView()) {
-            // 'k' means 1-24 hour
-            if (mHourFormat == 'k') {
-                mHourSpinner.setMinValue(1);
-                mHourSpinner.setMaxValue(24);
-            } else {
-                mHourSpinner.setMinValue(0);
-                mHourSpinner.setMaxValue(23);
-            }
-        } else {
-            // 'K' means 0-11 hour
-            if (mHourFormat == 'K') {
-                mHourSpinner.setMinValue(0);
-                mHourSpinner.setMaxValue(11);
-            } else {
-                mHourSpinner.setMinValue(1);
-                mHourSpinner.setMaxValue(12);
-            }
-        }
-        mHourSpinner.setFormatter(mHourWithTwoDigit ? NumberPicker.getTwoDigitFormatter() : null);
-    }
-
-    private void updateMinuteControl() {
-        if (is24HourView()) {
-            mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_DONE);
-        } else {
-            mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
-        }
-    }
-
-    private void setContentDescriptions() {
-        // Minute
-        trySetContentDescription(mMinuteSpinner, R.id.increment,
-                R.string.time_picker_increment_minute_button);
-        trySetContentDescription(mMinuteSpinner, R.id.decrement,
-                R.string.time_picker_decrement_minute_button);
-        // Hour
-        trySetContentDescription(mHourSpinner, R.id.increment,
-                R.string.time_picker_increment_hour_button);
-        trySetContentDescription(mHourSpinner, R.id.decrement,
-                R.string.time_picker_decrement_hour_button);
-        // AM/PM
-        if (mAmPmSpinner != null) {
-            trySetContentDescription(mAmPmSpinner, R.id.increment,
-                    R.string.time_picker_increment_set_pm_button);
-            trySetContentDescription(mAmPmSpinner, R.id.decrement,
-                    R.string.time_picker_decrement_set_am_button);
-        }
-    }
-
-    private void trySetContentDescription(View root, int viewId, int contDescResId) {
-        View target = root.findViewById(viewId);
-        if (target != null) {
-            target.setContentDescription(mContext.getString(contDescResId));
+            mOnTimeChangedListener.onTimeChanged(mDelegator,
+                    getCurrentHour(), getCurrentMinute());
         }
     }
 
@@ -559,19 +511,34 @@
      * Used to save / restore state of time picker
      */
     private static class SavedState extends View.BaseSavedState {
+
         private final int mHour;
         private final int mMinute;
+        private final boolean mIs24HourMode;
+        private final boolean mInKbMode;
+        private final ArrayList<Integer> mTypedTimes;
+        private final int mCurrentItemShowing;
 
-        private SavedState(Parcelable superState, int hour, int minute) {
+        private SavedState(Parcelable superState, int hour, int minute, boolean is24HourMode,
+                           boolean isKbMode, ArrayList<Integer> typedTimes,
+                           int currentItemShowing) {
             super(superState);
             mHour = hour;
             mMinute = minute;
+            mIs24HourMode = is24HourMode;
+            mInKbMode = isKbMode;
+            mTypedTimes = typedTimes;
+            mCurrentItemShowing = currentItemShowing;
         }
 
         private SavedState(Parcel in) {
             super(in);
             mHour = in.readInt();
             mMinute = in.readInt();
+            mIs24HourMode = (in.readInt() == 1);
+            mInKbMode = (in.readInt() == 1);
+            mTypedTimes = in.readArrayList(getClass().getClassLoader());
+            mCurrentItemShowing = in.readInt();
         }
 
         public int getHour() {
@@ -582,11 +549,31 @@
             return mMinute;
         }
 
+        public boolean is24HourMode() {
+            return mIs24HourMode;
+        }
+
+        public boolean inKbMode() {
+            return mInKbMode;
+        }
+
+        public ArrayList<Integer> getTypesTimes() {
+            return mTypedTimes;
+        }
+
+        public int getCurrentItemShowing() {
+            return mCurrentItemShowing;
+        }
+
         @Override
         public void writeToParcel(Parcel dest, int flags) {
             super.writeToParcel(dest, flags);
             dest.writeInt(mHour);
             dest.writeInt(mMinute);
+            dest.writeInt(mIs24HourMode ? 1 : 0);
+            dest.writeInt(mInKbMode ? 1 : 0);
+            dest.writeList(mTypedTimes);
+            dest.writeInt(mCurrentItemShowing);
         }
 
         @SuppressWarnings({"unused", "hiding"})
@@ -601,11 +588,706 @@
         };
     }
 
-    public static String[] getAmPmStrings(Context context) {
-        String[] result = new String[2];
-        LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale);
-        result[0] = d.amPm[0].length() > 2 ? d.narrowAm : d.amPm[0];
-        result[1] = d.amPm[1].length() > 2 ? d.narrowPm : d.amPm[1];
-        return result;
+    private void tryVibrate() {
+        mDelegator.performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);
     }
+
+    private void updateAmPmLabelStates(int amOrPm) {
+        final boolean isAm = amOrPm == AM;
+        mAmLabel.setChecked(isAm);
+        mAmLabel.setAlpha(isAm ? 1 : mDisabledAlpha);
+
+        final boolean isPm = amOrPm == PM;
+        mPmLabel.setChecked(isPm);
+        mPmLabel.setAlpha(isPm ? 1 : mDisabledAlpha);
+    }
+
+    /**
+     * Called by the picker for updating the header display.
+     */
+    @Override
+    public void onValueSelected(int pickerIndex, int newValue, boolean autoAdvance) {
+        if (pickerIndex == HOUR_INDEX) {
+            if (mAllowAutoAdvance && autoAdvance) {
+                updateHeaderHour(newValue, false);
+                setCurrentItemShowing(MINUTE_INDEX, true, false);
+                mRadialTimePickerView.announceForAccessibility(newValue + ". " + mSelectMinutes);
+            } else {
+                updateHeaderHour(newValue, true);
+                mRadialTimePickerView.setContentDescription(
+                        mHourPickerDescription + ": " + newValue);
+            }
+        } else if (pickerIndex == MINUTE_INDEX){
+            updateHeaderMinute(newValue, true);
+            mRadialTimePickerView.setContentDescription(mMinutePickerDescription + ": " + newValue);
+        } else if (pickerIndex == AMPM_INDEX) {
+            updateAmPmLabelStates(newValue);
+        } else if (pickerIndex == ENABLE_PICKER_INDEX) {
+            if (!isTypedTimeFullyLegal()) {
+                mTypedTimes.clear();
+            }
+            finishKbMode();
+        }
+    }
+
+    private void updateHeaderHour(int value, boolean announce) {
+        final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale,
+                (mIs24HourView) ? "Hm" : "hm");
+        final int lengthPattern = bestDateTimePattern.length();
+        boolean hourWithTwoDigit = false;
+        char hourFormat = '\0';
+        // Check if the returned pattern is single or double 'H', 'h', 'K', 'k'. We also save
+        // the hour format that we found.
+        for (int i = 0; i < lengthPattern; i++) {
+            final char c = bestDateTimePattern.charAt(i);
+            if (c == 'H' || c == 'h' || c == 'K' || c == 'k') {
+                hourFormat = c;
+                if (i + 1 < lengthPattern && c == bestDateTimePattern.charAt(i + 1)) {
+                    hourWithTwoDigit = true;
+                }
+                break;
+            }
+        }
+        final String format;
+        if (hourWithTwoDigit) {
+            format = "%02d";
+        } else {
+            format = "%d";
+        }
+        if (mIs24HourView) {
+            // 'k' means 1-24 hour
+            if (hourFormat == 'k' && value == 0) {
+                value = 24;
+            }
+        } else {
+            // 'K' means 0-11 hour
+            value = modulo12(value, hourFormat == 'K');
+        }
+        CharSequence text = String.format(format, value);
+        mHourView.setText(text);
+        if (announce) {
+            tryAnnounceForAccessibility(text, true);
+        }
+    }
+
+    private void tryAnnounceForAccessibility(CharSequence text, boolean isHour) {
+        if (mLastAnnouncedIsHour != isHour || !text.equals(mLastAnnouncedText)) {
+            // TODO: Find a better solution, potentially live regions?
+            mDelegator.announceForAccessibility(text);
+            mLastAnnouncedText = text;
+            mLastAnnouncedIsHour = isHour;
+        }
+    }
+
+    private static int modulo12(int n, boolean startWithZero) {
+        int value = n % 12;
+        if (value == 0 && !startWithZero) {
+            value = 12;
+        }
+        return value;
+    }
+
+    /**
+     * The time separator is defined in the Unicode CLDR and cannot be supposed to be ":".
+     *
+     * See http://unicode.org/cldr/trac/browser/trunk/common/main
+     *
+     * We pass the correct "skeleton" depending on 12 or 24 hours view and then extract the
+     * separator as the character which is just after the hour marker in the returned pattern.
+     */
+    private void updateHeaderSeparator() {
+        final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale,
+                (mIs24HourView) ? "Hm" : "hm");
+        final String separatorText;
+        // See http://www.unicode.org/reports/tr35/tr35-dates.html for hour formats
+        final char[] hourFormats = {'H', 'h', 'K', 'k'};
+        int hIndex = lastIndexOfAny(bestDateTimePattern, hourFormats);
+        if (hIndex == -1) {
+            // Default case
+            separatorText = ":";
+        } else {
+            separatorText = Character.toString(bestDateTimePattern.charAt(hIndex + 1));
+        }
+        mSeparatorView.setText(separatorText);
+    }
+
+    static private int lastIndexOfAny(String str, char[] any) {
+        final int lengthAny = any.length;
+        if (lengthAny > 0) {
+            for (int i = str.length() - 1; i >= 0; i--) {
+                char c = str.charAt(i);
+                for (int j = 0; j < lengthAny; j++) {
+                    if (c == any[j]) {
+                        return i;
+                    }
+                }
+            }
+        }
+        return -1;
+    }
+
+    private void updateHeaderMinute(int value, boolean announceForAccessibility) {
+        if (value == 60) {
+            value = 0;
+        }
+        final CharSequence text = String.format(mCurrentLocale, "%02d", value);
+        mMinuteView.setText(text);
+        if (announceForAccessibility) {
+            tryAnnounceForAccessibility(text, false);
+        }
+    }
+
+    /**
+     * Show either Hours or Minutes.
+     */
+    private void setCurrentItemShowing(int index, boolean animateCircle, boolean announce) {
+        mRadialTimePickerView.setCurrentItemShowing(index, animateCircle);
+
+        if (index == HOUR_INDEX) {
+            int hours = mRadialTimePickerView.getCurrentHour();
+            if (!mIs24HourView) {
+                hours = hours % 12;
+            }
+            mRadialTimePickerView.setContentDescription(mHourPickerDescription + ": " + hours);
+            if (announce) {
+                mRadialTimePickerView.announceForAccessibility(mSelectHours);
+            }
+        } else {
+            int minutes = mRadialTimePickerView.getCurrentMinute();
+            mRadialTimePickerView.setContentDescription(mMinutePickerDescription + ": " + minutes);
+            if (announce) {
+                mRadialTimePickerView.announceForAccessibility(mSelectMinutes);
+            }
+        }
+
+        mHourView.setSelected(index == HOUR_INDEX);
+        mMinuteView.setSelected(index == MINUTE_INDEX);
+    }
+
+    private void setAmOrPm(int amOrPm) {
+        updateAmPmLabelStates(amOrPm);
+        mRadialTimePickerView.setAmOrPm(amOrPm);
+    }
+
+    /**
+     * For keyboard mode, processes key events.
+     *
+     * @param keyCode the pressed key.
+     *
+     * @return true if the key was successfully processed, false otherwise.
+     */
+    private boolean processKeyUp(int keyCode) {
+        if (keyCode == KeyEvent.KEYCODE_DEL) {
+            if (mInKbMode) {
+                if (!mTypedTimes.isEmpty()) {
+                    int deleted = deleteLastTypedKey();
+                    String deletedKeyStr;
+                    if (deleted == getAmOrPmKeyCode(AM)) {
+                        deletedKeyStr = mAmText;
+                    } else if (deleted == getAmOrPmKeyCode(PM)) {
+                        deletedKeyStr = mPmText;
+                    } else {
+                        deletedKeyStr = String.format("%d", getValFromKeyCode(deleted));
+                    }
+                    mRadialTimePickerView.announceForAccessibility(
+                            String.format(mDeletedKeyFormat, deletedKeyStr));
+                    updateDisplay(true);
+                }
+            }
+        } else if (keyCode == KeyEvent.KEYCODE_0 || keyCode == KeyEvent.KEYCODE_1
+                || keyCode == KeyEvent.KEYCODE_2 || keyCode == KeyEvent.KEYCODE_3
+                || keyCode == KeyEvent.KEYCODE_4 || keyCode == KeyEvent.KEYCODE_5
+                || keyCode == KeyEvent.KEYCODE_6 || keyCode == KeyEvent.KEYCODE_7
+                || keyCode == KeyEvent.KEYCODE_8 || keyCode == KeyEvent.KEYCODE_9
+                || (!mIs24HourView &&
+                (keyCode == getAmOrPmKeyCode(AM) || keyCode == getAmOrPmKeyCode(PM)))) {
+            if (!mInKbMode) {
+                if (mRadialTimePickerView == null) {
+                    // Something's wrong, because time picker should definitely not be null.
+                    Log.e(TAG, "Unable to initiate keyboard mode, TimePicker was null.");
+                    return true;
+                }
+                mTypedTimes.clear();
+                tryStartingKbMode(keyCode);
+                return true;
+            }
+            // We're already in keyboard mode.
+            if (addKeyIfLegal(keyCode)) {
+                updateDisplay(false);
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Try to start keyboard mode with the specified key.
+     *
+     * @param keyCode The key to use as the first press. Keyboard mode will not be started if the
+     * key is not legal to start with. Or, pass in -1 to get into keyboard mode without a starting
+     * key.
+     */
+    private void tryStartingKbMode(int keyCode) {
+        if (keyCode == -1 || addKeyIfLegal(keyCode)) {
+            mInKbMode = true;
+            onValidationChanged(false);
+            updateDisplay(false);
+            mRadialTimePickerView.setInputEnabled(false);
+        }
+    }
+
+    private boolean addKeyIfLegal(int keyCode) {
+        // If we're in 24hour mode, we'll need to check if the input is full. If in AM/PM mode,
+        // we'll need to see if AM/PM have been typed.
+        if ((mIs24HourView && mTypedTimes.size() == 4) ||
+                (!mIs24HourView && isTypedTimeFullyLegal())) {
+            return false;
+        }
+
+        mTypedTimes.add(keyCode);
+        if (!isTypedTimeLegalSoFar()) {
+            deleteLastTypedKey();
+            return false;
+        }
+
+        int val = getValFromKeyCode(keyCode);
+        mRadialTimePickerView.announceForAccessibility(String.format("%d", val));
+        // Automatically fill in 0's if AM or PM was legally entered.
+        if (isTypedTimeFullyLegal()) {
+            if (!mIs24HourView && mTypedTimes.size() <= 3) {
+                mTypedTimes.add(mTypedTimes.size() - 1, KeyEvent.KEYCODE_0);
+                mTypedTimes.add(mTypedTimes.size() - 1, KeyEvent.KEYCODE_0);
+            }
+            onValidationChanged(true);
+        }
+
+        return true;
+    }
+
+    /**
+     * Traverse the tree to see if the keys that have been typed so far are legal as is,
+     * or may become legal as more keys are typed (excluding backspace).
+     */
+    private boolean isTypedTimeLegalSoFar() {
+        Node node = mLegalTimesTree;
+        for (int keyCode : mTypedTimes) {
+            node = node.canReach(keyCode);
+            if (node == null) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Check if the time that has been typed so far is completely legal, as is.
+     */
+    private boolean isTypedTimeFullyLegal() {
+        if (mIs24HourView) {
+            // For 24-hour mode, the time is legal if the hours and minutes are each legal. Note:
+            // getEnteredTime() will ONLY call isTypedTimeFullyLegal() when NOT in 24hour mode.
+            int[] values = getEnteredTime(null);
+            return (values[0] >= 0 && values[1] >= 0 && values[1] < 60);
+        } else {
+            // For AM/PM mode, the time is legal if it contains an AM or PM, as those can only be
+            // legally added at specific times based on the tree's algorithm.
+            return (mTypedTimes.contains(getAmOrPmKeyCode(AM)) ||
+                    mTypedTimes.contains(getAmOrPmKeyCode(PM)));
+        }
+    }
+
+    private int deleteLastTypedKey() {
+        int deleted = mTypedTimes.remove(mTypedTimes.size() - 1);
+        if (!isTypedTimeFullyLegal()) {
+            onValidationChanged(false);
+        }
+        return deleted;
+    }
+
+    /**
+     * Get out of keyboard mode. If there is nothing in typedTimes, revert to TimePicker's time.
+     */
+    private void finishKbMode() {
+        mInKbMode = false;
+        if (!mTypedTimes.isEmpty()) {
+            int values[] = getEnteredTime(null);
+            mRadialTimePickerView.setCurrentHour(values[0]);
+            mRadialTimePickerView.setCurrentMinute(values[1]);
+            if (!mIs24HourView) {
+                mRadialTimePickerView.setAmOrPm(values[2]);
+            }
+            mTypedTimes.clear();
+        }
+        updateDisplay(false);
+        mRadialTimePickerView.setInputEnabled(true);
+    }
+
+    /**
+     * Update the hours, minutes, and AM/PM displays with the typed times. If the typedTimes is
+     * empty, either show an empty display (filled with the placeholder text), or update from the
+     * timepicker's values.
+     *
+     * @param allowEmptyDisplay if true, then if the typedTimes is empty, use the placeholder text.
+     * Otherwise, revert to the timepicker's values.
+     */
+    private void updateDisplay(boolean allowEmptyDisplay) {
+        if (!allowEmptyDisplay && mTypedTimes.isEmpty()) {
+            int hour = mRadialTimePickerView.getCurrentHour();
+            int minute = mRadialTimePickerView.getCurrentMinute();
+            updateHeaderHour(hour, false);
+            updateHeaderMinute(minute, false);
+            if (!mIs24HourView) {
+                updateAmPmLabelStates(hour < 12 ? AM : PM);
+            }
+            setCurrentItemShowing(mRadialTimePickerView.getCurrentItemShowing(), true, true);
+            onValidationChanged(true);
+        } else {
+            boolean[] enteredZeros = {false, false};
+            int[] values = getEnteredTime(enteredZeros);
+            String hourFormat = enteredZeros[0] ? "%02d" : "%2d";
+            String minuteFormat = (enteredZeros[1]) ? "%02d" : "%2d";
+            String hourStr = (values[0] == -1) ? mDoublePlaceholderText :
+                    String.format(hourFormat, values[0]).replace(' ', mPlaceholderText);
+            String minuteStr = (values[1] == -1) ? mDoublePlaceholderText :
+                    String.format(minuteFormat, values[1]).replace(' ', mPlaceholderText);
+            mHourView.setText(hourStr);
+            mHourView.setSelected(false);
+            mMinuteView.setText(minuteStr);
+            mMinuteView.setSelected(false);
+            if (!mIs24HourView) {
+                updateAmPmLabelStates(values[2]);
+            }
+        }
+    }
+
+    private int getValFromKeyCode(int keyCode) {
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_0:
+                return 0;
+            case KeyEvent.KEYCODE_1:
+                return 1;
+            case KeyEvent.KEYCODE_2:
+                return 2;
+            case KeyEvent.KEYCODE_3:
+                return 3;
+            case KeyEvent.KEYCODE_4:
+                return 4;
+            case KeyEvent.KEYCODE_5:
+                return 5;
+            case KeyEvent.KEYCODE_6:
+                return 6;
+            case KeyEvent.KEYCODE_7:
+                return 7;
+            case KeyEvent.KEYCODE_8:
+                return 8;
+            case KeyEvent.KEYCODE_9:
+                return 9;
+            default:
+                return -1;
+        }
+    }
+
+    /**
+     * Get the currently-entered time, as integer values of the hours and minutes typed.
+     *
+     * @param enteredZeros A size-2 boolean array, which the caller should initialize, and which
+     * may then be used for the caller to know whether zeros had been explicitly entered as either
+     * hours of minutes. This is helpful for deciding whether to show the dashes, or actual 0's.
+     *
+     * @return A size-3 int array. The first value will be the hours, the second value will be the
+     * minutes, and the third will be either AM or PM.
+     */
+    private int[] getEnteredTime(boolean[] enteredZeros) {
+        int amOrPm = -1;
+        int startIndex = 1;
+        if (!mIs24HourView && isTypedTimeFullyLegal()) {
+            int keyCode = mTypedTimes.get(mTypedTimes.size() - 1);
+            if (keyCode == getAmOrPmKeyCode(AM)) {
+                amOrPm = AM;
+            } else if (keyCode == getAmOrPmKeyCode(PM)){
+                amOrPm = PM;
+            }
+            startIndex = 2;
+        }
+        int minute = -1;
+        int hour = -1;
+        for (int i = startIndex; i <= mTypedTimes.size(); i++) {
+            int val = getValFromKeyCode(mTypedTimes.get(mTypedTimes.size() - i));
+            if (i == startIndex) {
+                minute = val;
+            } else if (i == startIndex+1) {
+                minute += 10 * val;
+                if (enteredZeros != null && val == 0) {
+                    enteredZeros[1] = true;
+                }
+            } else if (i == startIndex+2) {
+                hour = val;
+            } else if (i == startIndex+3) {
+                hour += 10 * val;
+                if (enteredZeros != null && val == 0) {
+                    enteredZeros[0] = true;
+                }
+            }
+        }
+
+        return new int[] { hour, minute, amOrPm };
+    }
+
+    /**
+     * Get the keycode value for AM and PM in the current language.
+     */
+    private int getAmOrPmKeyCode(int amOrPm) {
+        // Cache the codes.
+        if (mAmKeyCode == -1 || mPmKeyCode == -1) {
+            // Find the first character in the AM/PM text that is unique.
+            KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
+            char amChar;
+            char pmChar;
+            for (int i = 0; i < Math.max(mAmText.length(), mPmText.length()); i++) {
+                amChar = mAmText.toLowerCase(mCurrentLocale).charAt(i);
+                pmChar = mPmText.toLowerCase(mCurrentLocale).charAt(i);
+                if (amChar != pmChar) {
+                    KeyEvent[] events = kcm.getEvents(new char[]{amChar, pmChar});
+                    // There should be 4 events: a down and up for both AM and PM.
+                    if (events != null && events.length == 4) {
+                        mAmKeyCode = events[0].getKeyCode();
+                        mPmKeyCode = events[2].getKeyCode();
+                    } else {
+                        Log.e(TAG, "Unable to find keycodes for AM and PM.");
+                    }
+                    break;
+                }
+            }
+        }
+        if (amOrPm == AM) {
+            return mAmKeyCode;
+        } else if (amOrPm == PM) {
+            return mPmKeyCode;
+        }
+
+        return -1;
+    }
+
+    /**
+     * Create a tree for deciding what keys can legally be typed.
+     */
+    private void generateLegalTimesTree() {
+        // Create a quick cache of numbers to their keycodes.
+        final int k0 = KeyEvent.KEYCODE_0;
+        final int k1 = KeyEvent.KEYCODE_1;
+        final int k2 = KeyEvent.KEYCODE_2;
+        final int k3 = KeyEvent.KEYCODE_3;
+        final int k4 = KeyEvent.KEYCODE_4;
+        final int k5 = KeyEvent.KEYCODE_5;
+        final int k6 = KeyEvent.KEYCODE_6;
+        final int k7 = KeyEvent.KEYCODE_7;
+        final int k8 = KeyEvent.KEYCODE_8;
+        final int k9 = KeyEvent.KEYCODE_9;
+
+        // The root of the tree doesn't contain any numbers.
+        mLegalTimesTree = new Node();
+        if (mIs24HourView) {
+            // We'll be re-using these nodes, so we'll save them.
+            Node minuteFirstDigit = new Node(k0, k1, k2, k3, k4, k5);
+            Node minuteSecondDigit = new Node(k0, k1, k2, k3, k4, k5, k6, k7, k8, k9);
+            // The first digit must be followed by the second digit.
+            minuteFirstDigit.addChild(minuteSecondDigit);
+
+            // The first digit may be 0-1.
+            Node firstDigit = new Node(k0, k1);
+            mLegalTimesTree.addChild(firstDigit);
+
+            // When the first digit is 0-1, the second digit may be 0-5.
+            Node secondDigit = new Node(k0, k1, k2, k3, k4, k5);
+            firstDigit.addChild(secondDigit);
+            // We may now be followed by the first minute digit. E.g. 00:09, 15:58.
+            secondDigit.addChild(minuteFirstDigit);
+
+            // When the first digit is 0-1, and the second digit is 0-5, the third digit may be 6-9.
+            Node thirdDigit = new Node(k6, k7, k8, k9);
+            // The time must now be finished. E.g. 0:55, 1:08.
+            secondDigit.addChild(thirdDigit);
+
+            // When the first digit is 0-1, the second digit may be 6-9.
+            secondDigit = new Node(k6, k7, k8, k9);
+            firstDigit.addChild(secondDigit);
+            // We must now be followed by the first minute digit. E.g. 06:50, 18:20.
+            secondDigit.addChild(minuteFirstDigit);
+
+            // The first digit may be 2.
+            firstDigit = new Node(k2);
+            mLegalTimesTree.addChild(firstDigit);
+
+            // When the first digit is 2, the second digit may be 0-3.
+            secondDigit = new Node(k0, k1, k2, k3);
+            firstDigit.addChild(secondDigit);
+            // We must now be followed by the first minute digit. E.g. 20:50, 23:09.
+            secondDigit.addChild(minuteFirstDigit);
+
+            // When the first digit is 2, the second digit may be 4-5.
+            secondDigit = new Node(k4, k5);
+            firstDigit.addChild(secondDigit);
+            // We must now be followd by the last minute digit. E.g. 2:40, 2:53.
+            secondDigit.addChild(minuteSecondDigit);
+
+            // The first digit may be 3-9.
+            firstDigit = new Node(k3, k4, k5, k6, k7, k8, k9);
+            mLegalTimesTree.addChild(firstDigit);
+            // We must now be followed by the first minute digit. E.g. 3:57, 8:12.
+            firstDigit.addChild(minuteFirstDigit);
+        } else {
+            // We'll need to use the AM/PM node a lot.
+            // Set up AM and PM to respond to "a" and "p".
+            Node ampm = new Node(getAmOrPmKeyCode(AM), getAmOrPmKeyCode(PM));
+
+            // The first hour digit may be 1.
+            Node firstDigit = new Node(k1);
+            mLegalTimesTree.addChild(firstDigit);
+            // We'll allow quick input of on-the-hour times. E.g. 1pm.
+            firstDigit.addChild(ampm);
+
+            // When the first digit is 1, the second digit may be 0-2.
+            Node secondDigit = new Node(k0, k1, k2);
+            firstDigit.addChild(secondDigit);
+            // Also for quick input of on-the-hour times. E.g. 10pm, 12am.
+            secondDigit.addChild(ampm);
+
+            // When the first digit is 1, and the second digit is 0-2, the third digit may be 0-5.
+            Node thirdDigit = new Node(k0, k1, k2, k3, k4, k5);
+            secondDigit.addChild(thirdDigit);
+            // The time may be finished now. E.g. 1:02pm, 1:25am.
+            thirdDigit.addChild(ampm);
+
+            // When the first digit is 1, the second digit is 0-2, and the third digit is 0-5,
+            // the fourth digit may be 0-9.
+            Node fourthDigit = new Node(k0, k1, k2, k3, k4, k5, k6, k7, k8, k9);
+            thirdDigit.addChild(fourthDigit);
+            // The time must be finished now. E.g. 10:49am, 12:40pm.
+            fourthDigit.addChild(ampm);
+
+            // When the first digit is 1, and the second digit is 0-2, the third digit may be 6-9.
+            thirdDigit = new Node(k6, k7, k8, k9);
+            secondDigit.addChild(thirdDigit);
+            // The time must be finished now. E.g. 1:08am, 1:26pm.
+            thirdDigit.addChild(ampm);
+
+            // When the first digit is 1, the second digit may be 3-5.
+            secondDigit = new Node(k3, k4, k5);
+            firstDigit.addChild(secondDigit);
+
+            // When the first digit is 1, and the second digit is 3-5, the third digit may be 0-9.
+            thirdDigit = new Node(k0, k1, k2, k3, k4, k5, k6, k7, k8, k9);
+            secondDigit.addChild(thirdDigit);
+            // The time must be finished now. E.g. 1:39am, 1:50pm.
+            thirdDigit.addChild(ampm);
+
+            // The hour digit may be 2-9.
+            firstDigit = new Node(k2, k3, k4, k5, k6, k7, k8, k9);
+            mLegalTimesTree.addChild(firstDigit);
+            // We'll allow quick input of on-the-hour-times. E.g. 2am, 5pm.
+            firstDigit.addChild(ampm);
+
+            // When the first digit is 2-9, the second digit may be 0-5.
+            secondDigit = new Node(k0, k1, k2, k3, k4, k5);
+            firstDigit.addChild(secondDigit);
+
+            // When the first digit is 2-9, and the second digit is 0-5, the third digit may be 0-9.
+            thirdDigit = new Node(k0, k1, k2, k3, k4, k5, k6, k7, k8, k9);
+            secondDigit.addChild(thirdDigit);
+            // The time must be finished now. E.g. 2:57am, 9:30pm.
+            thirdDigit.addChild(ampm);
+        }
+    }
+
+    /**
+     * Simple node class to be used for traversal to check for legal times.
+     * mLegalKeys represents the keys that can be typed to get to the node.
+     * mChildren are the children that can be reached from this node.
+     */
+    private class Node {
+        private int[] mLegalKeys;
+        private ArrayList<Node> mChildren;
+
+        public Node(int... legalKeys) {
+            mLegalKeys = legalKeys;
+            mChildren = new ArrayList<Node>();
+        }
+
+        public void addChild(Node child) {
+            mChildren.add(child);
+        }
+
+        public boolean containsKey(int key) {
+            for (int i = 0; i < mLegalKeys.length; i++) {
+                if (mLegalKeys[i] == key) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public Node canReach(int key) {
+            if (mChildren == null) {
+                return null;
+            }
+            for (Node child : mChildren) {
+                if (child.containsKey(key)) {
+                    return child;
+                }
+            }
+            return null;
+        }
+    }
+
+    private final View.OnClickListener mClickListener = new View.OnClickListener() {
+        @Override
+        public void onClick(View v) {
+
+            final int amOrPm;
+            switch (v.getId()) {
+                case R.id.am_label:
+                    setAmOrPm(AM);
+                    break;
+                case R.id.pm_label:
+                    setAmOrPm(PM);
+                    break;
+                case R.id.hours:
+                    setCurrentItemShowing(HOUR_INDEX, true, true);
+                    break;
+                case R.id.minutes:
+                    setCurrentItemShowing(MINUTE_INDEX, true, true);
+                    break;
+                default:
+                    // Failed to handle this click, don't vibrate.
+                    return;
+            }
+
+            tryVibrate();
+        }
+    };
+
+    private final View.OnKeyListener mKeyListener = new View.OnKeyListener() {
+        @Override
+        public boolean onKey(View v, int keyCode, KeyEvent event) {
+            if (event.getAction() == KeyEvent.ACTION_UP) {
+                return processKeyUp(keyCode);
+            }
+            return false;
+        }
+    };
+
+    private final View.OnFocusChangeListener mFocusListener = new View.OnFocusChangeListener() {
+        @Override
+        public void onFocusChange(View v, boolean hasFocus) {
+            if (!hasFocus && mInKbMode && isTypedTimeFullyLegal()) {
+                finishKbMode();
+
+                if (mOnTimeChangedListener != null) {
+                    mOnTimeChangedListener.onTimeChanged(mDelegator,
+                            mRadialTimePickerView.getCurrentHour(),
+                            mRadialTimePickerView.getCurrentMinute());
+                }
+            }
+        }
+    };
 }
diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
index 73e05e8..e162f4a 100644
--- a/core/java/android/widget/TimePickerSpinnerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -17,380 +17,365 @@
 package android.widget;
 
 import android.content.Context;
-import android.content.res.ColorStateList;
 import android.content.res.Configuration;
-import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.text.TextUtils;
 import android.text.format.DateFormat;
 import android.text.format.DateUtils;
 import android.util.AttributeSet;
-import android.util.Log;
-import android.view.HapticFeedbackConstants;
-import android.view.KeyCharacterMap;
-import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
-
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
 import com.android.internal.R;
 
-import java.util.ArrayList;
+import java.text.DateFormatSymbols;
 import java.util.Calendar;
 import java.util.Locale;
 
+import libcore.icu.LocaleData;
+
+import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
+import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
+
 /**
- * A view for selecting the time of day, in either 24 hour or AM/PM mode.
+ * A delegate implementing the basic spinner-based TimePicker.
  */
-class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate implements
-        RadialTimePickerView.OnValueSelectedListener {
-
-    private static final String TAG = "TimePickerDelegate";
-
-    // Index used by RadialPickerLayout
-    private static final int HOUR_INDEX = 0;
-    private static final int MINUTE_INDEX = 1;
-
-    // NOT a real index for the purpose of what's showing.
-    private static final int AMPM_INDEX = 2;
-
-    // Also NOT a real index, just used for keyboard mode.
-    private static final int ENABLE_PICKER_INDEX = 3;
-
-    private static final int AM = 0;
-    private static final int PM = 1;
-
+class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate {
     private static final boolean DEFAULT_ENABLED_STATE = true;
-    private boolean mIsEnabled = DEFAULT_ENABLED_STATE;
-
     private static final int HOURS_IN_HALF_DAY = 12;
 
-    private View mHeaderView;
-    private TextView mHourView;
-    private TextView mMinuteView;
-    private TextView mAmPmTextView;
-    private RadialTimePickerView mRadialTimePickerView;
-    private TextView mSeparatorView;
-
-    private String mAmText;
-    private String mPmText;
-
-    private boolean mAllowAutoAdvance;
-    private int mInitialHourOfDay;
-    private int mInitialMinute;
+    // state
     private boolean mIs24HourView;
+    private boolean mIsAm;
 
-    // For hardware IME input.
-    private char mPlaceholderText;
-    private String mDoublePlaceholderText;
-    private String mDeletedKeyFormat;
-    private boolean mInKbMode;
-    private ArrayList<Integer> mTypedTimes = new ArrayList<Integer>();
-    private Node mLegalTimesTree;
-    private int mAmKeyCode;
-    private int mPmKeyCode;
+    // ui components
+    private final NumberPicker mHourSpinner;
+    private final NumberPicker mMinuteSpinner;
+    private final NumberPicker mAmPmSpinner;
+    private final EditText mHourSpinnerInput;
+    private final EditText mMinuteSpinnerInput;
+    private final EditText mAmPmSpinnerInput;
+    private final TextView mDivider;
 
-    // Accessibility strings.
-    private String mHourPickerDescription;
-    private String mSelectHours;
-    private String mMinutePickerDescription;
-    private String mSelectMinutes;
+    // Note that the legacy implementation of the TimePicker is
+    // using a button for toggling between AM/PM while the new
+    // version uses a NumberPicker spinner. Therefore the code
+    // accommodates these two cases to be backwards compatible.
+    private final Button mAmPmButton;
 
+    private final String[] mAmPmStrings;
+
+    private boolean mIsEnabled = DEFAULT_ENABLED_STATE;
     private Calendar mTempCalendar;
+    private boolean mHourWithTwoDigit;
+    private char mHourFormat;
 
     public TimePickerSpinnerDelegate(TimePicker delegator, Context context, AttributeSet attrs,
             int defStyleAttr, int defStyleRes) {
         super(delegator, context);
 
         // process style attributes
-        final TypedArray a = mContext.obtainStyledAttributes(attrs,
-                R.styleable.TimePicker, defStyleAttr, defStyleRes);
-        final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
-                Context.LAYOUT_INFLATER_SERVICE);
-        final Resources res = mContext.getResources();
-
-        mHourPickerDescription = res.getString(R.string.hour_picker_description);
-        mSelectHours = res.getString(R.string.select_hours);
-        mMinutePickerDescription = res.getString(R.string.minute_picker_description);
-        mSelectMinutes = res.getString(R.string.select_minutes);
-
-        String[] amPmStrings = TimePickerClockDelegate.getAmPmStrings(context);
-        mAmText = amPmStrings[0];
-        mPmText = amPmStrings[1];
-
-        final int layoutResourceId = a.getResourceId(R.styleable.TimePicker_internalLayout,
-                R.layout.time_picker_holo);
-        final View mainView = inflater.inflate(layoutResourceId, null);
-        mDelegator.addView(mainView);
-
-        mHourView = (TextView) mainView.findViewById(R.id.hours);
-        mSeparatorView = (TextView) mainView.findViewById(R.id.separator);
-        mMinuteView = (TextView) mainView.findViewById(R.id.minutes);
-        mAmPmTextView = (TextView) mainView.findViewById(R.id.ampm_label);
-
-        // Set up text appearances from style.
-        final int headerTimeTextAppearance = a.getResourceId(
-                R.styleable.TimePicker_headerTimeTextAppearance, 0);
-        if (headerTimeTextAppearance != 0) {
-            mHourView.setTextAppearance(context, headerTimeTextAppearance);
-            mSeparatorView.setTextAppearance(context, headerTimeTextAppearance);
-            mMinuteView.setTextAppearance(context, headerTimeTextAppearance);
-        }
-
-        final int headerSelectedTextColor = a.getColor(
-                R.styleable.TimePicker_headerSelectedTextColor,
-                res.getColor(R.color.timepicker_default_selector_color_material));
-        mHourView.setTextColor(ColorStateList.addFirstIfMissing(mHourView.getTextColors(),
-                R.attr.state_selected, headerSelectedTextColor));
-        mMinuteView.setTextColor(ColorStateList.addFirstIfMissing(mMinuteView.getTextColors(),
-                R.attr.state_selected, headerSelectedTextColor));
-
-        final int headerAmPmTextAppearance = a.getResourceId(
-                R.styleable.TimePicker_headerAmPmTextAppearance, 0);
-        if (headerAmPmTextAppearance != 0) {
-            mAmPmTextView.setTextAppearance(context, headerAmPmTextAppearance);
-        }
-
-        mHeaderView = mainView.findViewById(R.id.time_header);
-        mHeaderView.setBackground(a.getDrawable(R.styleable.TimePicker_headerBackground));
-
+        final TypedArray a = mContext.obtainStyledAttributes(
+                attrs, R.styleable.TimePicker, defStyleAttr, defStyleRes);
+        final int layoutResourceId = a.getResourceId(
+                R.styleable.TimePicker_legacyLayout, R.layout.time_picker_legacy);
         a.recycle();
 
-        mRadialTimePickerView = (RadialTimePickerView) mainView.findViewById(
-                R.id.radial_picker);
+        final LayoutInflater inflater = LayoutInflater.from(mContext);
+        inflater.inflate(layoutResourceId, mDelegator, true);
 
-        setupListeners();
-
-        mAllowAutoAdvance = true;
-
-        // Set up for keyboard mode.
-        mDoublePlaceholderText = res.getString(R.string.time_placeholder);
-        mDeletedKeyFormat = res.getString(R.string.deleted_key);
-        mPlaceholderText = mDoublePlaceholderText.charAt(0);
-        mAmKeyCode = mPmKeyCode = -1;
-        generateLegalTimesTree();
-
-        // Initialize with current time
-        final Calendar calendar = Calendar.getInstance(mCurrentLocale);
-        final int currentHour = calendar.get(Calendar.HOUR_OF_DAY);
-        final int currentMinute = calendar.get(Calendar.MINUTE);
-        initialize(currentHour, currentMinute, false /* 12h */, HOUR_INDEX);
-    }
-
-    private void initialize(int hourOfDay, int minute, boolean is24HourView, int index) {
-        mInitialHourOfDay = hourOfDay;
-        mInitialMinute = minute;
-        mIs24HourView = is24HourView;
-        mInKbMode = false;
-        updateUI(index);
-    }
-
-    private void setupListeners() {
-        mHeaderView.setOnKeyListener(mKeyListener);
-        mHeaderView.setOnFocusChangeListener(mFocusListener);
-        mHeaderView.setFocusable(true);
-
-        mRadialTimePickerView.setOnValueSelectedListener(this);
-
-        mHourView.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                setCurrentItemShowing(HOUR_INDEX, true, true);
-                tryVibrate();
-            }
-        });
-        mMinuteView.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                setCurrentItemShowing(MINUTE_INDEX, true, true);
-                tryVibrate();
-            }
-        });
-    }
-
-    private void updateUI(int index) {
-        // Update RadialPicker values
-        updateRadialPicker(index);
-        // Enable or disable the AM/PM view.
-        updateHeaderAmPm();
-        // Update Hour and Minutes
-        updateHeaderHour(mInitialHourOfDay, true);
-        // Update time separator
-        updateHeaderSeparator();
-        // Update Minutes
-        updateHeaderMinute(mInitialMinute);
-        // Invalidate everything
-        mDelegator.invalidate();
-    }
-
-    private void updateRadialPicker(int index) {
-        mRadialTimePickerView.initialize(mInitialHourOfDay, mInitialMinute, mIs24HourView);
-        setCurrentItemShowing(index, false, true);
-    }
-
-    private int computeMaxWidthOfNumbers(int max) {
-        TextView tempView = new TextView(mContext);
-        tempView.setTextAppearance(mContext, R.style.TextAppearance_Material_TimePicker_TimeLabel);
-        ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
-                ViewGroup.LayoutParams.WRAP_CONTENT);
-        tempView.setLayoutParams(lp);
-        int maxWidth = 0;
-        for (int minutes = 0; minutes < max; minutes++) {
-            final String text = String.format("%02d", minutes);
-            tempView.setText(text);
-            tempView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
-            maxWidth = Math.max(maxWidth, tempView.getMeasuredWidth());
-        }
-        return maxWidth;
-    }
-
-    private void updateHeaderAmPm() {
-        if (mIs24HourView) {
-            mAmPmTextView.setVisibility(View.GONE);
-        } else {
-            mAmPmTextView.setVisibility(View.VISIBLE);
-            final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale,
-                    "hm");
-
-            boolean amPmOnLeft = bestDateTimePattern.startsWith("a");
-            if (TextUtils.getLayoutDirectionFromLocale(mCurrentLocale) ==
-                    View.LAYOUT_DIRECTION_RTL) {
-                amPmOnLeft = !amPmOnLeft;
-            }
-
-            RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams)
-                    mAmPmTextView.getLayoutParams();
-
-            if (amPmOnLeft) {
-                layoutParams.rightMargin = computeMaxWidthOfNumbers(12 /* for hours */);
-                layoutParams.removeRule(RelativeLayout.RIGHT_OF);
-                layoutParams.addRule(RelativeLayout.LEFT_OF, R.id.separator);
-            } else {
-                layoutParams.leftMargin = computeMaxWidthOfNumbers(60 /* for minutes */);
-                layoutParams.removeRule(RelativeLayout.LEFT_OF);
-                layoutParams.addRule(RelativeLayout.RIGHT_OF, R.id.separator);
-            }
-
-            updateAmPmDisplay(mInitialHourOfDay < 12 ? AM : PM);
-            mAmPmTextView.setOnClickListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    tryVibrate();
-                    int amOrPm = mRadialTimePickerView.getAmOrPm();
-                    if (amOrPm == AM) {
-                        amOrPm = PM;
-                    } else if (amOrPm == PM){
-                        amOrPm = AM;
+        // hour
+        mHourSpinner = (NumberPicker) delegator.findViewById(R.id.hour);
+        mHourSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
+            public void onValueChange(NumberPicker spinner, int oldVal, int newVal) {
+                updateInputState();
+                if (!is24HourView()) {
+                    if ((oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY) ||
+                            (oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1)) {
+                        mIsAm = !mIsAm;
+                        updateAmPmControl();
                     }
-                    updateAmPmDisplay(amOrPm);
-                    mRadialTimePickerView.setAmOrPm(amOrPm);
+                }
+                onTimeChanged();
+            }
+        });
+        mHourSpinnerInput = (EditText) mHourSpinner.findViewById(R.id.numberpicker_input);
+        mHourSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
+
+        // divider (only for the new widget style)
+        mDivider = (TextView) mDelegator.findViewById(R.id.divider);
+        if (mDivider != null) {
+            setDividerText();
+        }
+
+        // minute
+        mMinuteSpinner = (NumberPicker) mDelegator.findViewById(R.id.minute);
+        mMinuteSpinner.setMinValue(0);
+        mMinuteSpinner.setMaxValue(59);
+        mMinuteSpinner.setOnLongPressUpdateInterval(100);
+        mMinuteSpinner.setFormatter(NumberPicker.getTwoDigitFormatter());
+        mMinuteSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
+            public void onValueChange(NumberPicker spinner, int oldVal, int newVal) {
+                updateInputState();
+                int minValue = mMinuteSpinner.getMinValue();
+                int maxValue = mMinuteSpinner.getMaxValue();
+                if (oldVal == maxValue && newVal == minValue) {
+                    int newHour = mHourSpinner.getValue() + 1;
+                    if (!is24HourView() && newHour == HOURS_IN_HALF_DAY) {
+                        mIsAm = !mIsAm;
+                        updateAmPmControl();
+                    }
+                    mHourSpinner.setValue(newHour);
+                } else if (oldVal == minValue && newVal == maxValue) {
+                    int newHour = mHourSpinner.getValue() - 1;
+                    if (!is24HourView() && newHour == HOURS_IN_HALF_DAY - 1) {
+                        mIsAm = !mIsAm;
+                        updateAmPmControl();
+                    }
+                    mHourSpinner.setValue(newHour);
+                }
+                onTimeChanged();
+            }
+        });
+        mMinuteSpinnerInput = (EditText) mMinuteSpinner.findViewById(R.id.numberpicker_input);
+        mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
+
+        // Get the localized am/pm strings and use them in the spinner.
+        mAmPmStrings = getAmPmStrings(context);
+
+        // am/pm
+        final View amPmView = mDelegator.findViewById(R.id.amPm);
+        if (amPmView instanceof Button) {
+            mAmPmSpinner = null;
+            mAmPmSpinnerInput = null;
+            mAmPmButton = (Button) amPmView;
+            mAmPmButton.setOnClickListener(new View.OnClickListener() {
+                public void onClick(View button) {
+                    button.requestFocus();
+                    mIsAm = !mIsAm;
+                    updateAmPmControl();
+                    onTimeChanged();
                 }
             });
-        }
-    }
-
-    /**
-     * Set the current hour.
-     */
-    @Override
-    public void setCurrentHour(Integer currentHour) {
-        if (mInitialHourOfDay == currentHour) {
-            return;
-        }
-        mInitialHourOfDay = currentHour;
-        updateHeaderHour(currentHour, true /* accessibility announce */);
-        updateHeaderAmPm();
-        mRadialTimePickerView.setCurrentHour(currentHour);
-        mRadialTimePickerView.setAmOrPm(mInitialHourOfDay < 12 ? AM : PM);
-        mDelegator.invalidate();
-        onTimeChanged();
-    }
-
-    /**
-     * @return The current hour in the range (0-23).
-     */
-    @Override
-    public Integer getCurrentHour() {
-        int currentHour = mRadialTimePickerView.getCurrentHour();
-        if (mIs24HourView) {
-            return currentHour;
         } else {
-            switch(mRadialTimePickerView.getAmOrPm()) {
-                case PM:
-                    return (currentHour % HOURS_IN_HALF_DAY) + HOURS_IN_HALF_DAY;
-                case AM:
-                default:
-                    return currentHour % HOURS_IN_HALF_DAY;
+            mAmPmButton = null;
+            mAmPmSpinner = (NumberPicker) amPmView;
+            mAmPmSpinner.setMinValue(0);
+            mAmPmSpinner.setMaxValue(1);
+            mAmPmSpinner.setDisplayedValues(mAmPmStrings);
+            mAmPmSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
+                public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
+                    updateInputState();
+                    picker.requestFocus();
+                    mIsAm = !mIsAm;
+                    updateAmPmControl();
+                    onTimeChanged();
+                }
+            });
+            mAmPmSpinnerInput = (EditText) mAmPmSpinner.findViewById(R.id.numberpicker_input);
+            mAmPmSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_DONE);
+        }
+
+        if (isAmPmAtStart()) {
+            // Move the am/pm view to the beginning
+            ViewGroup amPmParent = (ViewGroup) delegator.findViewById(R.id.timePickerLayout);
+            amPmParent.removeView(amPmView);
+            amPmParent.addView(amPmView, 0);
+            // Swap layout margins if needed. They may be not symmetrical (Old Standard Theme
+            // for example and not for Holo Theme)
+            ViewGroup.MarginLayoutParams lp =
+                    (ViewGroup.MarginLayoutParams) amPmView.getLayoutParams();
+            final int startMargin = lp.getMarginStart();
+            final int endMargin = lp.getMarginEnd();
+            if (startMargin != endMargin) {
+                lp.setMarginStart(endMargin);
+                lp.setMarginEnd(startMargin);
+            }
+        }
+
+        getHourFormatData();
+
+        // update controls to initial state
+        updateHourControl();
+        updateMinuteControl();
+        updateAmPmControl();
+
+        // set to current time
+        setCurrentHour(mTempCalendar.get(Calendar.HOUR_OF_DAY));
+        setCurrentMinute(mTempCalendar.get(Calendar.MINUTE));
+
+        if (!isEnabled()) {
+            setEnabled(false);
+        }
+
+        // set the content descriptions
+        setContentDescriptions();
+
+        // If not explicitly specified this view is important for accessibility.
+        if (mDelegator.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
+            mDelegator.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+        }
+    }
+
+    private void getHourFormatData() {
+        final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale,
+                (mIs24HourView) ? "Hm" : "hm");
+        final int lengthPattern = bestDateTimePattern.length();
+        mHourWithTwoDigit = false;
+        char hourFormat = '\0';
+        // Check if the returned pattern is single or double 'H', 'h', 'K', 'k'. We also save
+        // the hour format that we found.
+        for (int i = 0; i < lengthPattern; i++) {
+            final char c = bestDateTimePattern.charAt(i);
+            if (c == 'H' || c == 'h' || c == 'K' || c == 'k') {
+                mHourFormat = c;
+                if (i + 1 < lengthPattern && c == bestDateTimePattern.charAt(i + 1)) {
+                    mHourWithTwoDigit = true;
+                }
+                break;
             }
         }
     }
 
+    private boolean isAmPmAtStart() {
+        final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale,
+                "hm" /* skeleton */);
+
+        return bestDateTimePattern.startsWith("a");
+    }
+
     /**
-     * Set the current minute (0-59).
+     * The time separator is defined in the Unicode CLDR and cannot be supposed to be ":".
+     *
+     * See http://unicode.org/cldr/trac/browser/trunk/common/main
+     *
+     * We pass the correct "skeleton" depending on 12 or 24 hours view and then extract the
+     * separator as the character which is just after the hour marker in the returned pattern.
      */
+    private void setDividerText() {
+        final String skeleton = (mIs24HourView) ? "Hm" : "hm";
+        final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale,
+                skeleton);
+        final String separatorText;
+        int hourIndex = bestDateTimePattern.lastIndexOf('H');
+        if (hourIndex == -1) {
+            hourIndex = bestDateTimePattern.lastIndexOf('h');
+        }
+        if (hourIndex == -1) {
+            // Default case
+            separatorText = ":";
+        } else {
+            int minuteIndex = bestDateTimePattern.indexOf('m', hourIndex + 1);
+            if  (minuteIndex == -1) {
+                separatorText = Character.toString(bestDateTimePattern.charAt(hourIndex + 1));
+            } else {
+                separatorText = bestDateTimePattern.substring(hourIndex + 1, minuteIndex);
+            }
+        }
+        mDivider.setText(separatorText);
+    }
+
     @Override
-    public void setCurrentMinute(Integer currentMinute) {
-        if (mInitialMinute == currentMinute) {
+    public void setCurrentHour(Integer currentHour) {
+        setCurrentHour(currentHour, true);
+    }
+
+    private void setCurrentHour(Integer currentHour, boolean notifyTimeChanged) {
+        // why was Integer used in the first place?
+        if (currentHour == null || currentHour == getCurrentHour()) {
             return;
         }
-        mInitialMinute = currentMinute;
-        updateHeaderMinute(currentMinute);
-        mRadialTimePickerView.setCurrentMinute(currentMinute);
-        mDelegator.invalidate();
+        if (!is24HourView()) {
+            // convert [0,23] ordinal to wall clock display
+            if (currentHour >= HOURS_IN_HALF_DAY) {
+                mIsAm = false;
+                if (currentHour > HOURS_IN_HALF_DAY) {
+                    currentHour = currentHour - HOURS_IN_HALF_DAY;
+                }
+            } else {
+                mIsAm = true;
+                if (currentHour == 0) {
+                    currentHour = HOURS_IN_HALF_DAY;
+                }
+            }
+            updateAmPmControl();
+        }
+        mHourSpinner.setValue(currentHour);
+        if (notifyTimeChanged) {
+            onTimeChanged();
+        }
+    }
+
+    @Override
+    public Integer getCurrentHour() {
+        int currentHour = mHourSpinner.getValue();
+        if (is24HourView()) {
+            return currentHour;
+        } else if (mIsAm) {
+            return currentHour % HOURS_IN_HALF_DAY;
+        } else {
+            return (currentHour % HOURS_IN_HALF_DAY) + HOURS_IN_HALF_DAY;
+        }
+    }
+
+    @Override
+    public void setCurrentMinute(Integer currentMinute) {
+        if (currentMinute == getCurrentMinute()) {
+            return;
+        }
+        mMinuteSpinner.setValue(currentMinute);
         onTimeChanged();
     }
 
-    /**
-     * @return The current minute.
-     */
     @Override
     public Integer getCurrentMinute() {
-        return mRadialTimePickerView.getCurrentMinute();
+        return mMinuteSpinner.getValue();
     }
 
-    /**
-     * Set whether in 24 hour or AM/PM mode.
-     *
-     * @param is24HourView True = 24 hour mode. False = AM/PM.
-     */
     @Override
     public void setIs24HourView(Boolean is24HourView) {
-        if (is24HourView == mIs24HourView) {
+        if (mIs24HourView == is24HourView) {
             return;
         }
+        // cache the current hour since spinner range changes and BEFORE changing mIs24HourView!!
+        int currentHour = getCurrentHour();
+        // Order is important here.
         mIs24HourView = is24HourView;
-        generateLegalTimesTree();
-        int hour = mRadialTimePickerView.getCurrentHour();
-        mInitialHourOfDay = hour;
-        updateHeaderHour(hour, false /* no accessibility announce */);
-        updateHeaderAmPm();
-        updateRadialPicker(mRadialTimePickerView.getCurrentItemShowing());
-        mDelegator.invalidate();
+        getHourFormatData();
+        updateHourControl();
+        // set value after spinner range is updated
+        setCurrentHour(currentHour, false);
+        updateMinuteControl();
+        updateAmPmControl();
     }
 
-    /**
-     * @return true if this is in 24 hour view else false.
-     */
     @Override
     public boolean is24HourView() {
         return mIs24HourView;
     }
 
     @Override
-    public void setOnTimeChangedListener(TimePicker.OnTimeChangedListener callback) {
-        mOnTimeChangedListener = callback;
+    public void setOnTimeChangedListener(TimePicker.OnTimeChangedListener onTimeChangedListener) {
+        mOnTimeChangedListener = onTimeChangedListener;
     }
 
     @Override
     public void setEnabled(boolean enabled) {
-        mHourView.setEnabled(enabled);
-        mMinuteView.setEnabled(enabled);
-        mAmPmTextView.setEnabled(enabled);
-        mRadialTimePickerView.setEnabled(enabled);
+        mMinuteSpinner.setEnabled(enabled);
+        if (mDivider != null) {
+            mDivider.setEnabled(enabled);
+        }
+        mHourSpinner.setEnabled(enabled);
+        if (mAmPmSpinner != null) {
+            mAmPmSpinner.setEnabled(enabled);
+        } else {
+            mAmPmButton.setEnabled(enabled);
+        }
         mIsEnabled = enabled;
     }
 
@@ -401,38 +386,24 @@
 
     @Override
     public int getBaseline() {
-        // does not support baseline alignment
-        return -1;
+        return mHourSpinner.getBaseline();
     }
 
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
-        updateUI(mRadialTimePickerView.getCurrentItemShowing());
+        setCurrentLocale(newConfig.locale);
     }
 
     @Override
     public Parcelable onSaveInstanceState(Parcelable superState) {
-        return new SavedState(superState, getCurrentHour(), getCurrentMinute(),
-                is24HourView(), inKbMode(), getTypedTimes(), getCurrentItemShowing());
+        return new SavedState(superState, getCurrentHour(), getCurrentMinute());
     }
 
     @Override
     public void onRestoreInstanceState(Parcelable state) {
         SavedState ss = (SavedState) state;
-        setInKbMode(ss.inKbMode());
-        setTypedTimes(ss.getTypesTimes());
-        initialize(ss.getHour(), ss.getMinute(), ss.is24HourMode(), ss.getCurrentItemShowing());
-        mRadialTimePickerView.invalidate();
-        if (mInKbMode) {
-            tryStartingKbMode(-1);
-            mHourView.invalidate();
-        }
-    }
-
-    @Override
-    public void setCurrentLocale(Locale locale) {
-        super.setCurrentLocale(locale);
-        mTempCalendar = Calendar.getInstance(locale);
+        setCurrentHour(ss.getHour());
+        setCurrentMinute(ss.getMinute());
     }
 
     @Override
@@ -451,9 +422,9 @@
         }
         mTempCalendar.set(Calendar.HOUR_OF_DAY, getCurrentHour());
         mTempCalendar.set(Calendar.MINUTE, getCurrentMinute());
-        String selectedDate = DateUtils.formatDateTime(mContext,
+        String selectedDateUtterance = DateUtils.formatDateTime(mContext,
                 mTempCalendar.getTimeInMillis(), flags);
-        event.getText().add(selectedDate);
+        event.getText().add(selectedDateUtterance);
     }
 
     @Override
@@ -466,48 +437,121 @@
         info.setClassName(TimePicker.class.getName());
     }
 
+    private void updateInputState() {
+        // Make sure that if the user changes the value and the IME is active
+        // for one of the inputs if this widget, the IME is closed. If the user
+        // changed the value via the IME and there is a next input the IME will
+        // be shown, otherwise the user chose another means of changing the
+        // value and having the IME up makes no sense.
+        InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
+        if (inputMethodManager != null) {
+            if (inputMethodManager.isActive(mHourSpinnerInput)) {
+                mHourSpinnerInput.clearFocus();
+                inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
+            } else if (inputMethodManager.isActive(mMinuteSpinnerInput)) {
+                mMinuteSpinnerInput.clearFocus();
+                inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
+            } else if (inputMethodManager.isActive(mAmPmSpinnerInput)) {
+                mAmPmSpinnerInput.clearFocus();
+                inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
+            }
+        }
+    }
+
+    private void updateAmPmControl() {
+        if (is24HourView()) {
+            if (mAmPmSpinner != null) {
+                mAmPmSpinner.setVisibility(View.GONE);
+            } else {
+                mAmPmButton.setVisibility(View.GONE);
+            }
+        } else {
+            int index = mIsAm ? Calendar.AM : Calendar.PM;
+            if (mAmPmSpinner != null) {
+                mAmPmSpinner.setValue(index);
+                mAmPmSpinner.setVisibility(View.VISIBLE);
+            } else {
+                mAmPmButton.setText(mAmPmStrings[index]);
+                mAmPmButton.setVisibility(View.VISIBLE);
+            }
+        }
+        mDelegator.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
+    }
+
     /**
-     * Set whether in keyboard mode or not.
+     * Sets the current locale.
      *
-     * @param inKbMode True means in keyboard mode.
+     * @param locale The current locale.
      */
-    private void setInKbMode(boolean inKbMode) {
-        mInKbMode = inKbMode;
+    @Override
+    public void setCurrentLocale(Locale locale) {
+        super.setCurrentLocale(locale);
+        mTempCalendar = Calendar.getInstance(locale);
     }
 
-    /**
-     * @return true if in keyboard mode
-     */
-    private boolean inKbMode() {
-        return mInKbMode;
-    }
-
-    private void setTypedTimes(ArrayList<Integer> typeTimes) {
-        mTypedTimes = typeTimes;
-    }
-
-    /**
-     * @return an array of typed times
-     */
-    private ArrayList<Integer> getTypedTimes() {
-        return mTypedTimes;
-    }
-
-    /**
-     * @return the index of the current item showing
-     */
-    private int getCurrentItemShowing() {
-        return mRadialTimePickerView.getCurrentItemShowing();
-    }
-
-    /**
-     * Propagate the time change
-     */
     private void onTimeChanged() {
         mDelegator.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
         if (mOnTimeChangedListener != null) {
-            mOnTimeChangedListener.onTimeChanged(mDelegator,
-                    getCurrentHour(), getCurrentMinute());
+            mOnTimeChangedListener.onTimeChanged(mDelegator, getCurrentHour(),
+                    getCurrentMinute());
+        }
+    }
+
+    private void updateHourControl() {
+        if (is24HourView()) {
+            // 'k' means 1-24 hour
+            if (mHourFormat == 'k') {
+                mHourSpinner.setMinValue(1);
+                mHourSpinner.setMaxValue(24);
+            } else {
+                mHourSpinner.setMinValue(0);
+                mHourSpinner.setMaxValue(23);
+            }
+        } else {
+            // 'K' means 0-11 hour
+            if (mHourFormat == 'K') {
+                mHourSpinner.setMinValue(0);
+                mHourSpinner.setMaxValue(11);
+            } else {
+                mHourSpinner.setMinValue(1);
+                mHourSpinner.setMaxValue(12);
+            }
+        }
+        mHourSpinner.setFormatter(mHourWithTwoDigit ? NumberPicker.getTwoDigitFormatter() : null);
+    }
+
+    private void updateMinuteControl() {
+        if (is24HourView()) {
+            mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_DONE);
+        } else {
+            mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
+        }
+    }
+
+    private void setContentDescriptions() {
+        // Minute
+        trySetContentDescription(mMinuteSpinner, R.id.increment,
+                R.string.time_picker_increment_minute_button);
+        trySetContentDescription(mMinuteSpinner, R.id.decrement,
+                R.string.time_picker_decrement_minute_button);
+        // Hour
+        trySetContentDescription(mHourSpinner, R.id.increment,
+                R.string.time_picker_increment_hour_button);
+        trySetContentDescription(mHourSpinner, R.id.decrement,
+                R.string.time_picker_decrement_hour_button);
+        // AM/PM
+        if (mAmPmSpinner != null) {
+            trySetContentDescription(mAmPmSpinner, R.id.increment,
+                    R.string.time_picker_increment_set_pm_button);
+            trySetContentDescription(mAmPmSpinner, R.id.decrement,
+                    R.string.time_picker_decrement_set_am_button);
+        }
+    }
+
+    private void trySetContentDescription(View root, int viewId, int contDescResId) {
+        View target = root.findViewById(viewId);
+        if (target != null) {
+            target.setContentDescription(mContext.getString(contDescResId));
         }
     }
 
@@ -515,34 +559,19 @@
      * Used to save / restore state of time picker
      */
     private static class SavedState extends View.BaseSavedState {
-
         private final int mHour;
         private final int mMinute;
-        private final boolean mIs24HourMode;
-        private final boolean mInKbMode;
-        private final ArrayList<Integer> mTypedTimes;
-        private final int mCurrentItemShowing;
 
-        private SavedState(Parcelable superState, int hour, int minute, boolean is24HourMode,
-                           boolean isKbMode, ArrayList<Integer> typedTimes,
-                           int currentItemShowing) {
+        private SavedState(Parcelable superState, int hour, int minute) {
             super(superState);
             mHour = hour;
             mMinute = minute;
-            mIs24HourMode = is24HourMode;
-            mInKbMode = isKbMode;
-            mTypedTimes = typedTimes;
-            mCurrentItemShowing = currentItemShowing;
         }
 
         private SavedState(Parcel in) {
             super(in);
             mHour = in.readInt();
             mMinute = in.readInt();
-            mIs24HourMode = (in.readInt() == 1);
-            mInKbMode = (in.readInt() == 1);
-            mTypedTimes = in.readArrayList(getClass().getClassLoader());
-            mCurrentItemShowing = in.readInt();
         }
 
         public int getHour() {
@@ -553,31 +582,11 @@
             return mMinute;
         }
 
-        public boolean is24HourMode() {
-            return mIs24HourMode;
-        }
-
-        public boolean inKbMode() {
-            return mInKbMode;
-        }
-
-        public ArrayList<Integer> getTypesTimes() {
-            return mTypedTimes;
-        }
-
-        public int getCurrentItemShowing() {
-            return mCurrentItemShowing;
-        }
-
         @Override
         public void writeToParcel(Parcel dest, int flags) {
             super.writeToParcel(dest, flags);
             dest.writeInt(mHour);
             dest.writeInt(mMinute);
-            dest.writeInt(mIs24HourMode ? 1 : 0);
-            dest.writeInt(mInKbMode ? 1 : 0);
-            dest.writeList(mTypedTimes);
-            dest.writeInt(mCurrentItemShowing);
         }
 
         @SuppressWarnings({"unused", "hiding"})
@@ -592,667 +601,11 @@
         };
     }
 
-    private void tryVibrate() {
-        mDelegator.performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);
+    public static String[] getAmPmStrings(Context context) {
+        String[] result = new String[2];
+        LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale);
+        result[0] = d.amPm[0].length() > 2 ? d.narrowAm : d.amPm[0];
+        result[1] = d.amPm[1].length() > 2 ? d.narrowPm : d.amPm[1];
+        return result;
     }
-
-    private void updateAmPmDisplay(int amOrPm) {
-        if (amOrPm == AM) {
-            mAmPmTextView.setText(mAmText);
-            mRadialTimePickerView.announceForAccessibility(mAmText);
-        } else if (amOrPm == PM){
-            mAmPmTextView.setText(mPmText);
-            mRadialTimePickerView.announceForAccessibility(mPmText);
-        } else {
-            mAmPmTextView.setText(mDoublePlaceholderText);
-        }
-    }
-
-    /**
-     * Called by the picker for updating the header display.
-     */
-    @Override
-    public void onValueSelected(int pickerIndex, int newValue, boolean autoAdvance) {
-        if (pickerIndex == HOUR_INDEX) {
-            updateHeaderHour(newValue, false);
-            String announcement = String.format("%d", newValue);
-            if (mAllowAutoAdvance && autoAdvance) {
-                setCurrentItemShowing(MINUTE_INDEX, true, false);
-                announcement += ". " + mSelectMinutes;
-            } else {
-                mRadialTimePickerView.setContentDescription(
-                        mHourPickerDescription + ": " + newValue);
-            }
-
-            mRadialTimePickerView.announceForAccessibility(announcement);
-        } else if (pickerIndex == MINUTE_INDEX){
-            updateHeaderMinute(newValue);
-            mRadialTimePickerView.setContentDescription(mMinutePickerDescription + ": " + newValue);
-        } else if (pickerIndex == AMPM_INDEX) {
-            updateAmPmDisplay(newValue);
-        } else if (pickerIndex == ENABLE_PICKER_INDEX) {
-            if (!isTypedTimeFullyLegal()) {
-                mTypedTimes.clear();
-            }
-            finishKbMode();
-        }
-    }
-
-    private void updateHeaderHour(int value, boolean announce) {
-        final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale,
-                (mIs24HourView) ? "Hm" : "hm");
-        final int lengthPattern = bestDateTimePattern.length();
-        boolean hourWithTwoDigit = false;
-        char hourFormat = '\0';
-        // Check if the returned pattern is single or double 'H', 'h', 'K', 'k'. We also save
-        // the hour format that we found.
-        for (int i = 0; i < lengthPattern; i++) {
-            final char c = bestDateTimePattern.charAt(i);
-            if (c == 'H' || c == 'h' || c == 'K' || c == 'k') {
-                hourFormat = c;
-                if (i + 1 < lengthPattern && c == bestDateTimePattern.charAt(i + 1)) {
-                    hourWithTwoDigit = true;
-                }
-                break;
-            }
-        }
-        final String format;
-        if (hourWithTwoDigit) {
-            format = "%02d";
-        } else {
-            format = "%d";
-        }
-        if (mIs24HourView) {
-            // 'k' means 1-24 hour
-            if (hourFormat == 'k' && value == 0) {
-                value = 24;
-            }
-        } else {
-            // 'K' means 0-11 hour
-            value = modulo12(value, hourFormat == 'K');
-        }
-        CharSequence text = String.format(format, value);
-        mHourView.setText(text);
-        if (announce) {
-            mRadialTimePickerView.announceForAccessibility(text);
-        }
-    }
-
-    private static int modulo12(int n, boolean startWithZero) {
-        int value = n % 12;
-        if (value == 0 && !startWithZero) {
-            value = 12;
-        }
-        return value;
-    }
-
-    /**
-     * The time separator is defined in the Unicode CLDR and cannot be supposed to be ":".
-     *
-     * See http://unicode.org/cldr/trac/browser/trunk/common/main
-     *
-     * We pass the correct "skeleton" depending on 12 or 24 hours view and then extract the
-     * separator as the character which is just after the hour marker in the returned pattern.
-     */
-    private void updateHeaderSeparator() {
-        final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale,
-                (mIs24HourView) ? "Hm" : "hm");
-        final String separatorText;
-        // See http://www.unicode.org/reports/tr35/tr35-dates.html for hour formats
-        final char[] hourFormats = {'H', 'h', 'K', 'k'};
-        int hIndex = lastIndexOfAny(bestDateTimePattern, hourFormats);
-        if (hIndex == -1) {
-            // Default case
-            separatorText = ":";
-        } else {
-            separatorText = Character.toString(bestDateTimePattern.charAt(hIndex + 1));
-        }
-        mSeparatorView.setText(separatorText);
-    }
-
-    static private int lastIndexOfAny(String str, char[] any) {
-        final int lengthAny = any.length;
-        if (lengthAny > 0) {
-            for (int i = str.length() - 1; i >= 0; i--) {
-                char c = str.charAt(i);
-                for (int j = 0; j < lengthAny; j++) {
-                    if (c == any[j]) {
-                        return i;
-                    }
-                }
-            }
-        }
-        return -1;
-    }
-
-    private void updateHeaderMinute(int value) {
-        if (value == 60) {
-            value = 0;
-        }
-        CharSequence text = String.format(mCurrentLocale, "%02d", value);
-        mRadialTimePickerView.announceForAccessibility(text);
-        mMinuteView.setText(text);
-    }
-
-    /**
-     * Show either Hours or Minutes.
-     */
-    private void setCurrentItemShowing(int index, boolean animateCircle, boolean announce) {
-        mRadialTimePickerView.setCurrentItemShowing(index, animateCircle);
-
-        if (index == HOUR_INDEX) {
-            int hours = mRadialTimePickerView.getCurrentHour();
-            if (!mIs24HourView) {
-                hours = hours % 12;
-            }
-            mRadialTimePickerView.setContentDescription(mHourPickerDescription + ": " + hours);
-            if (announce) {
-                mRadialTimePickerView.announceForAccessibility(mSelectHours);
-            }
-        } else {
-            int minutes = mRadialTimePickerView.getCurrentMinute();
-            mRadialTimePickerView.setContentDescription(mMinutePickerDescription + ": " + minutes);
-            if (announce) {
-                mRadialTimePickerView.announceForAccessibility(mSelectMinutes);
-            }
-        }
-
-        mHourView.setSelected(index == HOUR_INDEX);
-        mMinuteView.setSelected(index == MINUTE_INDEX);
-    }
-
-    /**
-     * For keyboard mode, processes key events.
-     *
-     * @param keyCode the pressed key.
-     *
-     * @return true if the key was successfully processed, false otherwise.
-     */
-    private boolean processKeyUp(int keyCode) {
-        if (keyCode == KeyEvent.KEYCODE_DEL) {
-            if (mInKbMode) {
-                if (!mTypedTimes.isEmpty()) {
-                    int deleted = deleteLastTypedKey();
-                    String deletedKeyStr;
-                    if (deleted == getAmOrPmKeyCode(AM)) {
-                        deletedKeyStr = mAmText;
-                    } else if (deleted == getAmOrPmKeyCode(PM)) {
-                        deletedKeyStr = mPmText;
-                    } else {
-                        deletedKeyStr = String.format("%d", getValFromKeyCode(deleted));
-                    }
-                    mRadialTimePickerView.announceForAccessibility(
-                            String.format(mDeletedKeyFormat, deletedKeyStr));
-                    updateDisplay(true);
-                }
-            }
-        } else if (keyCode == KeyEvent.KEYCODE_0 || keyCode == KeyEvent.KEYCODE_1
-                || keyCode == KeyEvent.KEYCODE_2 || keyCode == KeyEvent.KEYCODE_3
-                || keyCode == KeyEvent.KEYCODE_4 || keyCode == KeyEvent.KEYCODE_5
-                || keyCode == KeyEvent.KEYCODE_6 || keyCode == KeyEvent.KEYCODE_7
-                || keyCode == KeyEvent.KEYCODE_8 || keyCode == KeyEvent.KEYCODE_9
-                || (!mIs24HourView &&
-                (keyCode == getAmOrPmKeyCode(AM) || keyCode == getAmOrPmKeyCode(PM)))) {
-            if (!mInKbMode) {
-                if (mRadialTimePickerView == null) {
-                    // Something's wrong, because time picker should definitely not be null.
-                    Log.e(TAG, "Unable to initiate keyboard mode, TimePicker was null.");
-                    return true;
-                }
-                mTypedTimes.clear();
-                tryStartingKbMode(keyCode);
-                return true;
-            }
-            // We're already in keyboard mode.
-            if (addKeyIfLegal(keyCode)) {
-                updateDisplay(false);
-            }
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Try to start keyboard mode with the specified key.
-     *
-     * @param keyCode The key to use as the first press. Keyboard mode will not be started if the
-     * key is not legal to start with. Or, pass in -1 to get into keyboard mode without a starting
-     * key.
-     */
-    private void tryStartingKbMode(int keyCode) {
-        if (keyCode == -1 || addKeyIfLegal(keyCode)) {
-            mInKbMode = true;
-            onValidationChanged(false);
-            updateDisplay(false);
-            mRadialTimePickerView.setInputEnabled(false);
-        }
-    }
-
-    private boolean addKeyIfLegal(int keyCode) {
-        // If we're in 24hour mode, we'll need to check if the input is full. If in AM/PM mode,
-        // we'll need to see if AM/PM have been typed.
-        if ((mIs24HourView && mTypedTimes.size() == 4) ||
-                (!mIs24HourView && isTypedTimeFullyLegal())) {
-            return false;
-        }
-
-        mTypedTimes.add(keyCode);
-        if (!isTypedTimeLegalSoFar()) {
-            deleteLastTypedKey();
-            return false;
-        }
-
-        int val = getValFromKeyCode(keyCode);
-        mRadialTimePickerView.announceForAccessibility(String.format("%d", val));
-        // Automatically fill in 0's if AM or PM was legally entered.
-        if (isTypedTimeFullyLegal()) {
-            if (!mIs24HourView && mTypedTimes.size() <= 3) {
-                mTypedTimes.add(mTypedTimes.size() - 1, KeyEvent.KEYCODE_0);
-                mTypedTimes.add(mTypedTimes.size() - 1, KeyEvent.KEYCODE_0);
-            }
-            onValidationChanged(true);
-        }
-
-        return true;
-    }
-
-    /**
-     * Traverse the tree to see if the keys that have been typed so far are legal as is,
-     * or may become legal as more keys are typed (excluding backspace).
-     */
-    private boolean isTypedTimeLegalSoFar() {
-        Node node = mLegalTimesTree;
-        for (int keyCode : mTypedTimes) {
-            node = node.canReach(keyCode);
-            if (node == null) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Check if the time that has been typed so far is completely legal, as is.
-     */
-    private boolean isTypedTimeFullyLegal() {
-        if (mIs24HourView) {
-            // For 24-hour mode, the time is legal if the hours and minutes are each legal. Note:
-            // getEnteredTime() will ONLY call isTypedTimeFullyLegal() when NOT in 24hour mode.
-            int[] values = getEnteredTime(null);
-            return (values[0] >= 0 && values[1] >= 0 && values[1] < 60);
-        } else {
-            // For AM/PM mode, the time is legal if it contains an AM or PM, as those can only be
-            // legally added at specific times based on the tree's algorithm.
-            return (mTypedTimes.contains(getAmOrPmKeyCode(AM)) ||
-                    mTypedTimes.contains(getAmOrPmKeyCode(PM)));
-        }
-    }
-
-    private int deleteLastTypedKey() {
-        int deleted = mTypedTimes.remove(mTypedTimes.size() - 1);
-        if (!isTypedTimeFullyLegal()) {
-            onValidationChanged(false);
-        }
-        return deleted;
-    }
-
-    /**
-     * Get out of keyboard mode. If there is nothing in typedTimes, revert to TimePicker's time.
-     */
-    private void finishKbMode() {
-        mInKbMode = false;
-        if (!mTypedTimes.isEmpty()) {
-            int values[] = getEnteredTime(null);
-            mRadialTimePickerView.setCurrentHour(values[0]);
-            mRadialTimePickerView.setCurrentMinute(values[1]);
-            if (!mIs24HourView) {
-                mRadialTimePickerView.setAmOrPm(values[2]);
-            }
-            mTypedTimes.clear();
-        }
-        updateDisplay(false);
-        mRadialTimePickerView.setInputEnabled(true);
-    }
-
-    /**
-     * Update the hours, minutes, and AM/PM displays with the typed times. If the typedTimes is
-     * empty, either show an empty display (filled with the placeholder text), or update from the
-     * timepicker's values.
-     *
-     * @param allowEmptyDisplay if true, then if the typedTimes is empty, use the placeholder text.
-     * Otherwise, revert to the timepicker's values.
-     */
-    private void updateDisplay(boolean allowEmptyDisplay) {
-        if (!allowEmptyDisplay && mTypedTimes.isEmpty()) {
-            int hour = mRadialTimePickerView.getCurrentHour();
-            int minute = mRadialTimePickerView.getCurrentMinute();
-            updateHeaderHour(hour, true);
-            updateHeaderMinute(minute);
-            if (!mIs24HourView) {
-                updateAmPmDisplay(hour < 12 ? AM : PM);
-            }
-            setCurrentItemShowing(mRadialTimePickerView.getCurrentItemShowing(), true, true);
-            onValidationChanged(true);
-        } else {
-            boolean[] enteredZeros = {false, false};
-            int[] values = getEnteredTime(enteredZeros);
-            String hourFormat = enteredZeros[0] ? "%02d" : "%2d";
-            String minuteFormat = (enteredZeros[1]) ? "%02d" : "%2d";
-            String hourStr = (values[0] == -1) ? mDoublePlaceholderText :
-                    String.format(hourFormat, values[0]).replace(' ', mPlaceholderText);
-            String minuteStr = (values[1] == -1) ? mDoublePlaceholderText :
-                    String.format(minuteFormat, values[1]).replace(' ', mPlaceholderText);
-            mHourView.setText(hourStr);
-            mHourView.setSelected(false);
-            mMinuteView.setText(minuteStr);
-            mMinuteView.setSelected(false);
-            if (!mIs24HourView) {
-                updateAmPmDisplay(values[2]);
-            }
-        }
-    }
-
-    private int getValFromKeyCode(int keyCode) {
-        switch (keyCode) {
-            case KeyEvent.KEYCODE_0:
-                return 0;
-            case KeyEvent.KEYCODE_1:
-                return 1;
-            case KeyEvent.KEYCODE_2:
-                return 2;
-            case KeyEvent.KEYCODE_3:
-                return 3;
-            case KeyEvent.KEYCODE_4:
-                return 4;
-            case KeyEvent.KEYCODE_5:
-                return 5;
-            case KeyEvent.KEYCODE_6:
-                return 6;
-            case KeyEvent.KEYCODE_7:
-                return 7;
-            case KeyEvent.KEYCODE_8:
-                return 8;
-            case KeyEvent.KEYCODE_9:
-                return 9;
-            default:
-                return -1;
-        }
-    }
-
-    /**
-     * Get the currently-entered time, as integer values of the hours and minutes typed.
-     *
-     * @param enteredZeros A size-2 boolean array, which the caller should initialize, and which
-     * may then be used for the caller to know whether zeros had been explicitly entered as either
-     * hours of minutes. This is helpful for deciding whether to show the dashes, or actual 0's.
-     *
-     * @return A size-3 int array. The first value will be the hours, the second value will be the
-     * minutes, and the third will be either AM or PM.
-     */
-    private int[] getEnteredTime(boolean[] enteredZeros) {
-        int amOrPm = -1;
-        int startIndex = 1;
-        if (!mIs24HourView && isTypedTimeFullyLegal()) {
-            int keyCode = mTypedTimes.get(mTypedTimes.size() - 1);
-            if (keyCode == getAmOrPmKeyCode(AM)) {
-                amOrPm = AM;
-            } else if (keyCode == getAmOrPmKeyCode(PM)){
-                amOrPm = PM;
-            }
-            startIndex = 2;
-        }
-        int minute = -1;
-        int hour = -1;
-        for (int i = startIndex; i <= mTypedTimes.size(); i++) {
-            int val = getValFromKeyCode(mTypedTimes.get(mTypedTimes.size() - i));
-            if (i == startIndex) {
-                minute = val;
-            } else if (i == startIndex+1) {
-                minute += 10 * val;
-                if (enteredZeros != null && val == 0) {
-                    enteredZeros[1] = true;
-                }
-            } else if (i == startIndex+2) {
-                hour = val;
-            } else if (i == startIndex+3) {
-                hour += 10 * val;
-                if (enteredZeros != null && val == 0) {
-                    enteredZeros[0] = true;
-                }
-            }
-        }
-
-        return new int[] { hour, minute, amOrPm };
-    }
-
-    /**
-     * Get the keycode value for AM and PM in the current language.
-     */
-    private int getAmOrPmKeyCode(int amOrPm) {
-        // Cache the codes.
-        if (mAmKeyCode == -1 || mPmKeyCode == -1) {
-            // Find the first character in the AM/PM text that is unique.
-            KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
-            char amChar;
-            char pmChar;
-            for (int i = 0; i < Math.max(mAmText.length(), mPmText.length()); i++) {
-                amChar = mAmText.toLowerCase(mCurrentLocale).charAt(i);
-                pmChar = mPmText.toLowerCase(mCurrentLocale).charAt(i);
-                if (amChar != pmChar) {
-                    KeyEvent[] events = kcm.getEvents(new char[]{amChar, pmChar});
-                    // There should be 4 events: a down and up for both AM and PM.
-                    if (events != null && events.length == 4) {
-                        mAmKeyCode = events[0].getKeyCode();
-                        mPmKeyCode = events[2].getKeyCode();
-                    } else {
-                        Log.e(TAG, "Unable to find keycodes for AM and PM.");
-                    }
-                    break;
-                }
-            }
-        }
-        if (amOrPm == AM) {
-            return mAmKeyCode;
-        } else if (amOrPm == PM) {
-            return mPmKeyCode;
-        }
-
-        return -1;
-    }
-
-    /**
-     * Create a tree for deciding what keys can legally be typed.
-     */
-    private void generateLegalTimesTree() {
-        // Create a quick cache of numbers to their keycodes.
-        final int k0 = KeyEvent.KEYCODE_0;
-        final int k1 = KeyEvent.KEYCODE_1;
-        final int k2 = KeyEvent.KEYCODE_2;
-        final int k3 = KeyEvent.KEYCODE_3;
-        final int k4 = KeyEvent.KEYCODE_4;
-        final int k5 = KeyEvent.KEYCODE_5;
-        final int k6 = KeyEvent.KEYCODE_6;
-        final int k7 = KeyEvent.KEYCODE_7;
-        final int k8 = KeyEvent.KEYCODE_8;
-        final int k9 = KeyEvent.KEYCODE_9;
-
-        // The root of the tree doesn't contain any numbers.
-        mLegalTimesTree = new Node();
-        if (mIs24HourView) {
-            // We'll be re-using these nodes, so we'll save them.
-            Node minuteFirstDigit = new Node(k0, k1, k2, k3, k4, k5);
-            Node minuteSecondDigit = new Node(k0, k1, k2, k3, k4, k5, k6, k7, k8, k9);
-            // The first digit must be followed by the second digit.
-            minuteFirstDigit.addChild(minuteSecondDigit);
-
-            // The first digit may be 0-1.
-            Node firstDigit = new Node(k0, k1);
-            mLegalTimesTree.addChild(firstDigit);
-
-            // When the first digit is 0-1, the second digit may be 0-5.
-            Node secondDigit = new Node(k0, k1, k2, k3, k4, k5);
-            firstDigit.addChild(secondDigit);
-            // We may now be followed by the first minute digit. E.g. 00:09, 15:58.
-            secondDigit.addChild(minuteFirstDigit);
-
-            // When the first digit is 0-1, and the second digit is 0-5, the third digit may be 6-9.
-            Node thirdDigit = new Node(k6, k7, k8, k9);
-            // The time must now be finished. E.g. 0:55, 1:08.
-            secondDigit.addChild(thirdDigit);
-
-            // When the first digit is 0-1, the second digit may be 6-9.
-            secondDigit = new Node(k6, k7, k8, k9);
-            firstDigit.addChild(secondDigit);
-            // We must now be followed by the first minute digit. E.g. 06:50, 18:20.
-            secondDigit.addChild(minuteFirstDigit);
-
-            // The first digit may be 2.
-            firstDigit = new Node(k2);
-            mLegalTimesTree.addChild(firstDigit);
-
-            // When the first digit is 2, the second digit may be 0-3.
-            secondDigit = new Node(k0, k1, k2, k3);
-            firstDigit.addChild(secondDigit);
-            // We must now be followed by the first minute digit. E.g. 20:50, 23:09.
-            secondDigit.addChild(minuteFirstDigit);
-
-            // When the first digit is 2, the second digit may be 4-5.
-            secondDigit = new Node(k4, k5);
-            firstDigit.addChild(secondDigit);
-            // We must now be followd by the last minute digit. E.g. 2:40, 2:53.
-            secondDigit.addChild(minuteSecondDigit);
-
-            // The first digit may be 3-9.
-            firstDigit = new Node(k3, k4, k5, k6, k7, k8, k9);
-            mLegalTimesTree.addChild(firstDigit);
-            // We must now be followed by the first minute digit. E.g. 3:57, 8:12.
-            firstDigit.addChild(minuteFirstDigit);
-        } else {
-            // We'll need to use the AM/PM node a lot.
-            // Set up AM and PM to respond to "a" and "p".
-            Node ampm = new Node(getAmOrPmKeyCode(AM), getAmOrPmKeyCode(PM));
-
-            // The first hour digit may be 1.
-            Node firstDigit = new Node(k1);
-            mLegalTimesTree.addChild(firstDigit);
-            // We'll allow quick input of on-the-hour times. E.g. 1pm.
-            firstDigit.addChild(ampm);
-
-            // When the first digit is 1, the second digit may be 0-2.
-            Node secondDigit = new Node(k0, k1, k2);
-            firstDigit.addChild(secondDigit);
-            // Also for quick input of on-the-hour times. E.g. 10pm, 12am.
-            secondDigit.addChild(ampm);
-
-            // When the first digit is 1, and the second digit is 0-2, the third digit may be 0-5.
-            Node thirdDigit = new Node(k0, k1, k2, k3, k4, k5);
-            secondDigit.addChild(thirdDigit);
-            // The time may be finished now. E.g. 1:02pm, 1:25am.
-            thirdDigit.addChild(ampm);
-
-            // When the first digit is 1, the second digit is 0-2, and the third digit is 0-5,
-            // the fourth digit may be 0-9.
-            Node fourthDigit = new Node(k0, k1, k2, k3, k4, k5, k6, k7, k8, k9);
-            thirdDigit.addChild(fourthDigit);
-            // The time must be finished now. E.g. 10:49am, 12:40pm.
-            fourthDigit.addChild(ampm);
-
-            // When the first digit is 1, and the second digit is 0-2, the third digit may be 6-9.
-            thirdDigit = new Node(k6, k7, k8, k9);
-            secondDigit.addChild(thirdDigit);
-            // The time must be finished now. E.g. 1:08am, 1:26pm.
-            thirdDigit.addChild(ampm);
-
-            // When the first digit is 1, the second digit may be 3-5.
-            secondDigit = new Node(k3, k4, k5);
-            firstDigit.addChild(secondDigit);
-
-            // When the first digit is 1, and the second digit is 3-5, the third digit may be 0-9.
-            thirdDigit = new Node(k0, k1, k2, k3, k4, k5, k6, k7, k8, k9);
-            secondDigit.addChild(thirdDigit);
-            // The time must be finished now. E.g. 1:39am, 1:50pm.
-            thirdDigit.addChild(ampm);
-
-            // The hour digit may be 2-9.
-            firstDigit = new Node(k2, k3, k4, k5, k6, k7, k8, k9);
-            mLegalTimesTree.addChild(firstDigit);
-            // We'll allow quick input of on-the-hour-times. E.g. 2am, 5pm.
-            firstDigit.addChild(ampm);
-
-            // When the first digit is 2-9, the second digit may be 0-5.
-            secondDigit = new Node(k0, k1, k2, k3, k4, k5);
-            firstDigit.addChild(secondDigit);
-
-            // When the first digit is 2-9, and the second digit is 0-5, the third digit may be 0-9.
-            thirdDigit = new Node(k0, k1, k2, k3, k4, k5, k6, k7, k8, k9);
-            secondDigit.addChild(thirdDigit);
-            // The time must be finished now. E.g. 2:57am, 9:30pm.
-            thirdDigit.addChild(ampm);
-        }
-    }
-
-    /**
-     * Simple node class to be used for traversal to check for legal times.
-     * mLegalKeys represents the keys that can be typed to get to the node.
-     * mChildren are the children that can be reached from this node.
-     */
-    private class Node {
-        private int[] mLegalKeys;
-        private ArrayList<Node> mChildren;
-
-        public Node(int... legalKeys) {
-            mLegalKeys = legalKeys;
-            mChildren = new ArrayList<Node>();
-        }
-
-        public void addChild(Node child) {
-            mChildren.add(child);
-        }
-
-        public boolean containsKey(int key) {
-            for (int i = 0; i < mLegalKeys.length; i++) {
-                if (mLegalKeys[i] == key) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        public Node canReach(int key) {
-            if (mChildren == null) {
-                return null;
-            }
-            for (Node child : mChildren) {
-                if (child.containsKey(key)) {
-                    return child;
-                }
-            }
-            return null;
-        }
-    }
-
-    private final View.OnKeyListener mKeyListener = new View.OnKeyListener() {
-        @Override
-        public boolean onKey(View v, int keyCode, KeyEvent event) {
-            if (event.getAction() == KeyEvent.ACTION_UP) {
-                return processKeyUp(keyCode);
-            }
-            return false;
-        }
-    };
-
-    private final View.OnFocusChangeListener mFocusListener = new View.OnFocusChangeListener() {
-        @Override
-        public void onFocusChange(View v, boolean hasFocus) {
-            if (!hasFocus && mInKbMode && isTypedTimeFullyLegal()) {
-                finishKbMode();
-
-                if (mOnTimeChangedListener != null) {
-                    mOnTimeChangedListener.onTimeChanged(mDelegator,
-                            mRadialTimePickerView.getCurrentHour(),
-                            mRadialTimePickerView.getCurrentMinute());
-                }
-            }
-        }
-    };
 }
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index 1ce19ce..d8e39e3 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -66,7 +66,9 @@
  *     <li><em>A navigation button.</em> This may be an Up arrow, navigation menu toggle, close,
  *     collapse, done or another glyph of the app's choosing. This button should always be used
  *     to access other navigational destinations within the container of the Toolbar and
- *     its signified content or otherwise leave the current context signified by the Toolbar.</li>
+ *     its signified content or otherwise leave the current context signified by the Toolbar.
+ *     The navigation button is vertically aligned within the Toolbar's
+ *     {@link android.R.styleable#View_minHeight minimum height}, if set.</li>
  *     <li><em>A branded logo image.</em> This may extend to the height of the bar and can be
  *     arbitrarily wide.</li>
  *     <li><em>A title and subtitle.</em> The title should be a signpost for the Toolbar's current
@@ -82,8 +84,9 @@
  *     <li><em>An {@link ActionMenuView action menu}.</em> The menu of actions will pin to the
  *     end of the Toolbar offering a few
  *     <a href="http://developer.android.com/design/patterns/actionbar.html#ActionButtons">
- *         frequent, important or typical</a> actions along with an optional overflow menu for
- *         additional actions.</li>
+ *     frequent, important or typical</a> actions along with an optional overflow menu for
+ *     additional actions. Action buttons are vertically aligned within the Toolbar's
+ *     {@link android.R.styleable#View_minHeight minimum height}, if set.</li>
  * </ul>
  * </p>
  *
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 5267811..0bc1a8d 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -16,13 +16,20 @@
 
 package com.android.internal.app;
 
+import android.app.Activity;
+import android.content.ComponentName;
 import android.content.Intent;
+import android.content.IntentSender;
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.util.Log;
+import android.util.Slog;
 
 public class ChooserActivity extends ResolverActivity {
+    private static final String TAG = "ChooserActivity";
+
     private Bundle mReplacementExtras;
+    private IntentSender mChosenComponentSender;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -60,11 +67,14 @@
                 initialIntents[i] = in;
             }
         }
+        mChosenComponentSender = intent.getParcelableExtra(
+                Intent.EXTRA_CHOSEN_COMPONENT_INTENT_SENDER);
         setSafeForwardingMode(true);
         super.onCreate(savedInstanceState, target, title, defaultTitleRes, initialIntents,
                 null, false);
     }
 
+    @Override
     public Intent getReplacementIntent(String packageName, Intent defIntent) {
         if (mReplacementExtras != null) {
             final Bundle replExtras = mReplacementExtras.getBundle(packageName);
@@ -77,6 +87,22 @@
         return defIntent;
     }
 
+    @Override
+    public void onActivityStarted(Intent intent) {
+        if (mChosenComponentSender != null) {
+            final ComponentName target = intent.getComponent();
+            if (target != null) {
+                final Intent fillIn = new Intent().putExtra(Intent.EXTRA_CHOSEN_COMPONENT, target);
+                try {
+                    mChosenComponentSender.sendIntent(this, Activity.RESULT_OK, fillIn, null, null);
+                } catch (IntentSender.SendIntentException e) {
+                    Slog.e(TAG, "Unable to launch supplied IntentSender to report "
+                            + "the chosen component: " + e);
+                }
+            }
+        }
+    }
+
     private void modifyTargetIntent(Intent in) {
         final String action = in.getAction();
         if (Intent.ACTION_SEND.equals(action) ||
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 0062e2d..ccffa19 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -74,6 +74,9 @@
 import java.util.Map;
 import java.util.Set;
 
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+
 /**
  * This activity is displayed when the system attempts to start an Intent for
  * which there is more than one matching activity, allowing the user to decide
@@ -269,6 +272,9 @@
             mListView = (ListView) findViewById(R.id.resolver_list);
             mListView.setVisibility(View.GONE);
         }
+        // Prevent the Resolver window from becoming the top fullscreen window and thus from taking
+        // control of the system bars.
+        getWindow().clearFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR);
 
         final ResolverDrawerLayout rdl = (ResolverDrawerLayout) findViewById(R.id.contentPanel);
         if (rdl != null) {
@@ -638,10 +644,12 @@
     public void safelyStartActivity(Intent intent) {
         if (!mSafeForwardingMode) {
             startActivity(intent);
+            onActivityStarted(intent);
             return;
         }
         try {
             startActivityAsCaller(intent, null, UserHandle.USER_NULL);
+            onActivityStarted(intent);
         } catch (RuntimeException e) {
             String launchedFromPackage;
             try {
@@ -656,6 +664,10 @@
         }
     }
 
+    public void onActivityStarted(Intent intent) {
+        // Do nothing
+    }
+
     void showAppDetails(ResolveInfo ri) {
         Intent in = new Intent().setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                 .setData(Uri.fromParts("package", ri.activityInfo.packageName, null))
@@ -819,6 +831,11 @@
                         }
                         ResolveInfo ri = new ResolveInfo();
                         ri.activityInfo = ai;
+                        UserManager userManager =
+                                (UserManager) getSystemService(Context.USER_SERVICE);
+                        if (userManager.isManagedProfile()) {
+                            ri.noResourceId = true;
+                        }
                         if (ii instanceof LabeledIntent) {
                             LabeledIntent li = (LabeledIntent)ii;
                             ri.resolvePackageName = li.getSourcePackage();
diff --git a/core/java/com/android/internal/util/MemInfoReader.java b/core/java/com/android/internal/util/MemInfoReader.java
index 5f240f7..1dd9464 100644
--- a/core/java/com/android/internal/util/MemInfoReader.java
+++ b/core/java/com/android/internal/util/MemInfoReader.java
@@ -34,40 +34,65 @@
         }
     }
 
+    /**
+     * Total amount of RAM available to the kernel.
+     */
     public long getTotalSize() {
         return mInfos[Debug.MEMINFO_TOTAL] * 1024;
     }
 
+    /**
+     * Amount of RAM that is not being used for anything.
+     */
     public long getFreeSize() {
         return mInfos[Debug.MEMINFO_FREE] * 1024;
     }
 
+    /**
+     * Amount of RAM that the kernel is being used for caches, not counting caches
+     * that are mapped in to processes.
+     */
     public long getCachedSize() {
-        return mInfos[Debug.MEMINFO_CACHED] * 1024;
+        return getCachedSizeKb() * 1024;
     }
 
+    /**
+     * Amount of RAM that is in use by the kernel for actual allocations.
+     */
+    public long getKernelUsedSize() {
+        return getKernelUsedSizeKb() * 1024;
+    }
+
+    /**
+     * Total amount of RAM available to the kernel.
+     */
     public long getTotalSizeKb() {
         return mInfos[Debug.MEMINFO_TOTAL];
     }
 
+    /**
+     * Amount of RAM that is not being used for anything.
+     */
     public long getFreeSizeKb() {
         return mInfos[Debug.MEMINFO_FREE];
     }
 
+    /**
+     * Amount of RAM that the kernel is being used for caches, not counting caches
+     * that are mapped in to processes.
+     */
     public long getCachedSizeKb() {
-        return mInfos[Debug.MEMINFO_CACHED];
+        return mInfos[Debug.MEMINFO_BUFFERS]
+                + mInfos[Debug.MEMINFO_CACHED] - mInfos[Debug.MEMINFO_MAPPED];
     }
 
-    public long getBuffersSizeKb() {
-        return mInfos[Debug.MEMINFO_BUFFERS];
-    }
-
-    public long getShmemSizeKb() {
-        return mInfos[Debug.MEMINFO_SHMEM];
-    }
-
-    public long getSlabSizeKb() {
-        return mInfos[Debug.MEMINFO_SLAB];
+    /**
+     * Amount of RAM that is in use by the kernel for actual allocations.
+     */
+    public long getKernelUsedSizeKb() {
+        return mInfos[Debug.MEMINFO_SHMEM] + mInfos[Debug.MEMINFO_SLAB]
+                + mInfos[Debug.MEMINFO_VM_ALLOC_USED] + mInfos[Debug.MEMINFO_PAGE_TABLES]
+                + mInfos[Debug.MEMINFO_KERNEL_STACK];
     }
 
     public long getSwapTotalSizeKb() {
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index 40f58e9..99bb1ac 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -54,6 +54,7 @@
     private final boolean mOverflowOnly;
     private final int mPopupMaxWidth;
     private final int mPopupStyleAttr;
+    private final int mPopupStyleRes;
 
     private View mAnchorView;
     private ListPopupWindow mPopup;
@@ -73,21 +74,27 @@
     private int mDropDownGravity = Gravity.NO_GRAVITY;
 
     public MenuPopupHelper(Context context, MenuBuilder menu) {
-        this(context, menu, null, false, com.android.internal.R.attr.popupMenuStyle);
+        this(context, menu, null, false, com.android.internal.R.attr.popupMenuStyle, 0);
     }
 
     public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView) {
-        this(context, menu, anchorView, false, com.android.internal.R.attr.popupMenuStyle);
+        this(context, menu, anchorView, false, com.android.internal.R.attr.popupMenuStyle, 0);
     }
 
     public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView,
             boolean overflowOnly, int popupStyleAttr) {
+        this(context, menu, anchorView, overflowOnly, popupStyleAttr, 0);
+    }
+
+    public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView,
+            boolean overflowOnly, int popupStyleAttr, int popupStyleRes) {
         mContext = context;
         mInflater = LayoutInflater.from(context);
         mMenu = menu;
         mAdapter = new MenuAdapter(mMenu);
         mOverflowOnly = overflowOnly;
         mPopupStyleAttr = popupStyleAttr;
+        mPopupStyleRes = popupStyleRes;
 
         final Resources res = context.getResources();
         mPopupMaxWidth = Math.max(res.getDisplayMetrics().widthPixels / 2,
@@ -122,7 +129,7 @@
     }
 
     public boolean tryShow() {
-        mPopup = new ListPopupWindow(mContext, null, mPopupStyleAttr);
+        mPopup = new ListPopupWindow(mContext, null, mPopupStyleAttr, mPopupStyleRes);
         mPopup.setOnDismissListener(this);
         mPopup.setOnItemClickListener(this);
         mPopup.setAdapter(mAdapter);
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 91e5330..b9a85e5 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -19,8 +19,6 @@
 import android.animation.LayoutTransition;
 import android.app.ActionBar;
 import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
@@ -29,9 +27,7 @@
 import android.text.Layout;
 import android.text.TextUtils;
 import android.util.AttributeSet;
-import android.util.TypedValue;
 import android.view.CollapsibleActionView;
-import android.view.ContextThemeWrapper;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.Menu;
@@ -111,10 +107,10 @@
     private int mProgressBarPadding;
     private int mItemPadding;
 
-    private int mTitleStyleRes;
-    private int mSubtitleStyleRes;
-    private int mProgressStyle;
-    private int mIndeterminateProgressStyle;
+    private final int mTitleStyleRes;
+    private final int mSubtitleStyleRes;
+    private final int mProgressStyle;
+    private final int mIndeterminateProgressStyle;
 
     private boolean mUserTitle;
     private boolean mIncludeTabs;
diff --git a/core/java/com/android/internal/widget/ExploreByTouchHelper.java b/core/java/com/android/internal/widget/ExploreByTouchHelper.java
index 11c4ca1..4689179 100644
--- a/core/java/com/android/internal/widget/ExploreByTouchHelper.java
+++ b/core/java/com/android/internal/widget/ExploreByTouchHelper.java
@@ -54,6 +54,10 @@
     /** Default class name used for virtual views. */
     private static final String DEFAULT_CLASS_NAME = View.class.getName();
 
+    /** Default bounds used to determine if the client didn't set any. */
+    private static final Rect INVALID_PARENT_BOUNDS = new Rect(
+            Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE);
+
     // Temporary, reusable data structures.
     private final Rect mTempScreenRect = new Rect();
     private final Rect mTempParentRect = new Rect();
@@ -372,6 +376,7 @@
         // Ensure the client has good defaults.
         node.setEnabled(true);
         node.setClassName(DEFAULT_CLASS_NAME);
+        node.setBoundsInParent(INVALID_PARENT_BOUNDS);
 
         // Allow the client to populate the node.
         onPopulateNodeForVirtualView(virtualViewId, node);
@@ -383,7 +388,7 @@
         }
 
         node.getBoundsInParent(mTempParentRect);
-        if (mTempParentRect.isEmpty()) {
+        if (mTempParentRect.equals(INVALID_PARENT_BOUNDS)) {
             throw new RuntimeException("Callbacks must set parent bounds in "
                     + "populateNodeForVirtualViewId()");
         }
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 8ea28ec..a578b5d 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -315,7 +315,8 @@
     }
 
     SkBitmap decodingBitmap;
-    if (!decoder->decode(stream, &decodingBitmap, prefColorType, decodeMode)) {
+    if (decoder->decode(stream, &decodingBitmap, prefColorType, decodeMode)
+                != SkImageDecoder::kSuccess) {
         return nullObjectReturn("decoder->decode returned false");
     }
 
@@ -478,7 +479,7 @@
 
     NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
 
-    jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
+    int descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
 
     struct stat fdStat;
     if (fstat(descriptor, &fdStat) == -1) {
@@ -486,16 +487,27 @@
         return nullObjectReturn("fstat return -1");
     }
 
-    // Restore the descriptor's offset on exiting this function.
+    // Restore the descriptor's offset on exiting this function. Even though
+    // we dup the descriptor, both the original and dup refer to the same open
+    // file description and changes to the file offset in one impact the other.
     AutoFDSeek autoRestore(descriptor);
 
-    FILE* file = fdopen(descriptor, "r");
+    // Duplicate the descriptor here to prevent leaking memory. A leak occurs
+    // if we only close the file descriptor and not the file object it is used to
+    // create.  If we don't explicitly clean up the file (which in turn closes the
+    // descriptor) the buffers allocated internally by fseek will be leaked.
+    int dupDescriptor = dup(descriptor);
+
+    FILE* file = fdopen(dupDescriptor, "r");
     if (file == NULL) {
+        // cleanup the duplicated descriptor since it will not be closed when the
+        // file is cleaned up (fclose).
+        close(dupDescriptor);
         return nullObjectReturn("Could not open file");
     }
 
     SkAutoTUnref<SkFILEStream> fileStream(new SkFILEStream(file,
-                         SkFILEStream::kCallerRetains_Ownership));
+                         SkFILEStream::kCallerPasses_Ownership));
 
     // Use a buffered stream. Although an SkFILEStream can be rewound, this
     // ensures that SkImageDecoder::Factory never rewinds beyond the
diff --git a/core/jni/android/graphics/Matrix.cpp b/core/jni/android/graphics/Matrix.cpp
index cbd20e9..01ab699 100644
--- a/core/jni/android/graphics/Matrix.cpp
+++ b/core/jni/android/graphics/Matrix.cpp
@@ -308,46 +308,47 @@
 static JNINativeMethod methods[] = {
     {"finalizer", "(J)V", (void*) SkMatrixGlue::finalizer},
     {"native_create","(J)J", (void*) SkMatrixGlue::create},
-    {"native_isIdentity","(J)Z", (void*) SkMatrixGlue::isIdentity},
-    {"native_isAffine","(J)Z", (void*) SkMatrixGlue::isAffine},
-    {"native_rectStaysRect","(J)Z", (void*) SkMatrixGlue::rectStaysRect},
-    {"native_reset","(J)V", (void*) SkMatrixGlue::reset},
-    {"native_set","(JJ)V", (void*) SkMatrixGlue::set},
-    {"native_setTranslate","(JFF)V", (void*) SkMatrixGlue::setTranslate},
-    {"native_setScale","(JFFFF)V", (void*) SkMatrixGlue::setScale__FFFF},
-    {"native_setScale","(JFF)V", (void*) SkMatrixGlue::setScale__FF},
-    {"native_setRotate","(JFFF)V", (void*) SkMatrixGlue::setRotate__FFF},
-    {"native_setRotate","(JF)V", (void*) SkMatrixGlue::setRotate__F},
-    {"native_setSinCos","(JFFFF)V", (void*) SkMatrixGlue::setSinCos__FFFF},
-    {"native_setSinCos","(JFF)V", (void*) SkMatrixGlue::setSinCos__FF},
-    {"native_setSkew","(JFFFF)V", (void*) SkMatrixGlue::setSkew__FFFF},
-    {"native_setSkew","(JFF)V", (void*) SkMatrixGlue::setSkew__FF},
-    {"native_setConcat","(JJJ)V", (void*) SkMatrixGlue::setConcat},
-    {"native_preTranslate","(JFF)V", (void*) SkMatrixGlue::preTranslate},
-    {"native_preScale","(JFFFF)V", (void*) SkMatrixGlue::preScale__FFFF},
-    {"native_preScale","(JFF)V", (void*) SkMatrixGlue::preScale__FF},
-    {"native_preRotate","(JFFF)V", (void*) SkMatrixGlue::preRotate__FFF},
-    {"native_preRotate","(JF)V", (void*) SkMatrixGlue::preRotate__F},
-    {"native_preSkew","(JFFFF)V", (void*) SkMatrixGlue::preSkew__FFFF},
-    {"native_preSkew","(JFF)V", (void*) SkMatrixGlue::preSkew__FF},
-    {"native_preConcat","(JJ)V", (void*) SkMatrixGlue::preConcat},
-    {"native_postTranslate","(JFF)V", (void*) SkMatrixGlue::postTranslate},
-    {"native_postScale","(JFFFF)V", (void*) SkMatrixGlue::postScale__FFFF},
-    {"native_postScale","(JFF)V", (void*) SkMatrixGlue::postScale__FF},
-    {"native_postRotate","(JFFF)V", (void*) SkMatrixGlue::postRotate__FFF},
-    {"native_postRotate","(JF)V", (void*) SkMatrixGlue::postRotate__F},
-    {"native_postSkew","(JFFFF)V", (void*) SkMatrixGlue::postSkew__FFFF},
-    {"native_postSkew","(JFF)V", (void*) SkMatrixGlue::postSkew__FF},
-    {"native_postConcat","(JJ)V", (void*) SkMatrixGlue::postConcat},
-    {"native_setRectToRect","(JLandroid/graphics/RectF;Landroid/graphics/RectF;I)Z", (void*) SkMatrixGlue::setRectToRect},
-    {"native_setPolyToPoly","(J[FI[FII)Z", (void*) SkMatrixGlue::setPolyToPoly},
-    {"native_invert","(JJ)Z", (void*) SkMatrixGlue::invert},
-    {"native_mapPoints","(J[FI[FIIZ)V", (void*) SkMatrixGlue::mapPoints},
-    {"native_mapRect","(JLandroid/graphics/RectF;Landroid/graphics/RectF;)Z", (void*) SkMatrixGlue::mapRect__RectFRectF},
-    {"native_mapRadius","(JF)F", (void*) SkMatrixGlue::mapRadius},
-    {"native_getValues","(J[F)V", (void*) SkMatrixGlue::getValues},
-    {"native_setValues","(J[F)V", (void*) SkMatrixGlue::setValues},
-    {"native_equals", "(JJ)Z", (void*) SkMatrixGlue::equals}
+
+    {"native_isIdentity","!(J)Z", (void*) SkMatrixGlue::isIdentity},
+    {"native_isAffine","!(J)Z", (void*) SkMatrixGlue::isAffine},
+    {"native_rectStaysRect","!(J)Z", (void*) SkMatrixGlue::rectStaysRect},
+    {"native_reset","!(J)V", (void*) SkMatrixGlue::reset},
+    {"native_set","!(JJ)V", (void*) SkMatrixGlue::set},
+    {"native_setTranslate","!(JFF)V", (void*) SkMatrixGlue::setTranslate},
+    {"native_setScale","!(JFFFF)V", (void*) SkMatrixGlue::setScale__FFFF},
+    {"native_setScale","!(JFF)V", (void*) SkMatrixGlue::setScale__FF},
+    {"native_setRotate","!(JFFF)V", (void*) SkMatrixGlue::setRotate__FFF},
+    {"native_setRotate","!(JF)V", (void*) SkMatrixGlue::setRotate__F},
+    {"native_setSinCos","!(JFFFF)V", (void*) SkMatrixGlue::setSinCos__FFFF},
+    {"native_setSinCos","!(JFF)V", (void*) SkMatrixGlue::setSinCos__FF},
+    {"native_setSkew","!(JFFFF)V", (void*) SkMatrixGlue::setSkew__FFFF},
+    {"native_setSkew","!(JFF)V", (void*) SkMatrixGlue::setSkew__FF},
+    {"native_setConcat","!(JJJ)V", (void*) SkMatrixGlue::setConcat},
+    {"native_preTranslate","!(JFF)V", (void*) SkMatrixGlue::preTranslate},
+    {"native_preScale","!(JFFFF)V", (void*) SkMatrixGlue::preScale__FFFF},
+    {"native_preScale","!(JFF)V", (void*) SkMatrixGlue::preScale__FF},
+    {"native_preRotate","!(JFFF)V", (void*) SkMatrixGlue::preRotate__FFF},
+    {"native_preRotate","!(JF)V", (void*) SkMatrixGlue::preRotate__F},
+    {"native_preSkew","!(JFFFF)V", (void*) SkMatrixGlue::preSkew__FFFF},
+    {"native_preSkew","!(JFF)V", (void*) SkMatrixGlue::preSkew__FF},
+    {"native_preConcat","!(JJ)V", (void*) SkMatrixGlue::preConcat},
+    {"native_postTranslate","!(JFF)V", (void*) SkMatrixGlue::postTranslate},
+    {"native_postScale","!(JFFFF)V", (void*) SkMatrixGlue::postScale__FFFF},
+    {"native_postScale","!(JFF)V", (void*) SkMatrixGlue::postScale__FF},
+    {"native_postRotate","!(JFFF)V", (void*) SkMatrixGlue::postRotate__FFF},
+    {"native_postRotate","!(JF)V", (void*) SkMatrixGlue::postRotate__F},
+    {"native_postSkew","!(JFFFF)V", (void*) SkMatrixGlue::postSkew__FFFF},
+    {"native_postSkew","!(JFF)V", (void*) SkMatrixGlue::postSkew__FF},
+    {"native_postConcat","!(JJ)V", (void*) SkMatrixGlue::postConcat},
+    {"native_setRectToRect","!(JLandroid/graphics/RectF;Landroid/graphics/RectF;I)Z", (void*) SkMatrixGlue::setRectToRect},
+    {"native_setPolyToPoly","!(J[FI[FII)Z", (void*) SkMatrixGlue::setPolyToPoly},
+    {"native_invert","!(JJ)Z", (void*) SkMatrixGlue::invert},
+    {"native_mapPoints","!(J[FI[FIIZ)V", (void*) SkMatrixGlue::mapPoints},
+    {"native_mapRect","!(JLandroid/graphics/RectF;Landroid/graphics/RectF;)Z", (void*) SkMatrixGlue::mapRect__RectFRectF},
+    {"native_mapRadius","!(JF)F", (void*) SkMatrixGlue::mapRadius},
+    {"native_getValues","!(J[F)V", (void*) SkMatrixGlue::getValues},
+    {"native_setValues","!(J[F)V", (void*) SkMatrixGlue::setValues},
+    {"native_equals", "!(JJ)Z", (void*) SkMatrixGlue::equals}
 };
 
 static jfieldID sNativeInstanceField;
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 4bb31fc..6b02326 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -939,58 +939,60 @@
     {"finalizer", "(J)V", (void*) PaintGlue::finalizer},
     {"native_init","()J", (void*) PaintGlue::init},
     {"native_initWithPaint","(J)J", (void*) PaintGlue::initWithPaint},
-    {"native_reset","(J)V", (void*) PaintGlue::reset},
-    {"native_set","(JJ)V", (void*) PaintGlue::assign},
-    {"getFlags","()I", (void*) PaintGlue::getFlags},
-    {"setFlags","(I)V", (void*) PaintGlue::setFlags},
-    {"getHinting","()I", (void*) PaintGlue::getHinting},
-    {"setHinting","(I)V", (void*) PaintGlue::setHinting},
-    {"setAntiAlias","(Z)V", (void*) PaintGlue::setAntiAlias},
-    {"setSubpixelText","(Z)V", (void*) PaintGlue::setSubpixelText},
-    {"setLinearText","(Z)V", (void*) PaintGlue::setLinearText},
-    {"setUnderlineText","(Z)V", (void*) PaintGlue::setUnderlineText},
-    {"setStrikeThruText","(Z)V", (void*) PaintGlue::setStrikeThruText},
-    {"setFakeBoldText","(Z)V", (void*) PaintGlue::setFakeBoldText},
-    {"setFilterBitmap","(Z)V", (void*) PaintGlue::setFilterBitmap},
-    {"setDither","(Z)V", (void*) PaintGlue::setDither},
-    {"native_getStyle","(J)I", (void*) PaintGlue::getStyle},
-    {"native_setStyle","(JI)V", (void*) PaintGlue::setStyle},
-    {"getColor","()I", (void*) PaintGlue::getColor},
-    {"setColor","(I)V", (void*) PaintGlue::setColor},
-    {"getAlpha","()I", (void*) PaintGlue::getAlpha},
-    {"setAlpha","(I)V", (void*) PaintGlue::setAlpha},
-    {"getStrokeWidth","()F", (void*) PaintGlue::getStrokeWidth},
-    {"setStrokeWidth","(F)V", (void*) PaintGlue::setStrokeWidth},
-    {"getStrokeMiter","()F", (void*) PaintGlue::getStrokeMiter},
-    {"setStrokeMiter","(F)V", (void*) PaintGlue::setStrokeMiter},
-    {"native_getStrokeCap","(J)I", (void*) PaintGlue::getStrokeCap},
-    {"native_setStrokeCap","(JI)V", (void*) PaintGlue::setStrokeCap},
-    {"native_getStrokeJoin","(J)I", (void*) PaintGlue::getStrokeJoin},
-    {"native_setStrokeJoin","(JI)V", (void*) PaintGlue::setStrokeJoin},
-    {"native_getFillPath","(JJJ)Z", (void*) PaintGlue::getFillPath},
-    {"native_setShader","(JJ)J", (void*) PaintGlue::setShader},
-    {"native_setColorFilter","(JJ)J", (void*) PaintGlue::setColorFilter},
-    {"native_setXfermode","(JJ)J", (void*) PaintGlue::setXfermode},
-    {"native_setPathEffect","(JJ)J", (void*) PaintGlue::setPathEffect},
-    {"native_setMaskFilter","(JJ)J", (void*) PaintGlue::setMaskFilter},
-    {"native_setTypeface","(JJ)J", (void*) PaintGlue::setTypeface},
-    {"native_setRasterizer","(JJ)J", (void*) PaintGlue::setRasterizer},
-    {"native_getTextAlign","(J)I", (void*) PaintGlue::getTextAlign},
-    {"native_setTextAlign","(JI)V", (void*) PaintGlue::setTextAlign},
-    {"native_setTextLocale","(JLjava/lang/String;)V", (void*) PaintGlue::setTextLocale},
-    {"isElegantTextHeight","()Z", (void*) PaintGlue::isElegantTextHeight},
-    {"setElegantTextHeight","(Z)V", (void*) PaintGlue::setElegantTextHeight},
-    {"getTextSize","()F", (void*) PaintGlue::getTextSize},
-    {"setTextSize","(F)V", (void*) PaintGlue::setTextSize},
-    {"getTextScaleX","()F", (void*) PaintGlue::getTextScaleX},
-    {"setTextScaleX","(F)V", (void*) PaintGlue::setTextScaleX},
-    {"getTextSkewX","()F", (void*) PaintGlue::getTextSkewX},
-    {"setTextSkewX","(F)V", (void*) PaintGlue::setTextSkewX},
-    {"native_getLetterSpacing","(J)F", (void*) PaintGlue::getLetterSpacing},
-    {"native_setLetterSpacing","(JF)V", (void*) PaintGlue::setLetterSpacing},
+
+    {"native_reset","!(J)V", (void*) PaintGlue::reset},
+    {"native_set","!(JJ)V", (void*) PaintGlue::assign},
+    {"getFlags","!()I", (void*) PaintGlue::getFlags},
+    {"setFlags","!(I)V", (void*) PaintGlue::setFlags},
+    {"getHinting","!()I", (void*) PaintGlue::getHinting},
+    {"setHinting","!(I)V", (void*) PaintGlue::setHinting},
+    {"setAntiAlias","!(Z)V", (void*) PaintGlue::setAntiAlias},
+    {"setSubpixelText","!(Z)V", (void*) PaintGlue::setSubpixelText},
+    {"setLinearText","!(Z)V", (void*) PaintGlue::setLinearText},
+    {"setUnderlineText","!(Z)V", (void*) PaintGlue::setUnderlineText},
+    {"setStrikeThruText","!(Z)V", (void*) PaintGlue::setStrikeThruText},
+    {"setFakeBoldText","!(Z)V", (void*) PaintGlue::setFakeBoldText},
+    {"setFilterBitmap","!(Z)V", (void*) PaintGlue::setFilterBitmap},
+    {"setDither","!(Z)V", (void*) PaintGlue::setDither},
+    {"native_getStyle","!(J)I", (void*) PaintGlue::getStyle},
+    {"native_setStyle","!(JI)V", (void*) PaintGlue::setStyle},
+    {"getColor","!()I", (void*) PaintGlue::getColor},
+    {"setColor","!(I)V", (void*) PaintGlue::setColor},
+    {"getAlpha","!()I", (void*) PaintGlue::getAlpha},
+    {"setAlpha","!(I)V", (void*) PaintGlue::setAlpha},
+    {"getStrokeWidth","!()F", (void*) PaintGlue::getStrokeWidth},
+    {"setStrokeWidth","!(F)V", (void*) PaintGlue::setStrokeWidth},
+    {"getStrokeMiter","!()F", (void*) PaintGlue::getStrokeMiter},
+    {"setStrokeMiter","!(F)V", (void*) PaintGlue::setStrokeMiter},
+    {"native_getStrokeCap","!(J)I", (void*) PaintGlue::getStrokeCap},
+    {"native_setStrokeCap","!(JI)V", (void*) PaintGlue::setStrokeCap},
+    {"native_getStrokeJoin","!(J)I", (void*) PaintGlue::getStrokeJoin},
+    {"native_setStrokeJoin","!(JI)V", (void*) PaintGlue::setStrokeJoin},
+    {"native_getFillPath","!(JJJ)Z", (void*) PaintGlue::getFillPath},
+    {"native_setShader","!(JJ)J", (void*) PaintGlue::setShader},
+    {"native_setColorFilter","!(JJ)J", (void*) PaintGlue::setColorFilter},
+    {"native_setXfermode","!(JJ)J", (void*) PaintGlue::setXfermode},
+    {"native_setPathEffect","!(JJ)J", (void*) PaintGlue::setPathEffect},
+    {"native_setMaskFilter","!(JJ)J", (void*) PaintGlue::setMaskFilter},
+    {"native_setTypeface","!(JJ)J", (void*) PaintGlue::setTypeface},
+    {"native_setRasterizer","!(JJ)J", (void*) PaintGlue::setRasterizer},
+    {"native_getTextAlign","!(J)I", (void*) PaintGlue::getTextAlign},
+    {"native_setTextAlign","!(JI)V", (void*) PaintGlue::setTextAlign},
+    {"native_setTextLocale","!(JLjava/lang/String;)V", (void*) PaintGlue::setTextLocale},
+    {"isElegantTextHeight","!()Z", (void*) PaintGlue::isElegantTextHeight},
+    {"setElegantTextHeight","!(Z)V", (void*) PaintGlue::setElegantTextHeight},
+    {"getTextSize","!()F", (void*) PaintGlue::getTextSize},
+    {"setTextSize","!(F)V", (void*) PaintGlue::setTextSize},
+    {"getTextScaleX","!()F", (void*) PaintGlue::getTextScaleX},
+    {"setTextScaleX","!(F)V", (void*) PaintGlue::setTextScaleX},
+    {"getTextSkewX","!()F", (void*) PaintGlue::getTextSkewX},
+    {"setTextSkewX","!(F)V", (void*) PaintGlue::setTextSkewX},
+    {"native_getLetterSpacing","!(J)F", (void*) PaintGlue::getLetterSpacing},
+    {"native_setLetterSpacing","!(JF)V", (void*) PaintGlue::setLetterSpacing},
     {"native_setFontFeatureSettings","(JLjava/lang/String;)V", (void*) PaintGlue::setFontFeatureSettings},
-    {"ascent","()F", (void*) PaintGlue::ascent},
-    {"descent","()F", (void*) PaintGlue::descent},
+    {"ascent","!()F", (void*) PaintGlue::ascent},
+    {"descent","!()F", (void*) PaintGlue::descent},
+
     {"getFontMetrics", "(Landroid/graphics/Paint$FontMetrics;)F", (void*)PaintGlue::getFontMetrics},
     {"getFontMetricsInt", "(Landroid/graphics/Paint$FontMetricsInt;)I", (void*)PaintGlue::getFontMetricsInt},
     {"native_measureText","([CIII)F", (void*) PaintGlue::measureText_CIII},
@@ -1014,8 +1016,9 @@
                                         (void*) PaintGlue::getStringBounds },
     {"nativeGetCharArrayBounds", "(JJ[CIIILandroid/graphics/Rect;)V",
                                     (void*) PaintGlue::getCharArrayBounds },
-    {"native_setShadowLayer", "(JFFFI)V", (void*)PaintGlue::setShadowLayer},
-    {"native_hasShadowLayer", "(J)Z", (void*)PaintGlue::hasShadowLayer}
+
+    {"native_setShadowLayer", "!(JFFFI)V", (void*)PaintGlue::setShadowLayer},
+    {"native_hasShadowLayer", "!(J)Z", (void*)PaintGlue::hasShadowLayer}
 };
 
 static jfieldID req_fieldID(jfieldID id) {
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index f8bab24..4cff56d 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -48,13 +48,20 @@
     jfieldID    canDisableShutterSound;
     jfieldID    face_rect;
     jfieldID    face_score;
+    jfieldID    face_id;
+    jfieldID    face_left_eye;
+    jfieldID    face_right_eye;
+    jfieldID    face_mouth;
     jfieldID    rect_left;
     jfieldID    rect_top;
     jfieldID    rect_right;
     jfieldID    rect_bottom;
+    jfieldID    point_x;
+    jfieldID    point_y;
     jmethodID   post_event;
     jmethodID   rect_constructor;
     jmethodID   face_constructor;
+    jmethodID   point_constructor;
 };
 
 static fields_t fields;
@@ -88,6 +95,7 @@
     sp<Camera>  mCamera;                // strong reference to native object
     jclass      mFaceClass;  // strong reference to Face class
     jclass      mRectClass;  // strong reference to Rect class
+    jclass      mPointClass;  // strong reference to Point class
     Mutex       mLock;
 
     /*
@@ -144,6 +152,9 @@
     jclass rectClazz = env->FindClass("android/graphics/Rect");
     mRectClass = (jclass) env->NewGlobalRef(rectClazz);
 
+    jclass pointClazz = env->FindClass("android/graphics/Point");
+    mPointClass = (jclass) env->NewGlobalRef(pointClazz);
+
     mManualBufferMode = false;
     mManualCameraCallbackSet = false;
 }
@@ -170,6 +181,10 @@
         env->DeleteGlobalRef(mRectClass);
         mRectClass = NULL;
     }
+    if (mPointClass != NULL) {
+        env->DeleteGlobalRef(mPointClass);
+        mPointClass = NULL;
+    }
     clearCallbackBuffers_l(env);
     mCamera.clear();
 }
@@ -356,6 +371,33 @@
         env->SetObjectField(face, fields.face_rect, rect);
         env->SetIntField(face, fields.face_score, metadata->faces[i].score);
 
+        bool optionalFields = metadata->faces[i].id != 0
+            && metadata->faces[i].left_eye[0] != -2000 && metadata->faces[i].left_eye[1] != -2000
+            && metadata->faces[i].right_eye[0] != -2000 && metadata->faces[i].right_eye[1] != -2000
+            && metadata->faces[i].mouth[0] != -2000 && metadata->faces[i].mouth[1] != -2000;
+        if (optionalFields) {
+            int32_t id = metadata->faces[i].id;
+            env->SetIntField(face, fields.face_id, id);
+
+            jobject leftEye = env->NewObject(mPointClass, fields.point_constructor);
+            env->SetIntField(leftEye, fields.point_x, metadata->faces[i].left_eye[0]);
+            env->SetIntField(leftEye, fields.point_y, metadata->faces[i].left_eye[1]);
+            env->SetObjectField(face, fields.face_left_eye, leftEye);
+            env->DeleteLocalRef(leftEye);
+
+            jobject rightEye = env->NewObject(mPointClass, fields.point_constructor);
+            env->SetIntField(rightEye, fields.point_x, metadata->faces[i].right_eye[0]);
+            env->SetIntField(rightEye, fields.point_y, metadata->faces[i].right_eye[1]);
+            env->SetObjectField(face, fields.face_right_eye, rightEye);
+            env->DeleteLocalRef(rightEye);
+
+            jobject mouth = env->NewObject(mPointClass, fields.point_constructor);
+            env->SetIntField(mouth, fields.point_x, metadata->faces[i].mouth[0]);
+            env->SetIntField(mouth, fields.point_y, metadata->faces[i].mouth[1]);
+            env->SetObjectField(face, fields.face_mouth, mouth);
+            env->DeleteLocalRef(mouth);
+        }
+
         env->DeleteLocalRef(face);
         env->DeleteLocalRef(rect);
     }
@@ -1020,11 +1062,17 @@
         { "android/hardware/Camera$CameraInfo", "canDisableShutterSound",   "Z",
           &fields.canDisableShutterSound },
         { "android/hardware/Camera$Face", "rect", "Landroid/graphics/Rect;", &fields.face_rect },
+        { "android/hardware/Camera$Face", "leftEye", "Landroid/graphics/Point;", &fields.face_left_eye},
+        { "android/hardware/Camera$Face", "rightEye", "Landroid/graphics/Point;", &fields.face_right_eye},
+        { "android/hardware/Camera$Face", "mouth", "Landroid/graphics/Point;", &fields.face_mouth},
         { "android/hardware/Camera$Face", "score", "I", &fields.face_score },
+        { "android/hardware/Camera$Face", "id", "I", &fields.face_id},
         { "android/graphics/Rect", "left", "I", &fields.rect_left },
         { "android/graphics/Rect", "top", "I", &fields.rect_top },
         { "android/graphics/Rect", "right", "I", &fields.rect_right },
         { "android/graphics/Rect", "bottom", "I", &fields.rect_bottom },
+        { "android/graphics/Point", "x", "I", &fields.point_x},
+        { "android/graphics/Point", "y", "I", &fields.point_y},
     };
 
     if (find_fields(env, fields_to_find, NELEM(fields_to_find)) < 0)
@@ -1052,6 +1100,13 @@
         return -1;
     }
 
+    clazz = env->FindClass("android/graphics/Point");
+    fields.point_constructor = env->GetMethodID(clazz, "<init>", "()V");
+    if (fields.point_constructor == NULL) {
+        ALOGE("Can't find android/graphics/Point()");
+        return -1;
+    }
+
     // Register native functions
     return AndroidRuntime::registerNativeMethods(env, "android/hardware/Camera",
                                               camMethods, NELEM(camMethods));
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 7b3528b..9ec9993 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -552,6 +552,10 @@
     MEMINFO_SWAP_TOTAL,
     MEMINFO_SWAP_FREE,
     MEMINFO_ZRAM_TOTAL,
+    MEMINFO_MAPPED,
+    MEMINFO_VMALLOC_USED,
+    MEMINFO_PAGE_TABLES,
+    MEMINFO_KERNEL_STACK,
     MEMINFO_COUNT
 };
 
@@ -590,6 +594,11 @@
             "Slab:",
             "SwapTotal:",
             "SwapFree:",
+            "ZRam:",
+            "Mapped:",
+            "VmallocUsed:",
+            "PageTables:",
+            "KernelStack:",
             NULL
     };
     static const int tagsLen[] = {
@@ -601,12 +610,17 @@
             5,
             10,
             9,
+            5,
+            7,
+            12,
+            11,
+            12,
             0
     };
-    long mem[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+    long mem[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 
     char* p = buffer;
-    while (*p && numFound < 8) {
+    while (*p && numFound < 13) {
         int i = 0;
         while (tags[i]) {
             if (strncmp(p, tags[i], tagsLen[i]) == 0) {
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 050037e..621df72 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -483,68 +483,68 @@
     { "nOutput",               "(J)V",  (void*) android_view_RenderNode_output },
     { "nGetDebugSize",         "(J)I",  (void*) android_view_RenderNode_getDebugSize },
 
-    { "nSetLayerType",         "(JI)Z",  (void*) android_view_RenderNode_setLayerType },
-    { "nSetLayerPaint",        "(JJ)Z",  (void*) android_view_RenderNode_setLayerPaint },
-    { "nSetStaticMatrix",      "(JJ)Z",  (void*) android_view_RenderNode_setStaticMatrix },
-    { "nSetAnimationMatrix",   "(JJ)Z",  (void*) android_view_RenderNode_setAnimationMatrix },
-    { "nSetClipToBounds",      "(JZ)Z",  (void*) android_view_RenderNode_setClipToBounds },
-    { "nSetClipBounds",        "(JIIII)Z", (void*) android_view_RenderNode_setClipBounds },
-    { "nSetClipBoundsEmpty",   "(J)Z",   (void*) android_view_RenderNode_setClipBoundsEmpty },
-    { "nSetProjectBackwards",  "(JZ)Z",  (void*) android_view_RenderNode_setProjectBackwards },
-    { "nSetProjectionReceiver","(JZ)Z",  (void*) android_view_RenderNode_setProjectionReceiver },
+    { "nSetLayerType",         "!(JI)Z",  (void*) android_view_RenderNode_setLayerType },
+    { "nSetLayerPaint",        "!(JJ)Z",  (void*) android_view_RenderNode_setLayerPaint },
+    { "nSetStaticMatrix",      "!(JJ)Z",  (void*) android_view_RenderNode_setStaticMatrix },
+    { "nSetAnimationMatrix",   "!(JJ)Z",  (void*) android_view_RenderNode_setAnimationMatrix },
+    { "nSetClipToBounds",      "!(JZ)Z",  (void*) android_view_RenderNode_setClipToBounds },
+    { "nSetClipBounds",        "!(JIIII)Z", (void*) android_view_RenderNode_setClipBounds },
+    { "nSetClipBoundsEmpty",   "!(J)Z",   (void*) android_view_RenderNode_setClipBoundsEmpty },
+    { "nSetProjectBackwards",  "!(JZ)Z",  (void*) android_view_RenderNode_setProjectBackwards },
+    { "nSetProjectionReceiver","!(JZ)Z",  (void*) android_view_RenderNode_setProjectionReceiver },
 
     { "nSetOutlineRoundRect",  "(JIIIIFF)Z", (void*) android_view_RenderNode_setOutlineRoundRect },
     { "nSetOutlineConvexPath", "(JJF)Z", (void*) android_view_RenderNode_setOutlineConvexPath },
     { "nSetOutlineEmpty",      "(J)Z",   (void*) android_view_RenderNode_setOutlineEmpty },
     { "nSetOutlineNone",       "(J)Z",   (void*) android_view_RenderNode_setOutlineNone },
-    { "nHasShadow",            "(J)Z",   (void*) android_view_RenderNode_hasShadow },
-    { "nSetClipToOutline",     "(JZ)Z",  (void*) android_view_RenderNode_setClipToOutline },
+    { "nHasShadow",            "!(J)Z",   (void*) android_view_RenderNode_hasShadow },
+    { "nSetClipToOutline",     "!(JZ)Z",  (void*) android_view_RenderNode_setClipToOutline },
     { "nSetRevealClip",        "(JZFFF)Z", (void*) android_view_RenderNode_setRevealClip },
 
-    { "nSetAlpha",             "(JF)Z",  (void*) android_view_RenderNode_setAlpha },
-    { "nSetHasOverlappingRendering", "(JZ)Z",
+    { "nSetAlpha",             "!(JF)Z",  (void*) android_view_RenderNode_setAlpha },
+    { "nSetHasOverlappingRendering", "!(JZ)Z",
             (void*) android_view_RenderNode_setHasOverlappingRendering },
-    { "nSetElevation",         "(JF)Z",  (void*) android_view_RenderNode_setElevation },
-    { "nSetTranslationX",      "(JF)Z",  (void*) android_view_RenderNode_setTranslationX },
-    { "nSetTranslationY",      "(JF)Z",  (void*) android_view_RenderNode_setTranslationY },
-    { "nSetTranslationZ",      "(JF)Z",  (void*) android_view_RenderNode_setTranslationZ },
-    { "nSetRotation",          "(JF)Z",  (void*) android_view_RenderNode_setRotation },
-    { "nSetRotationX",         "(JF)Z",  (void*) android_view_RenderNode_setRotationX },
-    { "nSetRotationY",         "(JF)Z",  (void*) android_view_RenderNode_setRotationY },
-    { "nSetScaleX",            "(JF)Z",  (void*) android_view_RenderNode_setScaleX },
-    { "nSetScaleY",            "(JF)Z",  (void*) android_view_RenderNode_setScaleY },
-    { "nSetPivotX",            "(JF)Z",  (void*) android_view_RenderNode_setPivotX },
-    { "nSetPivotY",            "(JF)Z",  (void*) android_view_RenderNode_setPivotY },
-    { "nSetCameraDistance",    "(JF)Z",  (void*) android_view_RenderNode_setCameraDistance },
-    { "nSetLeft",              "(JI)Z",  (void*) android_view_RenderNode_setLeft },
-    { "nSetTop",               "(JI)Z",  (void*) android_view_RenderNode_setTop },
-    { "nSetRight",             "(JI)Z",  (void*) android_view_RenderNode_setRight },
-    { "nSetBottom",            "(JI)Z",  (void*) android_view_RenderNode_setBottom },
-    { "nSetLeftTopRightBottom","(JIIII)Z", (void*) android_view_RenderNode_setLeftTopRightBottom },
-    { "nOffsetLeftAndRight",   "(JI)Z",  (void*) android_view_RenderNode_offsetLeftAndRight },
-    { "nOffsetTopAndBottom",   "(JI)Z",  (void*) android_view_RenderNode_offsetTopAndBottom },
+    { "nSetElevation",         "!(JF)Z",  (void*) android_view_RenderNode_setElevation },
+    { "nSetTranslationX",      "!(JF)Z",  (void*) android_view_RenderNode_setTranslationX },
+    { "nSetTranslationY",      "!(JF)Z",  (void*) android_view_RenderNode_setTranslationY },
+    { "nSetTranslationZ",      "!(JF)Z",  (void*) android_view_RenderNode_setTranslationZ },
+    { "nSetRotation",          "!(JF)Z",  (void*) android_view_RenderNode_setRotation },
+    { "nSetRotationX",         "!(JF)Z",  (void*) android_view_RenderNode_setRotationX },
+    { "nSetRotationY",         "!(JF)Z",  (void*) android_view_RenderNode_setRotationY },
+    { "nSetScaleX",            "!(JF)Z",  (void*) android_view_RenderNode_setScaleX },
+    { "nSetScaleY",            "!(JF)Z",  (void*) android_view_RenderNode_setScaleY },
+    { "nSetPivotX",            "!(JF)Z",  (void*) android_view_RenderNode_setPivotX },
+    { "nSetPivotY",            "!(JF)Z",  (void*) android_view_RenderNode_setPivotY },
+    { "nSetCameraDistance",    "!(JF)Z",  (void*) android_view_RenderNode_setCameraDistance },
+    { "nSetLeft",              "!(JI)Z",  (void*) android_view_RenderNode_setLeft },
+    { "nSetTop",               "!(JI)Z",  (void*) android_view_RenderNode_setTop },
+    { "nSetRight",             "!(JI)Z",  (void*) android_view_RenderNode_setRight },
+    { "nSetBottom",            "!(JI)Z",  (void*) android_view_RenderNode_setBottom },
+    { "nSetLeftTopRightBottom","!(JIIII)Z", (void*) android_view_RenderNode_setLeftTopRightBottom },
+    { "nOffsetLeftAndRight",   "!(JI)Z",  (void*) android_view_RenderNode_offsetLeftAndRight },
+    { "nOffsetTopAndBottom",   "!(JI)Z",  (void*) android_view_RenderNode_offsetTopAndBottom },
 
-    { "nHasOverlappingRendering", "(J)Z",  (void*) android_view_RenderNode_hasOverlappingRendering },
-    { "nGetClipToOutline",        "(J)Z",  (void*) android_view_RenderNode_getClipToOutline },
-    { "nGetAlpha",                "(J)F",  (void*) android_view_RenderNode_getAlpha },
-    { "nGetCameraDistance",       "(J)F",  (void*) android_view_RenderNode_getCameraDistance },
-    { "nGetScaleX",               "(J)F",  (void*) android_view_RenderNode_getScaleX },
-    { "nGetScaleY",               "(J)F",  (void*) android_view_RenderNode_getScaleY },
-    { "nGetElevation",            "(J)F",  (void*) android_view_RenderNode_getElevation },
-    { "nGetTranslationX",         "(J)F",  (void*) android_view_RenderNode_getTranslationX },
-    { "nGetTranslationY",         "(J)F",  (void*) android_view_RenderNode_getTranslationY },
-    { "nGetTranslationZ",         "(J)F",  (void*) android_view_RenderNode_getTranslationZ },
-    { "nGetRotation",             "(J)F",  (void*) android_view_RenderNode_getRotation },
-    { "nGetRotationX",            "(J)F",  (void*) android_view_RenderNode_getRotationX },
-    { "nGetRotationY",            "(J)F",  (void*) android_view_RenderNode_getRotationY },
-    { "nIsPivotExplicitlySet",    "(J)Z",  (void*) android_view_RenderNode_isPivotExplicitlySet },
-    { "nHasIdentityMatrix",       "(J)Z",  (void*) android_view_RenderNode_hasIdentityMatrix },
+    { "nHasOverlappingRendering", "!(J)Z",  (void*) android_view_RenderNode_hasOverlappingRendering },
+    { "nGetClipToOutline",        "!(J)Z",  (void*) android_view_RenderNode_getClipToOutline },
+    { "nGetAlpha",                "!(J)F",  (void*) android_view_RenderNode_getAlpha },
+    { "nGetCameraDistance",       "!(J)F",  (void*) android_view_RenderNode_getCameraDistance },
+    { "nGetScaleX",               "!(J)F",  (void*) android_view_RenderNode_getScaleX },
+    { "nGetScaleY",               "!(J)F",  (void*) android_view_RenderNode_getScaleY },
+    { "nGetElevation",            "!(J)F",  (void*) android_view_RenderNode_getElevation },
+    { "nGetTranslationX",         "!(J)F",  (void*) android_view_RenderNode_getTranslationX },
+    { "nGetTranslationY",         "!(J)F",  (void*) android_view_RenderNode_getTranslationY },
+    { "nGetTranslationZ",         "!(J)F",  (void*) android_view_RenderNode_getTranslationZ },
+    { "nGetRotation",             "!(J)F",  (void*) android_view_RenderNode_getRotation },
+    { "nGetRotationX",            "!(J)F",  (void*) android_view_RenderNode_getRotationX },
+    { "nGetRotationY",            "!(J)F",  (void*) android_view_RenderNode_getRotationY },
+    { "nIsPivotExplicitlySet",    "!(J)Z",  (void*) android_view_RenderNode_isPivotExplicitlySet },
+    { "nHasIdentityMatrix",       "!(J)Z",  (void*) android_view_RenderNode_hasIdentityMatrix },
 
-    { "nGetTransformMatrix",       "(JJ)V", (void*) android_view_RenderNode_getTransformMatrix },
-    { "nGetInverseTransformMatrix","(JJ)V", (void*) android_view_RenderNode_getInverseTransformMatrix },
+    { "nGetTransformMatrix",       "!(JJ)V", (void*) android_view_RenderNode_getTransformMatrix },
+    { "nGetInverseTransformMatrix","!(JJ)V", (void*) android_view_RenderNode_getInverseTransformMatrix },
 
-    { "nGetPivotX",                "(J)F",  (void*) android_view_RenderNode_getPivotX },
-    { "nGetPivotY",                "(J)F",  (void*) android_view_RenderNode_getPivotY },
+    { "nGetPivotX",                "!(J)F",  (void*) android_view_RenderNode_getPivotX },
+    { "nGetPivotY",                "!(J)F",  (void*) android_view_RenderNode_getPivotY },
 
     { "nAddAnimator",              "(JJ)V", (void*) android_view_RenderNode_addAnimator },
     { "nEndAllAnimators",          "(J)V", (void*) android_view_RenderNode_endAllAnimators },
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index b3d9890..a0b2ca8 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -374,6 +374,7 @@
     ContextFactory factory;
     RenderProxy* proxy = new RenderProxy(false, rootNode, &factory);
     proxy->loadSystemProperties();
+    proxy->setSwapBehavior(kSwap_discardBuffer);
     proxy->initialize(surface);
     // Shadows can't be used via this interface, so just set the light source
     // to all 0s. (and width & height are unused, TODO remove them)
diff --git a/core/res/res/drawable-hdpi/ic_text_dot.png b/core/res/res/drawable-hdpi/ic_text_dot.png
deleted file mode 100644
index fa69c69..0000000
--- a/core/res/res/drawable-hdpi/ic_text_dot.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ic_text_dot.png b/core/res/res/drawable-ldpi/ic_text_dot.png
deleted file mode 100644
index 4aff20c..0000000
--- a/core/res/res/drawable-ldpi/ic_text_dot.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_text_dot.png b/core/res/res/drawable-mdpi/ic_text_dot.png
deleted file mode 100644
index 2225bd5..0000000
--- a/core/res/res/drawable-mdpi/ic_text_dot.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_text_dot.png b/core/res/res/drawable-xhdpi/ic_text_dot.png
deleted file mode 100644
index 869dd95..0000000
--- a/core/res/res/drawable-xhdpi/ic_text_dot.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_text_dot.png b/core/res/res/drawable-xxhdpi/ic_text_dot.png
deleted file mode 100644
index a74c286..0000000
--- a/core/res/res/drawable-xxhdpi/ic_text_dot.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/ic_text_dot.xml b/core/res/res/drawable/ic_text_dot.xml
new file mode 100644
index 0000000..f8f3964
--- /dev/null
+++ b/core/res/res/drawable/ic_text_dot.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:inset="10dp">
+    <shape android:shape="oval">
+        <solid android:color="?android:attr/textColorSecondary" />
+        <size android:width="4dp" android:height="4dp" />
+    </shape>
+</inset>
diff --git a/core/res/res/drawable/vector_drawable_progress_bar_large.xml b/core/res/res/drawable/vector_drawable_progress_bar_large.xml
index 023f5cc..cd678f1 100644
--- a/core/res/res/drawable/vector_drawable_progress_bar_large.xml
+++ b/core/res/res/drawable/vector_drawable_progress_bar_large.xml
@@ -17,7 +17,8 @@
         android:height="76dp"
         android:width="76dp"
         android:viewportHeight="48"
-        android:viewportWidth="48" >
+        android:viewportWidth="48"
+        android:tint="?attr/colorControlActivated">
 
     <group
         android:name="root"
@@ -27,7 +28,7 @@
             android:name="progressBar"
             android:fillColor="#00000000"
             android:pathData="M0, 0 m 0, -19 a 19,19 0 1,1 0,38 a 19,19 0 1,1 0,-38"
-            android:strokeColor="?attr/colorControlActivated"
+            android:strokeColor="@color/white"
             android:strokeLineCap="square"
             android:strokeLineJoin="miter"
             android:strokeWidth="4"
diff --git a/core/res/res/drawable/vector_drawable_progress_bar_medium.xml b/core/res/res/drawable/vector_drawable_progress_bar_medium.xml
index e72097e..7f038f4 100644
--- a/core/res/res/drawable/vector_drawable_progress_bar_medium.xml
+++ b/core/res/res/drawable/vector_drawable_progress_bar_medium.xml
@@ -17,7 +17,8 @@
         android:height="48dp"
         android:width="48dp"
         android:viewportHeight="48"
-        android:viewportWidth="48" >
+        android:viewportWidth="48"
+        android:tint="?attr/colorControlActivated">
 
     <group
         android:name="root"
@@ -27,7 +28,7 @@
             android:name="progressBar"
             android:fillColor="#00000000"
             android:pathData="M0, 0 m 0, -19 a 19,19 0 1,1 0,38 a 19,19 0 1,1 0,-38"
-            android:strokeColor="?attr/colorControlActivated"
+            android:strokeColor="@color/white"
             android:strokeLineCap="square"
             android:strokeLineJoin="miter"
             android:strokeWidth="4"
diff --git a/core/res/res/drawable/vector_drawable_progress_bar_small.xml b/core/res/res/drawable/vector_drawable_progress_bar_small.xml
index 875e7a3..5625788 100644
--- a/core/res/res/drawable/vector_drawable_progress_bar_small.xml
+++ b/core/res/res/drawable/vector_drawable_progress_bar_small.xml
@@ -17,7 +17,8 @@
         android:height="16dp"
         android:width="16dp"
         android:viewportHeight="48"
-        android:viewportWidth="48" >
+        android:viewportWidth="48"
+        android:tint="?attr/colorControlActivated">
 
     <group
         android:name="root"
@@ -27,7 +28,7 @@
             android:name="progressBar"
             android:fillColor="#00000000"
             android:pathData="M0, 0 m 0, -19 a 19,19 0 1,1 0,38 a 19,19 0 1,1 0,-38"
-            android:strokeColor="?attr/colorControlActivated"
+            android:strokeColor="@color/white"
             android:strokeLineCap="square"
             android:strokeLineJoin="miter"
             android:strokeWidth="4"
diff --git a/core/res/res/layout/time_header_label.xml b/core/res/res/layout/time_header_label.xml
index 5c97040..84b2b0c 100644
--- a/core/res/res/layout/time_header_label.xml
+++ b/core/res/res/layout/time_header_label.xml
@@ -20,14 +20,13 @@
     android:layout_height="match_parent">
     <RelativeLayout
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_gravity="center">
+        android:layout_height="match_parent">
         <TextView
             android:id="@+id/hours"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_toLeftOf="@+id/separator"
-            android:layout_alignBaseline="@+id/separator" />
+            android:layout_centerVertical="true" />
         <TextView
             android:id="@+id/separator"
             android:layout_width="wrap_content"
@@ -41,14 +40,31 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_toRightOf="@+id/separator"
-            android:layout_alignBaseline="@+id/separator" />
-        <TextView
-            android:id="@+id/ampm_label"
+            android:layout_centerVertical="true" />
+        <LinearLayout
+            android:id="@+id/ampm_layout"
+            android:layout_alignBaseline="@+id/minutes"
+            android:layout_toEndOf="@+id/separator"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:paddingLeft="@dimen/timepicker_ampm_left_padding"
-            android:paddingRight="@dimen/timepicker_ampm_left_padding"
-            android:layout_toRightOf="@+id/separator"
-            android:layout_alignBaseline="@+id/separator" />
+            android:baselineAlignedChildIndex="1"
+            android:orientation="vertical">
+            <CheckedTextView
+                android:id="@+id/am_label"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:paddingStart="@dimen/timepicker_ampm_horizontal_padding"
+                android:paddingTop="@dimen/timepicker_ampm_vertical_padding"
+                android:paddingEnd="@dimen/timepicker_ampm_horizontal_padding"
+                android:paddingBottom="@dimen/timepicker_am_bottom_padding" />
+            <CheckedTextView
+                android:id="@+id/pm_label"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:paddingStart="@dimen/timepicker_ampm_horizontal_padding"
+                android:paddingTop="@dimen/timepicker_pm_top_padding"
+                android:paddingEnd="@dimen/timepicker_ampm_horizontal_padding"
+                android:paddingBottom="@dimen/timepicker_ampm_vertical_padding" />
+        </LinearLayout>
     </RelativeLayout>
 </FrameLayout>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 2a1be03..d3004a5 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Probeer weer"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Probeer weer"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Maksimum gesigontsluit-pogings oorskry"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Laai, (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Gelaai"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Koppel jou herlaaier."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Geen SIM-kaart nie"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Geen SIM-kaart in tablet nie."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Geen SIM-kaart in foon nie."</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 2425de1..3f15389 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"እንደገና ሞክር"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"እንደገና ሞክር"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"የመጨረሻውን  የገጽ ክፈት ሙከራዎችን አልፏል"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"ኃይል በመሙላት ላይ፣ <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"ባትሪ ሞልቷል።"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"ኃይል መሙያዎን ያያይዙ"</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"ምንም ሲም ካርድ የለም"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"በጡባዊ ውስጥ ምንም SIM ካርድ የለም።"</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"በስልክ ውስጥ ምንም SIM ካርድ የለም።"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 5a85883..092cb29 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"أعد المحاولة"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"أعد المحاولة"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"تم تجاوز الحد الأقصى لعدد محاولات تأمين الجهاز بالوجه"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"جارٍ الشحن، <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"تم الشحن"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"توصيل جهاز الشحن."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"‏ليست هناك بطاقة SIM"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"‏ليس هناك بطاقة SIM في الجهاز اللوحي."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"‏ليس هناك بطاقة SIM في الهاتف."</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 0aa18b1..6f3569a 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Опитайте отново"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Опитайте отново"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Максималният брой опити за отключване с лице е надвишен"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Зарежда се, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Заредена"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Свържете зарядното си устройство."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Няма SIM карта"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"В таблета няма SIM карта."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"В телефона няма SIM карта."</string>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index 0c97f24..77d46b3 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"আবার চেষ্টা করুন"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"আবার চেষ্টা করুন"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"মুখের সাহায্যে আনলক করার প্রচেষ্টা যতবার করা যায় তার সীমা পেরিয়ে গেছে"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"চার্জ হচ্ছে, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"চার্জ হয়েছে"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"আপনার চার্জার সংযুক্ত করুন৷"</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"কোনো সিম কার্ড নেই"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"ট্যাবলেটের মধ্যে কোনো সিম কার্ড নেই৷"</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"ফোনের মধ্যে কোনো সিম কার্ড নেই৷"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index fc9c470..40dd5f4 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Torna-ho a provar"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Torna-ho a provar"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"S\'ha superat el nombre màxim d\'intents de desbloqueig facial"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"S\'està carregant, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Carregada"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Connecteu el carregador."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"No hi ha cap targeta SIM."</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"No hi ha cap targeta SIM a la tauleta."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"No hi ha cap targeta SIM al telèfon."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 2b3f873..df6a0f4 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Zkusit znovu"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Zkusit znovu"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Překročili jste maximální povolený počet pokusů o odemknutí obličejem."</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Nabíjení - <xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Nabito"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Připojte dobíjecí zařízení."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Není vložena SIM karta"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"V tabletu není SIM karta."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"V telefonu není žádná SIM karta."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 677b9733..c2481de 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Prøv igen"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Prøv igen"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Det maksimale antal forsøg på at bruge Ansigtslås er overskredet"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Oplader, <xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Opladet"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Tilslut din oplader."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Intet SIM-kort"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Der er ikke noget SIM-kort i tabletcomputeren."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Der er ikke noget SIM-kort i telefonen."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 8924f9a..780c0b9 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Erneut versuchen"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Erneut versuchen"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Die maximal zulässige Anzahl an Face Unlock-Versuchen wurde überschritten."</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Wird aufgeladen... (<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>)"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Aufgeladen"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Ladegerät anschließen"</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Keine SIM-Karte"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Keine SIM-Karte im Tablet"</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Keine SIM-Karte im Telefon"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 9b8f0da..f02cac1 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Προσπαθήστε ξανά"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Προσπαθήστε ξανά"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Έγινε υπέρβαση του μέγιστου αριθμού προσπαθειών Face Unlock"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Φόρτιση, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Μπαταρία πλήρης"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Συνδέστε τον φορτιστή."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Δεν υπάρχει κάρτα SIM"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Δεν υπάρχει κάρτα SIM στο tablet."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Δεν υπάρχει κάρτα SIM στο τηλέφωνο."</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index ac974a6..ccf4ffa 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Try again"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Try again"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Maximum Face Unlock attempts exceeded"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Charging, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Charged"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Connect your charger."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"No SIM card"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"No SIM card in tablet."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"No SIM card in phone."</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index ac974a6..ccf4ffa 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Try again"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Try again"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Maximum Face Unlock attempts exceeded"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Charging, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Charged"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Connect your charger."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"No SIM card"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"No SIM card in tablet."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"No SIM card in phone."</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 8b45f58..bf39973 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Vuelve a intentarlo."</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Volver a intentarlo"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Se superó el máximo de intentos permitido para el desbloqueo facial del dispositivo."</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Cargando <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Cargada"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Conecta tu cargador."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Sin tarjeta SIM"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"No hay tarjeta SIM en el tablet."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"No hay tarjeta SIM en el dispositivo."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index b585e96..44ff61a 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Vuelve a intentarlo"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Vuelve a intentarlo"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Se ha superado el número máximo de intentos de desbloqueo facial."</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Cargando (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Cargada"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Conecta el cargador"</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Falta la tarjeta SIM."</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"No se ha insertado ninguna tarjeta SIM en el tablet."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"No se ha insertado ninguna tarjeta SIM en el teléfono."</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index f2b543b..cde326c 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Proovige uuesti"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Proovige uuesti"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Maksimaalne teenusega Face Unlock avamise katsete arv on ületatud"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Laadimine, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Laetud"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Ühendage laadija."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"SIM-kaarti pole"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Tahvelarvutis pole SIM-kaarti."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Telefonis pole SIM-kaarti."</string>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index a67b364..1ff59e4f 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Saiatu berriro"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Saiatu berriro"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Aurpegiaren bidez desblokeatzeko saiakera muga gainditu da"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Kargatzen, <xliff:g id="PERCENT">%%</xliff:g> <xliff:g id="NUMBER">%d</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Kargatuta"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="PERCENT">%%</xliff:g> <xliff:g id="NUMBER">%d</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Konektatu kargagailua."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Ez dago SIM txartelik"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Ez dago SIM txartelik tabletan."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Ez dago SIM txartelik telefonoan."</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 5b8d466..b66d0ae 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"دوباره امتحان کنید"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"دوباره امتحان کنید"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"‏دفعات تلاش برای Face Unlock از حداکثر مجاز بیشتر شد"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"در حال شارژ، <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"شارژ شد"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"شارژر خود را متصل کنید."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"سیم کارت موجود نیست"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"سیم کارت درون رایانهٔ لوحی نیست."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"سیم کارت درون تلفن نیست."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 12363b1..a796438 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Yritä uudelleen"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Yritä uudelleen"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Face Unlock -yrityksiä tehty suurin sallittu määrä."</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Ladataan (<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>)"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Täynnä"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Kytke laturi."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Ei SIM-korttia"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Tablet-laitteessa ei ole SIM-korttia."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Puhelimessa ei ole SIM-korttia."</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 741aee8..bd394ee 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Réessayer"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Réessayer"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Nombre maximal autorisé de tentatives Face Unlock atteint."</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"En charge (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Chargé"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Branchez votre chargeur."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Aucune carte SIM"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Aucune carte SIM n\'est insérée dans la tablette."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Aucune carte SIM n\'est insérée dans le téléphone."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 5eac5e7..1fee667 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Veuillez réessayer."</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Veuillez réessayer."</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Nombre maximal autorisé de tentatives Face Unlock atteint."</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"En charge (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Chargé"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Branchez votre chargeur."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Aucune carte SIM"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Aucune carte SIM n\'est insérée dans la tablette."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Aucune carte SIM n\'est insérée dans le téléphone."</string>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index bc152824..4085bbb 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Téntao de novo"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Téntao de novo"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Superouse o número máximo de intentos de desbloqueo facial"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Cargando, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Cargado"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Conecta o cargador."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Non hai ningunha tarxeta SIM"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Non hai ningunha tarxeta SIM no tablet."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Non hai ningunha tarxeta SIM no teléfono."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index a873caf..b3ffb8d 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"फिर से प्रयास करें"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"फिर से प्रयास करें"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"फेस अनलॉक के अधिकतम प्रयासों की सीमा पार हो गई"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"चार्ज हो रही है, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"चार्ज हो गया"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"अपना चार्जर कनेक्‍ट करें."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"कोई सिम कार्ड नहीं है"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"टेबलेट में कोई सिम कार्ड नहीं है."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"फ़ोन में कोई सिम कार्ड नहीं है."</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 74b6a7a..aa93037 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Pokušajte ponovo"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Pokušajte ponovo"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Premašen je maksimalni broj Otključavanja licem"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Punjenje, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Napunjeno"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Priključite punjač."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Nema SIM kartice"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"U tabletnom uređaju nema SIM kartice."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"U telefonu nema SIM kartice."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 6e67587..a39e2f0 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Próbálja újra"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Újra"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Elérte az arcalapú feloldási kísérletek maximális számát"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Töltés (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Feltöltve"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Csatlakoztassa a töltőt."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Nincs SIM kártya."</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Nincs SIM kártya a táblagépben."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Nincs SIM kártya a telefonban."</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 2493470..84e2662 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Կրկին փորձեք"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Կրկին փորձեք"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Առավելագույն Դեմքով ապակողպման փորձերը գերազանցված են"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Լիցքավորում, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Լիցքավորված է"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Միացրեք ձեր լիցքավորիչը:"</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"SIM քարտ չկա"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Գրասալիկում SIM քարտ չկա:"</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Հեռախոսում SIM քարտ չկա:"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index b58bcc6..b0e027c 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Coba lagi"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Coba lagi"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Percobaan Face Unlock melebihi batas maksimum"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Mengisi daya, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Terisi"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Hubungkan pengisi daya."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Tidak ada kartu SIM"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Tidak ada kartu SIM dalam tablet."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Tidak ada Kartu SIM di dalam ponsel."</string>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index 64fd266..02cfa67 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Reyndu aftur"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Reyndu aftur"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Hámarksfjölda tilrauna til að opna með andliti náð"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Í hleðslu, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Fullhlaðið"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Tengdu hleðslutækið."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Ekkert SIM-kort"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Ekkert SIM-kort í spjaldtölvunni."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Ekkert SIM-kort í símanum."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index d47f9ed..7778b93 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Riprova"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Riprova"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Numero massimo di tentativi di Sblocco col sorriso superato"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"In carica (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Carica"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Collegare il caricabatterie."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Nessuna scheda SIM"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Nessuna scheda SIM presente nel tablet."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Nessuna SIM presente nel telefono."</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 45f290f..074f252 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"נסה שוב"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"נסה שוב"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"חרגת ממספר הניסיונות המרבי של זיהוי פנים"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"טוען (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"טעון"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"חבר את המטען."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"‏אין כרטיס SIM"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"‏אין כרטיס SIM בטאבלט."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"‏אין כרטיס SIM בטלפון."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 00101ba..585022a 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"もう一度お試しください"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"もう一度お試しください"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"フェイスアンロックの最大試行回数を超えました"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"充電しています: <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"充電完了"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"充電してください"</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"SIMカードが挿入されていません"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"タブレット内にSIMカードがありません。"</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"SIMカードが挿入されていません"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 754ccdf..27f9fbd 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"კიდევ სცადეთ"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"კიდევ სცადეთ"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"სახის ამოცნობით განბლოკვის მცდელობამ დაშვებულ რაოდენობას გადააჭარბა"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"დამუხტვა, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"დამუხტულია"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"შეაერთეთ დამტენი."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"SIM ბარათი არ არის"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"ტაბლეტში არ დევს SIM ბარათი."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"არ არის SIM ბარათი ტელეფონში."</string>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index 2988201..7bfafe6 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Әрекетті қайталау"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Әрекетті қайталау"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Бет-әлпет арқылы ашу әрекеттері анықталған шегінен асып кетті"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Зарядтауда, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Зарядталған"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Зарядтағышты қосыңыз."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"SIM картасы жоқ"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Планшетте SIM картасы жоқ."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Телефонда SIM картасы жоқ."</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 30e675d..19f31ae 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"ព្យាយាម​ម្ដង​ទៀត"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"ព្យាយាម​ម្ដង​ទៀត"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"បាន​លើស​ការ​ព្យាយាម​ដោះ​សោ​តាម​ទម្រង់​មុខ"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"បញ្ចូល​ថ្ម <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"បាន​បញ្ចូល​ពេញ។"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"ភ្ជាប់​ឧបករណ៍​បញ្ចូល​ថ្ម។"</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"គ្មាន​ស៊ី​ម​កាត"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"គ្មាន​ស៊ីម​កាត​ក្នុង​កុំព្យូទ័រ​បន្ទះ។"</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"គ្មាន​ស៊ីម​កាត​ក្នុង​ទូរស័ព្ទ។"</string>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index b1b7825..cd8f11e 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"ಮತ್ತೆ ಪ್ರಯತ್ನಿಸು"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"ಮತ್ತೆ ಪ್ರಯತ್ನಿಸು"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"ಗರಿಷ್ಠ ಫೇಸ್ ಅನ್‍ಲಾಕ್ ಪ್ರಯತ್ನಗಳು ಮೀರಿವೆ"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"ಚಾರ್ಜ್ ಆಗಿದೆ"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"ನಿಮ್ಮ ಚಾರ್ಜರ್‌ಗೆ ಸಂಪರ್ಕಪಡಿಸಿ."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"ಯಾವುದೇ ಸಿಮ್‌ ಕಾರ್ಡ್ ಇಲ್ಲ"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"ಟ್ಯಾಬ್ಲೆಟ್‌ನಲ್ಲಿ ಸಿಮ್‌ ಕಾರ್ಡ್ ಇಲ್ಲ."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"ಫೋನ್‌ನಲ್ಲಿ ಸಿಮ್‌ ಕಾರ್ಡ್ ಇಲ್ಲ."</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 85c85b2..a4006ce 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"다시 시도"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"다시 시도"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"얼굴 인식 잠금해제 최대 시도 횟수를 초과했습니다."</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"충전 중(<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"충전됨"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"충전기를 연결하세요."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"SIM 카드가 없습니다."</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"태블릿에 SIM 카드가 없습니다."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"휴대전화에 SIM 카드가 없습니다."</string>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index b0a521b..ecd4c17 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -1195,11 +1195,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Дагы аракет кылыңыз"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Дагы аракет кылыңыз"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Жүзүнөн таанып ачуу аракеттеринин чегинен аштыңыз"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Дүрмөттөлүүдө, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Дүрмөттөлдү"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <!-- no translation found for lockscreen_low_battery (1482873981919249740) -->
-    <skip />
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"SIM-карта жок"</string>
     <!-- no translation found for lockscreen_missing_sim_message (151659196095791474) -->
     <skip />
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index 49da58b..5eeb1e0 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"ລອງໃໝ່ອີກຄັ້ງ"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"ທົດລອງອີກຄັ້ງ"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"ຄວາມພະຍາຍາມປົດລັອກດ້ວຍໜ້ານັ້ນ ເກີນຈຳນວນທີ່ກຳນົດແລ້ວ"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"ກຳລັງສາກ <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"ສາກເຕັມແລ້ວ."</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"ເຊື່ອມຕໍ່ສາຍສາກຂອງທ່ານ."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"ບໍ່ມີ SIM card."</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"ບໍ່ມີຊິມກາດໃນແທັບເລັດ."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"ບໍ່ມີ SIM card ໃນໂທລະສັບ."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index a631677..bf6c1b1 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Bandykite dar kartą"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Bandykite dar kartą"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Viršijote maksimalų atrakinimo pagal veidą bandymų skaičių"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Įkraunama, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Įkrauta"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Prijunkite kroviklį."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Nėra SIM kortelės"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Planšetiniame kompiuteryje nėra SIM kortelės."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Telefone nėra SIM kortelės."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 6cdf543..4b8a301 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Mēģināt vēlreiz"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Mēģināt vēlreiz"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Ir pārsniegts maksimālais Autorizācijas pēc sejas mēģinājumu skaits."</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Notiek uzlāde (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Uzlādēts"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Pievienojiet uzlādes ierīci."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Nav SIM kartes"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Planšetdatorā nav SIM kartes."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Tālrunī nav SIM kartes."</string>
diff --git a/core/res/res/values-mcc310-mnc160/config.xml b/core/res/res/values-mcc310-mnc160/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc200/config.xml b/core/res/res/values-mcc310-mnc200/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc200/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc210/config.xml b/core/res/res/values-mcc310-mnc210/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc210/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc220/config.xml b/core/res/res/values-mcc310-mnc220/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc220/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc230/config.xml b/core/res/res/values-mcc310-mnc230/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc230/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc240/config.xml b/core/res/res/values-mcc310-mnc240/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc240/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc250/config.xml b/core/res/res/values-mcc310-mnc250/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc250/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc260/config.xml b/core/res/res/values-mcc310-mnc260/config.xml
index 28cd695..6bfc3d1 100644
--- a/core/res/res/values-mcc310-mnc260/config.xml
+++ b/core/res/res/values-mcc310-mnc260/config.xml
@@ -25,8 +25,8 @@
     -->
     <integer name="config_mobile_mtu">1440</integer>
 
-    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+    <!-- Flag specifying whether VoLTE should be available for carrier: independent of
          carrier provisioning. If false: hard disabled. If true: then depends on carrier
          provisioning, availability etc -->
-    <bool name="config_carrier_volte_vt_available">true</bool>
+    <bool name="config_carrier_volte_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc270/config.xml b/core/res/res/values-mcc310-mnc270/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc270/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc300/config.xml b/core/res/res/values-mcc310-mnc300/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc300/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc310/config.xml b/core/res/res/values-mcc310-mnc310/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc310/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc490/config.xml b/core/res/res/values-mcc310-mnc490/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc490/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc530/config.xml b/core/res/res/values-mcc310-mnc530/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc530/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc580/config.xml b/core/res/res/values-mcc310-mnc580/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc580/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc590/config.xml b/core/res/res/values-mcc310-mnc590/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc590/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc640/config.xml b/core/res/res/values-mcc310-mnc640/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc640/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc660/config.xml b/core/res/res/values-mcc310-mnc660/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc660/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc800/config.xml b/core/res/res/values-mcc310-mnc800/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc800/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc311-mnc480/config.xml b/core/res/res/values-mcc311-mnc480/config.xml
index c2be340..d0a57b3 100644
--- a/core/res/res/values-mcc311-mnc480/config.xml
+++ b/core/res/res/values-mcc311-mnc480/config.xml
@@ -38,10 +38,10 @@
         be disabled) but individual Features can be disabled using ImsConfig.setFeatureValue() -->
     <bool name="imsServiceAllowTurnOff">false</bool>
 
-    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+    <!-- Flag specifying whether VoLTE should be available for carrier: independent of
          carrier provisioning. If false: hard disabled. If true: then depends on carrier
          provisioning, availability etc -->
-    <bool name="config_carrier_volte_vt_available">false</bool>
+    <bool name="config_carrier_volte_available">true</bool>
 
     <bool name="config_auto_attach_data_on_creation">false</bool>
     <!-- service number convert map in roaming network. -->
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index 444628a..dfa537e 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Обидете се повторно"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Обидете се повторно"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Максималниот број обиди на отклучување со лице е надминат"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Се полни, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Наполнета"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Поврзете го полначот."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Нема СИМ картичка"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Во таблетот нема СИМ картичка."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Во телефонот нема СИМ картичка."</string>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index 2237d8c..93df33f 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"വീണ്ടും ശ്രമിക്കുക"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"വീണ്ടും ശ്രമിക്കുക"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"മുഖം തിരിച്ചറിഞ്ഞുള്ള അൺലോക്ക് ശ്രമങ്ങളുടെ പരമാവധി കഴിഞ്ഞു"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"ചാർജ്ജുചെയ്യുന്നു, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"ചാർജ്ജുചെയ്‌തു"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"നിങ്ങളുടെ ചാർജർ കണക്റ്റുചെയ്യുക."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"സിം കാർഡൊന്നുമില്ല"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"ടാബ്‌ലെറ്റിൽ സിം കാർഡൊന്നുമില്ല."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"ഫോണിൽ സിം കാർഡൊന്നുമില്ല."</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index 9cb3e92..a82fb50 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Дахин оролдох"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Дахин оролдох"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Нүүрээр түгжээ тайлах оролдлогын тоо дээд хэмжээнээс хэтэрсэн"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Цэнэглэж байна, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Цэнэглэгдэв"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Цэнэглэгчээ холбоно уу."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"SIM карт байхгүй"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Таблет SIM картгүй."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Утсанд SIM карт байхгүй."</string>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index 93fe162..8392305 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"पुन्हा प्रयत्न करा"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"पुन्हा प्रयत्न करा"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"कमाल चेहरा अनलॉक प्रयत्न ओलांडले"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"चार्ज होत आहे, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"चार्ज झाली"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"आपले चार्जर कनेक्ट करा."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"सिम कार्ड नाही"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"टॅब्लेटमध्ये सिम कार्ड नाही."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"फोनमध्ये सिम कार्ड नाही."</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 557723f..2a6ef37 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Cuba lagi"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Cuba lagi"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Telah melepasi had cubaan Buka Kunci Wajah"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Mengecas, (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Sudah dicas"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Sambungkan pengecas anda."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Tiada kad SIM"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Tiada kad SIM dalam tablet."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Kad SIM tiada dalam telefon."</string>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index 3e156a8..a7c7999 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"ထပ် စမ်းပါ"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"ထပ် စမ်းပါ"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"မျက်မှာမှတ် သော့ဖွင့်ခြင်း ခွင့်ပြုသော အကြိမ်ရေထက် ကျော်လွန်သွားပါပြီ"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"အားသွင်းနေပါသည်, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"အားသွင်းနေပါသည်"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"အားသွင်းကြိုးဖြင့် ဆက်သွယ်ပါ"</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"ဆင်းကဒ် မရှိပါ"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"တက်ပလက်ထဲတွင်း ဆင်းကဒ် မရှိပါ"</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"ဖုန်းထဲတွင် ဆင်းကဒ် မရှိပါ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 02861c8..7ae95c4 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Prøv på nytt"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Prøv på nytt"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Du har overskredet grensen for opplåsingsforsøk med Ansiktslås"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Lader, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Oppladet"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Koble til en batterilader."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"SIM-kortet mangler"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Nettbrettet mangler SIM-kort."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Ikke noe SIM-kort i telefonen."</string>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index e2956a1..43ab645 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"फेरि प्रयास गर्नुहोस्"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"फेरि प्रयास गर्नुहोस्"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"अत्याधिक मोहडा खोल्ने प्रयासहरू बढी भए।"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"चार्ज हुँदै, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"चार्ज भयो"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"तपाईँको चार्जर जोड्नुहोस्।"</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"SIM कार्ड छैन"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"ट्याब्लेटमा SIM कार्ड छैन।"</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"फोनमा SIM कार्ड छैन।"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index f50077f..228587a 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Opnieuw proberen"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Nogmaals proberen"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Maximaal aantal pogingen voor Ontgrendelen via gezichtsherkenning overschreden"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Opladen, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Opgeladen"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Sluit de oplader aan."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Geen simkaart"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Geen SIM-kaart in tablet."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Geen SIM-kaart in telefoon."</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 9828832..84c2343 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Spróbuj ponownie."</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Spróbuj ponownie."</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Przekroczono maksymalną liczbę prób rozpoznania twarzy."</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Ładowanie (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Naładowany"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Podłącz ładowarkę."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Brak karty SIM"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Brak karty SIM w tablecie."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Brak karty SIM w telefonie."</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 90d3b75..fc2bb37 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Tentar novamente"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Tentar novamente"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Excedido o n.º máximo de tentativas de Desbloqueio Através do Rosto"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"A carregar, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Carregado"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Ligue o carregador."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Nenhum cartão SIM"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Nenhum cartão SIM no tablet."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Nenhum cartão SIM no telefone."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 1f8283b..972e601 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Tente novamente"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Tente novamente"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"O número máximo de tentativas de Desbloqueio por reconhecimento facial foi excedido"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Carregando, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Carregado"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Conecte o seu carregador."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Sem cartão SIM"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Não há um cartão SIM no tablet."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Não há um cartão SIM no telefone."</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index de3201b..113921c 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Încercaţi din nou"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Încercaţi din nou"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"S-a depăşit numărul maxim de încercări pentru Deblocare facială"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Se încarcă, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Încărcată"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Conectaţi încărcătorul."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Niciun card SIM"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Nu există card SIM în computerul tablet PC."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Telefonul nu are card SIM."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index d5ef427..e9ce7dc 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Повторите попытку"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Повторите попытку"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Все попытки войти с помощью Фейсконтроля использованы"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Идет зарядка (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Заряжено"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Подключите зарядное устройство"</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Нет SIM-карты"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"SIM-карта не установлена."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"SIM-карта не установлена."</string>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index d94be04..30998aa 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"නැවත උත්සාහ කරන්න"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"නැවත උත්සාහ කරන්න"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"මුහුණ භාවිතයෙන් අඟුළු හැරීමේ උපරිම ප්‍රයන්තයන් ගණන ඉක්මවා ඇත"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"ආරෝපණය වෙමින්, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"අරෝපිතයි"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"ඔබගේ ආරෝපකයට සම්බන්ධ කරන්න."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"SIM පත නැත"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"ටැබ්ලටයේ SIM පත නොමැත."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"දුරකථනය තුළ SIM පත නැත."</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index bed560f..d67fb2e 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Skúsiť znova"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Skúsiť znova"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Prekročili ste maximálny povolený počet pokusov o odomknutie tvárou"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Prebieha nabíjanie, <xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Nabitá batéria"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Pripojte nabíjačku."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Nie je vložená karta SIM"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"V tablete nie je žiadna karta SIM."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"V telefóne nie je žiadna karta SIM."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 5a6ed07..8d9060b 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Poskusi znova"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Poskusite znova"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Presegli ste dovoljeno število poskusov odklepanja z obrazom"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Polnjenje (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Napolnjeno"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Priključite napajalnik."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Ni kartice SIM"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"V tabličnem računalniku ni kartice SIM."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"V telefonu ni kartice SIM."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index a2c2128..fe19510 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Покушајте поново"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Покушајте поново"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Премашен је највећи дозвољени број покушаја Откључавања лицем"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Пуњење, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Напуњено"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Повежите пуњач."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Нема SIM картице"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"У таблету нема SIM картице."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"У телефон није уметнута SIM картица."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index a9a7891..14a00a4 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Försök igen"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Försök igen"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Du har försökt låsa upp med Ansiktslås för många gånger"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Laddar (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Batteriet har laddats"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Anslut din laddare."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Inget SIM-kort"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Inget SIM-kort i surfplattan."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Inget SIM-kort i telefonen."</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index d59f445..727e6b5 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Jaribu tena"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Jaribu tena"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Majaribio ya Juu ya Kufungua Uso yamezidishwa"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Inachaji <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Betri imejaa"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Unganisha chaja yako"</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Hakuna SIM kadi"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Hakuna SIM kadi katika kompyuta ndogo."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Hakuna SIM kadi kwenye simu."</string>
diff --git a/core/res/res/values-sw600dp/bools.xml b/core/res/res/values-sw600dp/bools.xml
index ddc48c5..00f45c1 100644
--- a/core/res/res/values-sw600dp/bools.xml
+++ b/core/res/res/values-sw600dp/bools.xml
@@ -19,7 +19,6 @@
     <bool name="show_ongoing_ime_switcher">true</bool>
     <bool name="kg_share_status_area">false</bool>
     <bool name="kg_sim_puk_account_full_screen">false</bool>
-    <bool name="kg_show_ime_at_screen_on">false</bool>
     <!-- No camera for you, tablet user -->
     <bool name="kg_enable_camera_default_widget">false</bool>
     <bool name="kg_center_small_widgets_vertically">true</bool>
diff --git a/core/res/res/values-sw720dp/dimens_material.xml b/core/res/res/values-sw720dp/dimens_material.xml
new file mode 100644
index 0000000..3b97b7a
--- /dev/null
+++ b/core/res/res/values-sw720dp/dimens_material.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+
+    <!-- Preference activity, vertical padding for the header list -->
+    <dimen name="preference_screen_header_vertical_padding_material">8dp</dimen>
+
+</resources>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index f19420d..ee9bad8 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"மீண்டும் முயற்சிக்கவும்"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"மீண்டும் முயற்சிக்கவும்"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"முகம் திறப்பதற்கான அதிகபட்ச முயற்சிகள் கடந்தன"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"சார்ஜ் ஏற்றுகிறது, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"சார்ஜ் செய்யப்பட்டது"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"உங்கள் சார்ஜரை இணைக்கவும்."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"சிம் கார்டு இல்லை"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"டேப்லெட்டில் சிம் கார்டு இல்லை."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"தொலைபேசியில் சிம் கார்டு இல்லை."</string>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index 8bfe52f..a0f2cb7 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"మళ్లీ ప్రయత్నించండి"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"మళ్లీ ప్రయత్నించండి"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"ముఖంతో అన్‌లాక్ ప్రయత్నాల గరిష్ట పరిమితి మించిపోయారు"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"ఛార్జ్ అవుతోంది, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"ఛార్జ్ అయింది"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"మీ ఛార్జర్‌ను కనెక్ట్ చేయండి."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"సిమ్ కార్డు లేదు"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"టాబ్లెట్‌లో సిమ్ కార్డు లేదు."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"ఫోన్‌లో సిమ్ కార్డు లేదు."</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index d9c01bb..ecef924 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"ลองอีกครั้ง"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"ลองอีกครั้ง"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"มีความพยายามที่จะใช้ Face Unlock เกินขีดจำกัด"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"กำลังชาร์จ, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"ชาร์จแล้ว"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"เสียบที่ชาร์จของคุณ"</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"ไม่มีซิมการ์ด"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"ไม่มีซิมการ์ดในแท็บเล็ต"</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"ไม่มีซิมการ์ดในโทรศัพท์"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 8ba750e..f61c548 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Subukang muli"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Subukang muli"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Nalagpasan na ang maximum na mga pagtatangka sa Face Unlock"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Nagcha-charge, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Siningil"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Ikonekta ang iyong charger."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Walang SIM card"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Walang SIM card sa tablet."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Walang SIM card sa telepono."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index ea497ed..a786101 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Tekrar deneyin"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Tekrar deneyin"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Yüz Tanıma Kilidi için maksimum deneme sayısı aşıldı"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Şarj oluyor (<xliff:g id="PERCENT">%%</xliff:g><xliff:g id="NUMBER">%d</xliff:g>)"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Şarj oldu"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="PERCENT">%%</xliff:g><xliff:g id="NUMBER">%d</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Şarj cihazınızı takın."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"SIM kart yok"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Tablette SIM kart yok."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Telefonda SIM kart yok."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 25ba77c..093844b 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Повторіть спробу"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Повторіть спробу"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Перевищено максимальну кількість спроб розблокування за допомогою функції \"Фейсконтроль\""</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Заряджається, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Заряджено"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Підкл. заряд. пристрій."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Відсутня SIM-карта"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"У пристр. нема SIM-карти."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"У тел. немає SIM-карти."</string>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index a298353..2826c4e 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"دوبارہ کوشش کریں"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"دوبارہ کوشش کریں"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"چہرہ کے ذریعے غیر مقفل کریں کی زیادہ سے زیادہ کوششوں سے تجاوز کرگیا"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"چارج ہو رہا ہے، <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"چارج ہو گیا"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"اپنا چاجر لگائیں۔"</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"‏کوئی SIM کارڈ نہیں ہے"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"‏ٹیبلیٹ میں کوئی SIM کارڈ نہیں ہے۔"</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"‏فون میں کوئی SIM کارڈ نہیں ہے۔"</string>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index 41c5547..2c209c3 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Qaytadan urining"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Qaytadan urining"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Yuzni tanitib qulfni ochishga urinish miqdoridan oshib ketdi"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Quvvatlanyapti: <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Zaryad to‘la"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Zaryadlagichni ulang."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"SIM karta yo‘q"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Planshetingizga SIM karta yo‘q."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Telefoningizga SIM karta yo‘q."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 222fcfe..2e024ae 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Thử lại"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Thử lại"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Đã vượt quá số lần Mở khóa bằng khuôn mặt tối đa"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Đang sạc, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Pin đầy"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Kết nối bộ sạc của bạn."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Không có thẻ SIM nào"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Không có thẻ SIM nào trong máy tính bảng."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Không có thẻ SIM nào trong điện thoại."</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index d1711b4..eef11ce 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"重试"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"重试"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"已超过“人脸解锁”尝试次数上限"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"正在充电,<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"充电完成"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"连接您的充电器。"</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"没有SIM卡"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"平板电脑中没有SIM卡。"</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"手机中无SIM卡"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 15a9832..cbdeae6 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"再試一次"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"再試一次"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"已超過臉容解鎖嘗試次數上限"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"充電中 (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"充電完成"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"請連接充電器。"</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"找不到 SIM 卡"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"平板電腦中沒有 SIM 卡。"</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"手機中沒有 SIM 卡。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index aa2c785..55c2eb1 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"再試一次"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"再試一次"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"已超過人臉解鎖嘗試次數上限"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"充電中 (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"充電完成"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"請連接充電器。"</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"找不到 SIM 卡"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"平板電腦中沒有 SIM 卡。"</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"手機未插入 SIM 卡。"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index f968a87..d0b15f9 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -905,10 +905,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Zama futhi"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Zama futhi"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Ukuzama Kokuvula Ubuso Okuningi kudluliwe"</string>
-    <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Iyashaja (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Kushajiwe"</string>
-    <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_low_battery" msgid="1482873981919249740">"Xhuma ishaja yakho."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Alikho ikhadi le-SIM."</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Alikho ikhadi le-SIM efonini."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Alikho ikhadi le-SIM efonini."</string>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index a8b5d6d..bb9885c 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -298,162 +298,75 @@
        <item>@drawable/quickcontact_badge_overlay_pressed_light</item>
 
        <!-- Material assets -->
-       <item>@drawable/ab_share_pack_mtrl_alpha</item>
-       <item>@drawable/ab_solid_shadow_mtrl_alpha</item>
-       <item>@drawable/btn_cab_done_mtrl_alpha</item>
-       <item>@drawable/btn_check_to_off_mtrl_000</item>
-       <item>@drawable/btn_check_to_off_mtrl_001</item>
-       <item>@drawable/btn_check_to_off_mtrl_002</item>
-       <item>@drawable/btn_check_to_off_mtrl_003</item>
-       <item>@drawable/btn_check_to_off_mtrl_004</item>
-       <item>@drawable/btn_check_to_off_mtrl_005</item>
-       <item>@drawable/btn_check_to_off_mtrl_006</item>
-       <item>@drawable/btn_check_to_off_mtrl_007</item>
-       <item>@drawable/btn_check_to_off_mtrl_008</item>
-       <item>@drawable/btn_check_to_off_mtrl_009</item>
-       <item>@drawable/btn_check_to_off_mtrl_010</item>
-       <item>@drawable/btn_check_to_off_mtrl_011</item>
-       <item>@drawable/btn_check_to_off_mtrl_012</item>
-       <item>@drawable/btn_check_to_off_mtrl_013</item>
-       <item>@drawable/btn_check_to_off_mtrl_014</item>
-       <item>@drawable/btn_check_to_off_mtrl_015</item>
-       <item>@drawable/btn_check_to_on_mtrl_000</item>
-       <item>@drawable/btn_check_to_on_mtrl_001</item>
-       <item>@drawable/btn_check_to_on_mtrl_002</item>
-       <item>@drawable/btn_check_to_on_mtrl_003</item>
-       <item>@drawable/btn_check_to_on_mtrl_004</item>
-       <item>@drawable/btn_check_to_on_mtrl_005</item>
-       <item>@drawable/btn_check_to_on_mtrl_006</item>
-       <item>@drawable/btn_check_to_on_mtrl_007</item>
-       <item>@drawable/btn_check_to_on_mtrl_008</item>
-       <item>@drawable/btn_check_to_on_mtrl_009</item>
-       <item>@drawable/btn_check_to_on_mtrl_010</item>
-       <item>@drawable/btn_check_to_on_mtrl_011</item>
-       <item>@drawable/btn_check_to_on_mtrl_012</item>
-       <item>@drawable/btn_check_to_on_mtrl_013</item>
-       <item>@drawable/btn_check_to_on_mtrl_014</item>
-       <item>@drawable/btn_check_to_on_mtrl_015</item>
-       <item>@drawable/btn_radio_to_off_mtrl_000</item>
-       <item>@drawable/btn_radio_to_off_mtrl_001</item>
-       <item>@drawable/btn_radio_to_off_mtrl_002</item>
-       <item>@drawable/btn_radio_to_off_mtrl_003</item>
-       <item>@drawable/btn_radio_to_off_mtrl_004</item>
-       <item>@drawable/btn_radio_to_off_mtrl_005</item>
-       <item>@drawable/btn_radio_to_off_mtrl_006</item>
-       <item>@drawable/btn_radio_to_off_mtrl_007</item>
-       <item>@drawable/btn_radio_to_off_mtrl_008</item>
-       <item>@drawable/btn_radio_to_off_mtrl_009</item>
-       <item>@drawable/btn_radio_to_off_mtrl_010</item>
-       <item>@drawable/btn_radio_to_off_mtrl_011</item>
-       <item>@drawable/btn_radio_to_off_mtrl_012</item>
-       <item>@drawable/btn_radio_to_off_mtrl_013</item>
-       <item>@drawable/btn_radio_to_off_mtrl_014</item>
-       <item>@drawable/btn_radio_to_off_mtrl_015</item>
-       <item>@drawable/btn_radio_to_on_mtrl_000</item>
-       <item>@drawable/btn_radio_to_on_mtrl_001</item>
-       <item>@drawable/btn_radio_to_on_mtrl_002</item>
-       <item>@drawable/btn_radio_to_on_mtrl_003</item>
-       <item>@drawable/btn_radio_to_on_mtrl_004</item>
-       <item>@drawable/btn_radio_to_on_mtrl_005</item>
-       <item>@drawable/btn_radio_to_on_mtrl_006</item>
-       <item>@drawable/btn_radio_to_on_mtrl_007</item>
-       <item>@drawable/btn_radio_to_on_mtrl_008</item>
-       <item>@drawable/btn_radio_to_on_mtrl_009</item>
-       <item>@drawable/btn_radio_to_on_mtrl_010</item>
-       <item>@drawable/btn_radio_to_on_mtrl_011</item>
-       <item>@drawable/btn_radio_to_on_mtrl_012</item>
-       <item>@drawable/btn_radio_to_on_mtrl_013</item>
-       <item>@drawable/btn_radio_to_on_mtrl_014</item>
-       <item>@drawable/btn_radio_to_on_mtrl_015</item>
-       <item>@drawable/btn_rating_star_off_mtrl_alpha</item>
-       <item>@drawable/btn_rating_star_on_mtrl_alpha</item>
-       <item>@drawable/btn_star_mtrl_alpha</item>
-       <item>@drawable/btn_switch_to_off_mtrl_00001</item>
-       <item>@drawable/btn_switch_to_off_mtrl_00002</item>
-       <item>@drawable/btn_switch_to_off_mtrl_00003</item>
-       <item>@drawable/btn_switch_to_off_mtrl_00004</item>
-       <item>@drawable/btn_switch_to_off_mtrl_00005</item>
-       <item>@drawable/btn_switch_to_off_mtrl_00006</item>
-       <item>@drawable/btn_switch_to_off_mtrl_00007</item>
-       <item>@drawable/btn_switch_to_off_mtrl_00008</item>
-       <item>@drawable/btn_switch_to_off_mtrl_00009</item>
-       <item>@drawable/btn_switch_to_off_mtrl_00010</item>
-       <item>@drawable/btn_switch_to_off_mtrl_00011</item>
-       <item>@drawable/btn_switch_to_off_mtrl_00012</item>
-       <item>@drawable/btn_switch_to_on_mtrl_00001</item>
-       <item>@drawable/btn_switch_to_on_mtrl_00002</item>
-       <item>@drawable/btn_switch_to_on_mtrl_00003</item>
-       <item>@drawable/btn_switch_to_on_mtrl_00004</item>
-       <item>@drawable/btn_switch_to_on_mtrl_00005</item>
-       <item>@drawable/btn_switch_to_on_mtrl_00006</item>
-       <item>@drawable/btn_switch_to_on_mtrl_00007</item>
-       <item>@drawable/btn_switch_to_on_mtrl_00008</item>
-       <item>@drawable/btn_switch_to_on_mtrl_00009</item>
-       <item>@drawable/btn_switch_to_on_mtrl_00010</item>
-       <item>@drawable/btn_switch_to_on_mtrl_00011</item>
-       <item>@drawable/btn_switch_to_on_mtrl_00012</item>
-       <item>@drawable/btn_toggle_indicator_mtrl_alpha</item>
-       <item>@drawable/expander_close_mtrl_alpha</item>
-       <item>@drawable/expander_open_mtrl_alpha</item>
-       <item>@drawable/fastscroll_thumb_mtrl_alpha</item>
-       <item>@drawable/fastscroll_track_mtrl_alpha</item>
+       <item>@drawable/ab_share_pack_material</item>
+       <item>@drawable/ab_solid_shadow_material</item>
+       <item>@drawable/activated_background_material</item>
+       <item>@drawable/btn_borderless_material</item>
+       <item>@drawable/btn_cab_done_material</item>
+       <item>@drawable/btn_check_material_anim</item>
+       <item>@drawable/btn_default_material</item>
+       <item>@drawable/btn_radio_material_anim</item>
+       <item>@drawable/btn_star_material</item>
+       <item>@drawable/btn_toggle_material</item>
+       <item>@drawable/cab_background_bottom_material</item>
+       <item>@drawable/cab_background_top_material</item>
+       <item>@drawable/dialog_background_material</item>
+       <item>@drawable/dialog_background_shadow_material</item>
+       <item>@drawable/edit_text_material</item>
+       <item>@drawable/expander_group_material</item>
+       <item>@drawable/fastscroll_label_left_material</item>
+       <item>@drawable/fastscroll_label_right_material</item>
+       <item>@drawable/fastscroll_thumb_material</item>
+       <item>@drawable/fastscroll_track_material</item>
        <item>@drawable/ic_ab_back_material</item>
-       <item>@drawable/ic_cab_done_mtrl_alpha</item>
-       <item>@drawable/ic_clear_mtrl_alpha</item>
-       <item>@drawable/ic_commit_search_api_mtrl_alpha</item>
+       <item>@drawable/ic_clear_material</item>
+       <item>@drawable/ic_commit_search_api_material</item>
        <item>@drawable/ic_dialog_alert_material</item>
-       <item>@drawable/ic_find_next_mtrl_alpha</item>
-       <item>@drawable/ic_find_previous_mtrl_alpha</item>
+       <item>@drawable/ic_find_next_material</item>
+       <item>@drawable/ic_find_previous_material</item>
        <item>@drawable/ic_go_search_api_material</item>
-       <item>@drawable/ic_media_route_disabled_mtrl_alpha</item>
-       <item>@drawable/ic_media_route_off_mtrl_alpha</item>
-       <item>@drawable/ic_media_route_on_0_mtrl_alpha</item>
-       <item>@drawable/ic_media_route_on_1_mtrl_alpha</item>
-       <item>@drawable/ic_media_route_on_2_mtrl_alpha</item>
-       <item>@drawable/ic_media_route_on_mtrl_alpha</item>
+       <item>@drawable/ic_media_route_connecting_material</item>
+       <item>@drawable/ic_media_route_material</item>
        <item>@drawable/ic_menu_copy_material</item>
        <item>@drawable/ic_menu_cut_material</item>
-       <item>@drawable/ic_menu_find_mtrl_alpha</item>
+       <item>@drawable/ic_menu_find_material</item>
        <item>@drawable/ic_menu_moreoverflow_material</item>
        <item>@drawable/ic_menu_paste_material</item>
-       <item>@drawable/ic_menu_search_mtrl_alpha</item>
+       <item>@drawable/ic_menu_search_material</item>
        <item>@drawable/ic_menu_selectall_material</item>
        <item>@drawable/ic_menu_share_material</item>
        <item>@drawable/ic_search_api_material</item>
        <item>@drawable/ic_voice_search_api_material</item>
-       <item>@drawable/list_divider_mtrl_alpha</item>
-       <item>@drawable/list_section_divider_mtrl_alpha</item>
-       <item>@drawable/popup_background_mtrl_mult</item>
-       <item>@drawable/progress_mtrl_alpha</item>
-       <item>@drawable/scrollbar_handle_mtrl_alpha</item>
-       <item>@drawable/scrubber_control_from_pressed_mtrl_000</item>
-       <item>@drawable/scrubber_control_from_pressed_mtrl_001</item>
-       <item>@drawable/scrubber_control_from_pressed_mtrl_002</item>
-       <item>@drawable/scrubber_control_from_pressed_mtrl_003</item>
-       <item>@drawable/scrubber_control_from_pressed_mtrl_004</item>
-       <item>@drawable/scrubber_control_from_pressed_mtrl_005</item>
-       <item>@drawable/scrubber_control_off_pressed_mtrl_alpha</item>
-       <item>@drawable/scrubber_control_off_mtrl_alpha</item>
-       <item>@drawable/scrubber_control_on_pressed_mtrl_alpha</item>
-       <item>@drawable/scrubber_control_on_mtrl_alpha</item>
-       <item>@drawable/scrubber_control_to_pressed_mtrl_000</item>
-       <item>@drawable/scrubber_control_to_pressed_mtrl_001</item>
-       <item>@drawable/scrubber_control_to_pressed_mtrl_002</item>
-       <item>@drawable/scrubber_control_to_pressed_mtrl_003</item>
-       <item>@drawable/scrubber_control_to_pressed_mtrl_004</item>
-       <item>@drawable/scrubber_control_to_pressed_mtrl_005</item>
-       <item>@drawable/scrubber_primary_mtrl_alpha</item>
-       <item>@drawable/scrubber_track_mtrl_alpha</item>
-       <item>@drawable/spinner_mtrl_am_alpha</item>
-       <item>@drawable/switch_track_mtrl_alpha</item>
-       <item>@drawable/text_cursor_mtrl_alpha</item>
-       <item>@drawable/textfield_activated_mtrl_alpha</item>
-       <item>@drawable/textfield_default_mtrl_alpha</item>
-       <item>@drawable/textfield_search_activated_mtrl_alpha</item>
-       <item>@drawable/textfield_search_default_mtrl_alpha</item>
-       <item>@drawable/text_select_handle_left_mtrl_alpha</item>
-       <item>@drawable/text_select_handle_middle_mtrl_alpha</item>
-       <item>@drawable/text_select_handle_right_mtrl_alpha</item>
+       <item>@drawable/item_background_borderless_material</item>
+       <item>@drawable/item_background_material</item>
+       <item>@drawable/list_divider_material</item>
+       <item>@drawable/list_section_divider_material</item>
+       <item>@drawable/notification_material_action_background</item>
+       <item>@drawable/notification_material_media_action_background</item>
+       <item>@drawable/popup_background_material</item>
+       <item>@drawable/progress_horizontal_material</item>
+       <item>@drawable/progress_indeterminate_horizontal_material</item>
+       <item>@drawable/progress_large_material</item>
+       <item>@drawable/progress_medium_material</item>
+       <item>@drawable/progress_small_material</item>
+       <item>@drawable/ratingbar_full_empty_material</item>
+       <item>@drawable/ratingbar_full_filled_material</item>
+       <item>@drawable/ratingbar_full_material</item>
+       <item>@drawable/scrollbar_handle_material</item>
+       <item>@drawable/scrubber_control_material_anim</item>
+       <item>@drawable/scrubber_control_selector_material</item>
+       <item>@drawable/scrubber_progress_horizontal_material</item>
+       <item>@drawable/spinner_background_material</item>
+       <item>@drawable/spinner_textfield_background_material</item>
+       <item>@drawable/switch_thumb_material_anim</item>
+       <item>@drawable/switch_track_material</item>
+       <item>@drawable/tab_indicator_material</item>
+       <item>@drawable/text_cursor_material</item>
+       <item>@drawable/textfield_search_material</item>
+       <item>@drawable/text_select_handle_left_material</item>
+       <item>@drawable/text_select_handle_middle_material</item>
+       <item>@drawable/text_select_handle_right_material</item>
+       <item>@drawable/ic_account_circle</item>
     </array>
 
     <!-- Do not translate. These are all of the color state list resources that should be
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 251652e..d988480 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2772,25 +2772,32 @@
         <attr name="layout_width" />
         <attr name="layout_height" />
         <!--  Specifies extra space on the left, top, right and bottom
-              sides of this view. This space is outside this view's bounds. -->
+              sides of this view. This space is outside this view's bounds.
+              Margin values should be positive. -->
         <attr name="layout_margin" format="dimension"  />
         <!--  Specifies extra space on the left side of this view.
-              This space is outside this view's bounds. -->
+              This space is outside this view's bounds.
+              Margin values should be positive. -->
         <attr name="layout_marginLeft" format="dimension"  />
         <!--  Specifies extra space on the top side of this view.
-              This space is outside this view's bounds. -->
+              This space is outside this view's bounds.
+              Margin values should be positive.-->
         <attr name="layout_marginTop" format="dimension" />
         <!--  Specifies extra space on the right side of this view.
-              This space is outside this view's bounds. -->
+              This space is outside this view's bounds.
+              Margin values should be positive.-->
         <attr name="layout_marginRight" format="dimension"  />
         <!--  Specifies extra space on the bottom side of this view.
-              This space is outside this view's bounds. -->
+              This space is outside this view's bounds.
+              Margin values should be positive.-->
         <attr name="layout_marginBottom" format="dimension"  />
         <!--  Specifies extra space on the start side of this view.
-              This space is outside this view's bounds. -->
+              This space is outside this view's bounds.
+              Margin values should be positive.-->
         <attr name="layout_marginStart" format="dimension"  />
         <!--  Specifies extra space on the end side of this view.
-              This space is outside this view's bounds. -->
+              This space is outside this view's bounds.
+              Margin values should be positive.-->
         <attr name="layout_marginEnd" format="dimension"  />
     </declare-styleable>
 
@@ -4862,6 +4869,12 @@
         <attr name="thickness" format="dimension" />
         <!-- Indicates whether the drawable's level affects the way the gradient is drawn. -->
         <attr name="useLevel" />
+        <!-- If set, specifies the color to apply to the drawable as a tint. By default,
+             no tint is applied. May be a color state list. -->
+        <attr name="tint" />
+        <!-- When a tint color is set, specifies its Porter-Duff blending mode. The
+             default value is src_in, which treats the drawable as an alpha mask. -->
+        <attr name="tintMode" />
     </declare-styleable>
 
     <!-- Used to specify the size of the shape for GradientDrawable. -->
@@ -4898,7 +4911,7 @@
         <!-- Y coordinate of the origin of the gradient within the shape. -->
         <attr name="centerY" format="float|fraction" />
         <!-- Radius of the gradient, used only with radial gradient. -->
-        <attr name="gradientRadius" format="float|fraction" />
+        <attr name="gradientRadius" format="float|fraction|dimension" />
     </declare-styleable>
 
     <!-- Used to fill the shape of GradientDrawable with a solid color. -->
diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml
index 18e4f2f..457131a 100644
--- a/core/res/res/values/bools.xml
+++ b/core/res/res/values/bools.xml
@@ -18,7 +18,6 @@
     <bool name="kg_enable_camera_default_widget">true</bool>
     <bool name="kg_center_small_widgets_vertically">false</bool>
     <bool name="kg_top_align_page_shrink_on_bouncer_visible">true</bool>
-    <bool name="kg_show_ime_at_screen_on">true</bool>
     <bool name="action_bar_embed_tabs">true</bool>
     <bool name="action_bar_embed_tabs_pre_jb">false</bool>
     <bool name="split_action_bar_is_narrow">true</bool>
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 235bf84..9f83db4 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -136,6 +136,8 @@
     <color name="notification_media_primary_color">@color/primary_text_material_dark</color>
     <color name="notification_media_secondary_color">@color/secondary_text_material_dark</color>
 
+    <color name="notification_progress_background_color">@color/secondary_text_material_light</color>
+
     <!-- Keyguard colors -->
     <color name="keyguard_avatar_frame_color">#ffffffff</color>
     <color name="keyguard_avatar_frame_shadow_color">#80000000</color>
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index 5773b94..46ec838 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -22,7 +22,7 @@
     <color name="background_floating_material_light">#ffeeeeee</color>
 
     <color name="primary_material_dark">#ff212121</color>
-    <color name="primary_material_light">#ffbdbdbd</color>
+    <color name="primary_material_light">#ffe0e0e0</color>
     <color name="primary_dark_material_dark">#ff000000</color>
     <color name="primary_dark_material_light">#ff757575</color>
 
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index eed2ef2..e50eb0c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1787,13 +1787,21 @@
         be disabled) but individual Features can be disabled using ImsConfig.setFeatureValue() -->
     <bool name="imsServiceAllowTurnOff">true</bool>
 
-    <!-- Flag specifying whether VoLTE & VT is availasble on device -->
-    <bool name="config_device_volte_vt_available">false</bool>
+    <!-- Flag specifying whether VoLTE is available on device -->
+    <bool name="config_device_volte_available">false</bool>
 
-    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+    <!-- Flag specifying whether VoLTE should be available for carrier: independent of
          carrier provisioning. If false: hard disabled. If true: then depends on carrier
          provisioning, availability etc -->
-    <bool name="config_carrier_volte_vt_available">false</bool>
+    <bool name="config_carrier_volte_available">false</bool>
+
+    <!-- Flag specifying whether VT is available on device -->
+    <bool name="config_device_vt_available">false</bool>
+
+    <!-- Flag specifying whether VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_vt_available">false</bool>
 
     <bool name="config_networkSamplingWakesDevice">true</bool>
 
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 26d3133..71f66ba 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -367,12 +367,15 @@
     <dimen name="timepicker_time_label_size">60sp</dimen>
     <dimen name="timepicker_extra_time_label_margin">-30dp</dimen>
     <dimen name="timepicker_ampm_label_size">16sp</dimen>
-    <dimen name="timepicker_ampm_left_padding">6dip</dimen>
-    <dimen name="timepicker_separator_padding">4dip</dimen>
-    <dimen name="timepicker_header_height">96dip</dimen>
-    <dimen name="timepicker_minimum_margin_sides">48dip</dimen>
-    <dimen name="timepicker_minimum_margin_top_bottom">24dip</dimen>
-    <dimen name="timepicker_radial_picker_dimen">270dip</dimen>
+    <dimen name="timepicker_ampm_horizontal_padding">12dp</dimen>
+    <dimen name="timepicker_ampm_vertical_padding">16dp</dimen>
+    <dimen name="timepicker_am_bottom_padding">1dp</dimen>
+    <dimen name="timepicker_pm_top_padding">2dp</dimen>
+    <dimen name="timepicker_separator_padding">4dp</dimen>
+    <dimen name="timepicker_header_height">96dp</dimen>
+    <dimen name="timepicker_minimum_margin_sides">48dp</dimen>
+    <dimen name="timepicker_minimum_margin_top_bottom">24dp</dimen>
+    <dimen name="timepicker_radial_picker_dimen">270dp</dimen>
 
     <!-- Used by SimpleMonthView -->
     <dimen name="datepicker_day_number_size">12sp</dimen>
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index 450658e..515922d 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -15,7 +15,7 @@
 -->
 <resources>
     <!-- Preference activity, vertical padding for the header list -->
-    <dimen name="preference_screen_header_vertical_padding_material">8dp</dimen>
+    <dimen name="preference_screen_header_vertical_padding_material">0dp</dimen>
 
     <!-- Preference activity side margins -->
     <dimen name="preference_screen_side_margin_material">0dp</dimen>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 987b291..56cf56d 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1449,9 +1449,8 @@
     <string name="permlab_bodySensors">body sensors (like heart rate monitors)
     </string>
     <!-- Description of the body sensors permission, listed so the user can decide whether to allow the application to access data from body sensors. [CHAR LIMIT=NONE] -->
-    <string name="permdesc_bodySensors" product="default">Allows the app to
-      access data from sensors you use to measure what’s happening inside your
-      body, such as heart rate.</string>
+    <string name="permdesc_bodySensors" product="default">Allows the app to access data from sensors
+    that monitor your physical condition, such as your heart rate.</string>
 
     <!-- Title of the read social stream permission, listed so the user can decide whether to allow the application to read information from the user's social stream. [CHAR LIMIT=30] -->
     <string name="permlab_readSocialStream" product="default">read your social stream</string>
@@ -2523,19 +2522,6 @@
     <!-- Shown when face unlock failed multiple times so we're just using the backup -->
     <string name="faceunlock_multiple_failures">Maximum Face Unlock attempts exceeded</string>
 
-    <!-- When the lock screen is showing and the phone plugged in, and the battery
-         is not fully charged, show the current charge %.  -->
-    <string name="lockscreen_plugged_in">Charging, <xliff:g id="number">%d</xliff:g><xliff:g id="percent">%%</xliff:g></string>
-    <!-- When the lock screen is showing, the phone is plugged in and the battery is fully
-         charged, say that it is charged. -->
-    <string name="lockscreen_charged">Charged</string>
-    <!-- A short representation of charging information, e.g "34%" -->
-    <string name="lockscreen_battery_short"><xliff:g id="number">%d</xliff:g><xliff:g id="percent">%%</xliff:g></string>
-
-    <!-- When the lock screen is showing and the battery is low, warn user to plug
-         in the phone soon. -->
-    <string name="lockscreen_low_battery">Connect your charger.</string>
-
     <!-- Shown in the lock screen when there is no SIM card. -->
     <string name="lockscreen_missing_sim_message_short">No SIM card</string>
     <!-- Shown in the lock screen when there is no SIM card. -->
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index f9fca00..6e03b3d 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -320,49 +320,47 @@
         <item name="textColor">?attr/textColorPrimaryDisableOnly</item>
     </style>
 
-    <style name="TextAppearance.Material.Widget.ActionMode"/>
-    <style name="TextAppearance.Material.Widget.ActionMode.Title"
-           parent="TextAppearance.Material.Title">
-        <item name="textSize">@dimen/text_size_title_material_toolbar</item>
-    </style>
-    <style name="TextAppearance.Material.Widget.ActionMode.Title.Inverse"
-           parent="TextAppearance.Material.Title.Inverse">
-        <item name="textSize">@dimen/text_size_title_material_toolbar</item>
-    </style>
-    <style name="TextAppearance.Material.Widget.ActionMode.Subtitle"
-           parent="TextAppearance.Material.Subhead">
-        <item name="textSize">@dimen/text_size_subtitle_material_toolbar</item>
-    </style>
-    <style name="TextAppearance.Material.Widget.ActionMode.Subtitle.Inverse"
-           parent="TextAppearance.Material.Subhead.Inverse">
-        <item name="textSize">@dimen/text_size_subtitle_material_toolbar</item>
-    </style>
     <style name="TextAppearance.Material.Widget.ActionBar.Title"
            parent="TextAppearance.Material.Title">
         <item name="textSize">@dimen/text_size_title_material_toolbar</item>
+        <item name="textColor">?attr/textColorPrimary</item>
     </style>
     <style name="TextAppearance.Material.Widget.ActionBar.Title.Inverse"
            parent="TextAppearance.Material.Title.Inverse">
         <item name="textSize">@dimen/text_size_title_material_toolbar</item>
+        <item name="textColor">?attr/textColorPrimaryInverse</item>
     </style>
     <style name="TextAppearance.Material.Widget.ActionBar.Subtitle"
            parent="TextAppearance.Material.Subhead">
         <item name="textSize">@dimen/text_size_subtitle_material_toolbar</item>
+        <item name="textColor">?attr/textColorSecondary</item>
     </style>
     <style name="TextAppearance.Material.Widget.ActionBar.Subtitle.Inverse"
            parent="TextAppearance.Material.Subhead.Inverse">
         <item name="textSize">@dimen/text_size_subtitle_material_toolbar</item>
+        <item name="textColor">?attr/textColorSecondaryInverse</item>
     </style>
 
-    <style name="TextAppearance.Material.Widget.ActionBar.Menu" parent="TextAppearance.Material.Menu">
+    <style name="TextAppearance.Material.Widget.ActionBar.Menu"
+           parent="TextAppearance.Material.Menu">
+        <item name="textColor">?attr/actionMenuTextColor</item>
+        <item name="textAllCaps">@bool/config_actionMenuItemAllCaps</item>
+    </style>
+    <style name="TextAppearance.Material.Widget.ActionBar.Menu.Inverse"
+           parent="TextAppearance.Material.Menu.Inverse">
         <item name="textColor">?attr/actionMenuTextColor</item>
         <item name="textAllCaps">@bool/config_actionMenuItemAllCaps</item>
     </style>
 
-    <style name="TextAppearance.Material.Widget.ActionBar.Menu.Inverse" parent="TextAppearance.Material.Menu.Inverse">
-        <item name="textColor">?attr/actionMenuTextColor</item>
-        <item name="textAllCaps">@bool/config_actionMenuItemAllCaps</item>
-    </style>
+    <style name="TextAppearance.Material.Widget.ActionMode"/>
+    <style name="TextAppearance.Material.Widget.ActionMode.Title"
+           parent="TextAppearance.Material.Widget.ActionBar.Title" />
+    <style name="TextAppearance.Material.Widget.ActionMode.Title.Inverse"
+           parent="TextAppearance.Material.Widget.ActionBar.Title.Inverse" />
+    <style name="TextAppearance.Material.Widget.ActionMode.Subtitle"
+           parent="TextAppearance.Material.Widget.ActionBar.Subtitle" />
+    <style name="TextAppearance.Material.Widget.ActionMode.Subtitle.Inverse"
+           parent="TextAppearance.Material.Widget.ActionBar.Subtitle.Inverse" />
 
     <style name="TextAppearance.Material.Widget.Toolbar.Title"
            parent="TextAppearance.Material.Widget.ActionBar.Title" />
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 47978eb..a11fdbc 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1791,6 +1791,7 @@
   <java-symbol type="drawable" name="notification_icon_legacy_bg" />
   <java-symbol type="color" name="notification_media_primary_color" />
   <java-symbol type="color" name="notification_media_secondary_color" />
+  <java-symbol type="color" name="notification_progress_background_color" />
   <java-symbol type="id" name="media_actions" />
 
     <!-- From SystemUI -->
@@ -1944,7 +1945,9 @@
   <java-symbol type="id" name="time_header" />
   <java-symbol type="id" name="hours" />
   <java-symbol type="id" name="minutes" />
-  <java-symbol type="id" name="ampm_label" />
+  <java-symbol type="id" name="ampm_layout" />
+  <java-symbol type="id" name="am_label" />
+  <java-symbol type="id" name="pm_label" />
   <java-symbol type="id" name="radial_picker" />
   <java-symbol type="id" name="separator" />
   <java-symbol type="id" name="date_picker_header" />
@@ -2037,8 +2040,10 @@
   <java-symbol type="attr" name="preferenceFragmentStyle" />
   <java-symbol type="bool" name="skipHoldBeforeMerge" />
   <java-symbol type="bool" name="imsServiceAllowTurnOff" />
-  <java-symbol type="bool" name="config_device_volte_vt_available" />
-  <java-symbol type="bool" name="config_carrier_volte_vt_available" />
+  <java-symbol type="bool" name="config_device_volte_available" />
+  <java-symbol type="bool" name="config_carrier_volte_available" />
+  <java-symbol type="bool" name="config_device_vt_available" />
+  <java-symbol type="bool" name="config_carrier_vt_available" />
   <java-symbol type="bool" name="useImsAlwaysForEmergencyCall" />
   <java-symbol type="attr" name="touchscreenBlocksFocus" />
   <java-symbol type="layout" name="resolver_list_with_default" />
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index b51974e..1864f89 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -781,9 +781,6 @@
         <item name="textCheckMark">@drawable/indicator_check_mark_light</item>
         <item name="textCheckMarkInverse">@drawable/indicator_check_mark_dark</item>
 
-        <item name="fastScrollPreviewBackgroundLeft">@drawable/fastscroll_label_left_holo_light</item>
-        <item name="fastScrollPreviewBackgroundRight">@drawable/fastscroll_label_right_holo_light</item>
-
         <item name="colorControlNormal">?attr/textColorSecondary</item>
         <item name="colorControlHighlight">@color/ripple_material_light</item>
         <item name="colorButtonNormal">@color/btn_default_material_light</item>
@@ -819,9 +816,6 @@
         <item name="textCheckMark">@drawable/indicator_check_mark_dark</item>
         <item name="textCheckMarkInverse">@drawable/indicator_check_mark_light</item>
 
-        <item name="fastScrollPreviewBackgroundLeft">@drawable/fastscroll_label_left_holo_dark</item>
-        <item name="fastScrollPreviewBackgroundRight">@drawable/fastscroll_label_right_holo_dark</item>
-
         <item name="colorControlNormal">?attr/textColorSecondary</item>
         <item name="colorControlHighlight">@color/ripple_material_dark</item>
         <item name="colorButtonNormal">@color/btn_default_material_dark</item>
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index b524177..226717e 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1252,6 +1252,13 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="android.content.res.ResourceCacheActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
     </application>
 
     <instrumentation android:name="android.test.InstrumentationTestRunner"
diff --git a/core/tests/coretests/res/anim/reset_state_anim.xml b/core/tests/coretests/res/anim/reset_state_anim.xml
index 918d0a3..4bbbe62 100644
--- a/core/tests/coretests/res/anim/reset_state_anim.xml
+++ b/core/tests/coretests/res/anim/reset_state_anim.xml
@@ -1,4 +1,18 @@
 <?xml version="1.0"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
 <set xmlns:android="http://schemas.android.com/apk/res/android">
     <objectAnimator android:propertyName="x" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
     <objectAnimator android:propertyName="y" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
diff --git a/core/tests/coretests/res/anim/test_animator.xml b/core/tests/coretests/res/anim/test_animator.xml
new file mode 100644
index 0000000..49afc3f
--- /dev/null
+++ b/core/tests/coretests/res/anim/test_animator.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <!-- if you change this, you should also change AnimatorInflaterTest#testLoadAnimator-->
+    <objectAnimator android:propertyName="x" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+    <objectAnimator android:propertyName="y" android:duration="100" android:valueTo="1" android:valueType="floatType"/>
+    <objectAnimator android:propertyName="left" android:duration="100" android:valueTo="2" android:valueType="intType"/>
+</set>
\ No newline at end of file
diff --git a/core/tests/coretests/res/anim/test_state_anim.xml b/core/tests/coretests/res/anim/test_state_anim.xml
index 9e08f68..b6a4822 100644
--- a/core/tests/coretests/res/anim/test_state_anim.xml
+++ b/core/tests/coretests/res/anim/test_state_anim.xml
@@ -1,4 +1,18 @@
 <?xml version="1.0"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_pressed="true">
         <set>
diff --git a/core/tests/coretests/res/values-land/dimens.xml b/core/tests/coretests/res/values-land/dimens.xml
new file mode 100644
index 0000000..1ee9f1d
--- /dev/null
+++ b/core/tests/coretests/res/values-land/dimens.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<resources>
+    <dimen name="resource_cache_test_orientation_dependent">3dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/core/tests/coretests/res/values/dimens.xml b/core/tests/coretests/res/values/dimens.xml
new file mode 100644
index 0000000..00fc414
--- /dev/null
+++ b/core/tests/coretests/res/values/dimens.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<resources>
+    <dimen name="resource_cache_test_generic">10dp</dimen>
+    <dimen name="resource_cache_test_orientation_dependent">20dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/animation/AnimatorInflaterTest.java b/core/tests/coretests/src/android/animation/AnimatorInflaterTest.java
new file mode 100644
index 0000000..3c81853
--- /dev/null
+++ b/core/tests/coretests/src/android/animation/AnimatorInflaterTest.java
@@ -0,0 +1,61 @@
+/*
+* Copyright (C) 2014 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package android.animation;
+
+import android.test.ActivityInstrumentationTestCase2;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import com.android.frameworks.coretests.R;
+
+public class AnimatorInflaterTest extends ActivityInstrumentationTestCase2<BasicAnimatorActivity>  {
+    Set<Integer> identityHashes = new HashSet<Integer>();
+
+    public AnimatorInflaterTest() {
+        super(BasicAnimatorActivity.class);
+    }
+
+    private void assertUnique(Object object) {
+        assertUnique(object, "");
+    }
+
+    private void assertUnique(Object object, String msg) {
+        final int code = System.identityHashCode(object);
+        assertTrue("object should be unique " + msg + ", obj:" + object, identityHashes.add(code));
+
+    }
+
+    public void testLoadStateListAnimator() {
+        StateListAnimator sla1 = AnimatorInflater.loadStateListAnimator(getActivity(),
+                R.anim.test_state_anim);
+        sla1.setTarget(getActivity().mAnimatingButton);
+        StateListAnimator sla2 = AnimatorInflater.loadStateListAnimator(getActivity(),
+                R.anim.test_state_anim);
+        assertNull(sla2.getTarget());
+        for (StateListAnimator sla : new StateListAnimator[]{sla1, sla2}) {
+            assertUnique(sla);
+            assertEquals(3, sla.getTuples().size());
+            for (StateListAnimator.Tuple tuple : sla.getTuples()) {
+                assertUnique(tuple);
+                assertUnique(tuple.getAnimator());
+            }
+        }
+    }
+
+}
diff --git a/core/tests/coretests/src/android/animation/BasicAnimatorActivity.java b/core/tests/coretests/src/android/animation/BasicAnimatorActivity.java
index 93808d9..6bcf8fc 100644
--- a/core/tests/coretests/src/android/animation/BasicAnimatorActivity.java
+++ b/core/tests/coretests/src/android/animation/BasicAnimatorActivity.java
@@ -19,11 +19,14 @@
 
 import android.app.Activity;
 import android.os.Bundle;
+import android.widget.Button;
 
 public class BasicAnimatorActivity extends Activity {
+    public Button mAnimatingButton;
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.animator_basic);
+        mAnimatingButton = (Button) findViewById(R.id.animatingButton);
     }
 }
diff --git a/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java b/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java
new file mode 100644
index 0000000..e9fd5fb
--- /dev/null
+++ b/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.res;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.TypedValue;
+
+import com.android.frameworks.coretests.R;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+public class ConfigurationBoundResourceCacheTest
+        extends ActivityInstrumentationTestCase2<ResourceCacheActivity> {
+
+    ConfigurationBoundResourceCache<Float> mCache;
+
+    Method mCalcConfigChanges;
+
+    public ConfigurationBoundResourceCacheTest() {
+        super(ResourceCacheActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mCache = new ConfigurationBoundResourceCache<Float>(getActivity().getResources());
+    }
+
+    public void testGetEmpty() {
+        assertNull(mCache.get(-1, null));
+    }
+
+    public void testSetGet() {
+        mCache.put(1, null, new DummyFloatConstantState(5f));
+        assertEquals(5f, mCache.get(1, null));
+        assertNotSame(5f, mCache.get(1, null));
+        assertEquals(null, mCache.get(1, getActivity().getTheme()));
+    }
+
+    public void testSetGetThemed() {
+        mCache.put(1, getActivity().getTheme(), new DummyFloatConstantState(5f));
+        assertEquals(null, mCache.get(1, null));
+        assertEquals(5f, mCache.get(1, getActivity().getTheme()));
+        assertNotSame(5f, mCache.get(1, getActivity().getTheme()));
+    }
+
+    public void testMultiThreadPutGet() {
+        mCache.put(1, getActivity().getTheme(), new DummyFloatConstantState(5f));
+        mCache.put(1, null, new DummyFloatConstantState(10f));
+        assertEquals(10f, mCache.get(1, null));
+        assertNotSame(10f, mCache.get(1, null));
+        assertEquals(5f, mCache.get(1, getActivity().getTheme()));
+        assertNotSame(5f, mCache.get(1, getActivity().getTheme()));
+    }
+
+    public void testVoidConfigChange()
+            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+        TypedValue staticValue = new TypedValue();
+        long key = 3L;
+        final Resources res = getActivity().getResources();
+        res.getValue(R.dimen.resource_cache_test_generic, staticValue, true);
+        float staticDim = TypedValue.complexToDimension(staticValue.data, res.getDisplayMetrics());
+        mCache.put(key, getActivity().getTheme(),
+                new DummyFloatConstantState(staticDim, staticValue.changingConfigurations));
+        final Configuration cfg = res.getConfiguration();
+        Configuration newCnf = new Configuration(cfg);
+        newCnf.orientation = cfg.orientation == Configuration.ORIENTATION_LANDSCAPE ?
+                Configuration.ORIENTATION_PORTRAIT
+                : Configuration.ORIENTATION_LANDSCAPE;
+        int changes = calcConfigChanges(res, newCnf);
+        assertEquals(staticDim, mCache.get(key, getActivity().getTheme()));
+        mCache.onConfigurationChange(changes);
+        assertEquals(staticDim, mCache.get(key, getActivity().getTheme()));
+    }
+
+    public void testEffectiveConfigChange()
+            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+        TypedValue changingValue = new TypedValue();
+        long key = 4L;
+        final Resources res = getActivity().getResources();
+        res.getValue(R.dimen.resource_cache_test_orientation_dependent, changingValue, true);
+        float changingDim = TypedValue.complexToDimension(changingValue.data,
+                res.getDisplayMetrics());
+        mCache.put(key, getActivity().getTheme(),
+                new DummyFloatConstantState(changingDim, changingValue.changingConfigurations));
+
+        final Configuration cfg = res.getConfiguration();
+        Configuration newCnf = new Configuration(cfg);
+        newCnf.orientation = cfg.orientation == Configuration.ORIENTATION_LANDSCAPE ?
+                Configuration.ORIENTATION_PORTRAIT
+                : Configuration.ORIENTATION_LANDSCAPE;
+        int changes = calcConfigChanges(res, newCnf);
+        assertEquals(changingDim, mCache.get(key, getActivity().getTheme()));
+        mCache.onConfigurationChange(changes);
+        assertNull(mCache.get(key, getActivity().getTheme()));
+    }
+
+    public void testConfigChangeMultipleResources()
+            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+        TypedValue staticValue = new TypedValue();
+        TypedValue changingValue = new TypedValue();
+        final Resources res = getActivity().getResources();
+        res.getValue(R.dimen.resource_cache_test_generic, staticValue, true);
+        res.getValue(R.dimen.resource_cache_test_orientation_dependent, changingValue, true);
+        float staticDim = TypedValue.complexToDimension(staticValue.data, res.getDisplayMetrics());
+        float changingDim = TypedValue.complexToDimension(changingValue.data,
+                res.getDisplayMetrics());
+        mCache.put(R.dimen.resource_cache_test_generic, getActivity().getTheme(),
+                new DummyFloatConstantState(staticDim, staticValue.changingConfigurations));
+        mCache.put(R.dimen.resource_cache_test_orientation_dependent, getActivity().getTheme(),
+                new DummyFloatConstantState(changingDim, changingValue.changingConfigurations));
+        final Configuration cfg = res.getConfiguration();
+        Configuration newCnf = new Configuration(cfg);
+        newCnf.orientation = cfg.orientation == Configuration.ORIENTATION_LANDSCAPE ?
+                Configuration.ORIENTATION_PORTRAIT
+                : Configuration.ORIENTATION_LANDSCAPE;
+        int changes = calcConfigChanges(res, newCnf);
+        assertEquals(staticDim, mCache.get(R.dimen.resource_cache_test_generic,
+                getActivity().getTheme()));
+        assertEquals(changingDim, mCache.get(R.dimen.resource_cache_test_orientation_dependent,
+                getActivity().getTheme()));
+        mCache.onConfigurationChange(changes);
+        assertEquals(staticDim, mCache.get(R.dimen.resource_cache_test_generic,
+                getActivity().getTheme()));
+        assertNull(mCache.get(R.dimen.resource_cache_test_orientation_dependent,
+                getActivity().getTheme()));
+    }
+
+    public void testConfigChangeMultipleThemes()
+            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+        TypedValue[] staticValues = new TypedValue[]{new TypedValue(), new TypedValue()};
+        TypedValue[] changingValues = new TypedValue[]{new TypedValue(), new TypedValue()};
+        float staticDim = 0;
+        float changingDim = 0;
+        final Resources res = getActivity().getResources();
+        for (int i = 0; i < 2; i++) {
+            res.getValue(R.dimen.resource_cache_test_generic, staticValues[i], true);
+            staticDim = TypedValue
+                    .complexToDimension(staticValues[i].data, res.getDisplayMetrics());
+
+            res.getValue(R.dimen.resource_cache_test_orientation_dependent, changingValues[i],
+                    true);
+            changingDim = TypedValue.complexToDimension(changingValues[i].data,
+                    res.getDisplayMetrics());
+            final Resources.Theme theme = i == 0 ? getActivity().getTheme() : null;
+            mCache.put(R.dimen.resource_cache_test_generic, theme,
+                    new DummyFloatConstantState(staticDim, staticValues[i].changingConfigurations));
+            mCache.put(R.dimen.resource_cache_test_orientation_dependent, theme,
+                    new DummyFloatConstantState(changingDim,
+                            changingValues[i].changingConfigurations));
+        }
+        final Configuration cfg = res.getConfiguration();
+        Configuration newCnf = new Configuration(cfg);
+        newCnf.orientation = cfg.orientation == Configuration.ORIENTATION_LANDSCAPE ?
+                Configuration.ORIENTATION_PORTRAIT
+                : Configuration.ORIENTATION_LANDSCAPE;
+        int changes = calcConfigChanges(res, newCnf);
+        for (int i = 0; i < 2; i++) {
+            final Resources.Theme theme = i == 0 ? getActivity().getTheme() : null;
+            assertEquals(staticDim, mCache.get(R.dimen.resource_cache_test_generic, theme));
+            assertEquals(changingDim,
+                    mCache.get(R.dimen.resource_cache_test_orientation_dependent, theme));
+        }
+        mCache.onConfigurationChange(changes);
+        for (int i = 0; i < 2; i++) {
+            final Resources.Theme theme = i == 0 ? getActivity().getTheme() : null;
+            assertEquals(staticDim, mCache.get(R.dimen.resource_cache_test_generic, theme));
+            assertNull(mCache.get(R.dimen.resource_cache_test_orientation_dependent, theme));
+        }
+    }
+
+    private int calcConfigChanges(Resources resources, Configuration configuration)
+            throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+        if (mCalcConfigChanges == null) {
+            mCalcConfigChanges = Resources.class.getDeclaredMethod("calcConfigChanges",
+                    Configuration.class);
+            mCalcConfigChanges.setAccessible(true);
+        }
+        return (Integer) mCalcConfigChanges.invoke(resources, configuration);
+
+    }
+
+    static class DummyFloatConstantState extends
+            ConstantState<Float> {
+
+        final Float mObj;
+
+        int mChangingConf = 0;
+
+        DummyFloatConstantState(Float obj) {
+            mObj = obj;
+        }
+
+        DummyFloatConstantState(Float obj, int changingConf) {
+            mObj = obj;
+            mChangingConf = changingConf;
+        }
+
+        @Override
+        public int getChangingConfigurations() {
+            return mChangingConf;
+        }
+
+        @Override
+        public Float newInstance() {
+            return new Float(mObj);
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/content/res/ResourceCacheActivity.java b/core/tests/coretests/src/android/content/res/ResourceCacheActivity.java
new file mode 100644
index 0000000..f37e549
--- /dev/null
+++ b/core/tests/coretests/src/android/content/res/ResourceCacheActivity.java
@@ -0,0 +1,37 @@
+/*
+* Copyright (C) 2014 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package android.content.res;
+
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.os.Bundle;
+
+import java.lang.ref.WeakReference;
+
+public class ResourceCacheActivity extends Activity {
+    static WeakReference<ResourceCacheActivity> lastCreatedInstance;
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        lastCreatedInstance = new WeakReference<ResourceCacheActivity>(this);
+    }
+
+    public static ResourceCacheActivity getLastCreatedInstance() {
+        return lastCreatedInstance == null ? null : lastCreatedInstance.get();
+    }
+}
diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
index 9fb3fb4..c2e93a7 100644
--- a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
@@ -313,6 +313,26 @@
         }
     }
 
+    @Override
+    public void applyTheme(Theme t) {
+        super.applyTheme(t);
+
+        final AnimatedRotateState state = mState;
+        if (state == null) {
+            return;
+        }
+
+        if (state.mDrawable != null) {
+            state.mDrawable.applyTheme(t);
+        }
+    }
+
+    @Override
+    public boolean canApplyTheme() {
+        final AnimatedRotateState state = mState;
+        return state != null && state.mDrawable != null && state.mDrawable.canApplyTheme();
+    }
+
     public void setFramesCount(int framesCount) {
         mState.mFramesCount = framesCount;
         mIncrement = 360.0f / mState.mFramesCount;
@@ -331,6 +351,15 @@
         return this;
     }
 
+    /**
+     * @hide
+     */
+    public void clearMutated() {
+        super.clearMutated();
+        mState.mDrawable.clearMutated();
+        mMutated = false;
+    }
+
     final static class AnimatedRotateState extends Drawable.ConstantState {
         Drawable mDrawable;
 
diff --git a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
index cb09bbf..849faec 100644
--- a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
@@ -139,27 +139,15 @@
 
     @Override
     protected boolean onStateChange(int[] stateSet) {
-        final int keyframeIndex = mState.indexOfKeyframe(stateSet);
-        if (keyframeIndex == getCurrentIndex()) {
-            // Propagate state change to current keyframe.
-            final Drawable current = getCurrent();
-            if (current != null) {
-                return current.setState(stateSet);
-            }
-            return false;
-        }
+        // If we're not already at the target index, either attempt to find a
+        // valid transition to it or jump directly there.
+        final int targetIndex = mState.indexOfKeyframe(stateSet);
+        final boolean changedIndex = targetIndex != getCurrentIndex()
+                && (selectTransition(targetIndex) || selectDrawable(targetIndex));
 
-        // Attempt to find a valid transition to the keyframe.
-        if (selectTransition(keyframeIndex)) {
-            return true;
-        }
-
-        // No valid transition, attempt to jump directly to the keyframe.
-        if (selectDrawable(keyframeIndex)) {
-            return true;
-        }
-
-        return super.onStateChange(stateSet);
+        // Always call super.onStateChanged() to propagate the state change to
+        // the current drawable.
+        return super.onStateChange(stateSet) || changedIndex;
     }
 
     private boolean selectTransition(int toIndex) {
@@ -507,6 +495,14 @@
         return this;
     }
 
+    /**
+     * @hide
+     */
+    public void clearMutated() {
+        super.clearMutated();
+        mMutated = false;
+    }
+
     static class AnimatedStateListState extends StateListState {
         private static final int REVERSE_SHIFT = 32;
         private static final int REVERSE_MASK = 0x1;
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index ad0b415..a904067 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -16,7 +16,6 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorInflater;
-import android.animation.ValueAnimator;
 import android.annotation.NonNull;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
@@ -137,15 +136,11 @@
     private boolean mMutated;
 
     public AnimatedVectorDrawable() {
-        mAnimatedVectorState = new AnimatedVectorDrawableState(null);
+        this(null, null);
     }
 
-    private AnimatedVectorDrawable(AnimatedVectorDrawableState state, Resources res,
-            Theme theme) {
-        mAnimatedVectorState = new AnimatedVectorDrawableState(state);
-        if (theme != null && canApplyTheme()) {
-            applyTheme(theme);
-        }
+    private AnimatedVectorDrawable(AnimatedVectorDrawableState state, Resources res) {
+        mAnimatedVectorState = new AnimatedVectorDrawableState(state, mCallback, res);
     }
 
     @Override
@@ -157,6 +152,15 @@
         return this;
     }
 
+    /**
+     * @hide
+     */
+    public void clearMutated() {
+        super.clearMutated();
+        mAnimatedVectorState.mVectorDrawable.clearMutated();
+        mMutated = false;
+    }
+
     @Override
     public ConstantState getConstantState() {
         mAnimatedVectorState.mChangingConfigurations = getChangingConfigurations();
@@ -281,7 +285,11 @@
                         VectorDrawable vectorDrawable = (VectorDrawable) res.getDrawable(
                                 drawableRes, theme).mutate();
                         vectorDrawable.setAllowCaching(false);
+                        vectorDrawable.setCallback(mCallback);
                         pathErrorScale = vectorDrawable.getPixelSize();
+                        if (mAnimatedVectorState.mVectorDrawable != null) {
+                            mAnimatedVectorState.mVectorDrawable.setCallback(null);
+                        }
                         mAnimatedVectorState.mVectorDrawable = vectorDrawable;
                     }
                     a.recycle();
@@ -329,14 +337,22 @@
         ArrayList<Animator> mAnimators;
         ArrayMap<Animator, String> mTargetNameMap;
 
-        public AnimatedVectorDrawableState(AnimatedVectorDrawableState copy) {
+        public AnimatedVectorDrawableState(AnimatedVectorDrawableState copy,
+                Callback owner, Resources res) {
             if (copy != null) {
                 mChangingConfigurations = copy.mChangingConfigurations;
                 if (copy.mVectorDrawable != null) {
-                    mVectorDrawable = (VectorDrawable) copy.mVectorDrawable.getConstantState().newDrawable();
-                    mVectorDrawable.mutate();
-                    mVectorDrawable.setAllowCaching(false);
+                    final ConstantState cs = copy.mVectorDrawable.getConstantState();
+                    if (res != null) {
+                        mVectorDrawable = (VectorDrawable) cs.newDrawable(res);
+                    } else {
+                        mVectorDrawable = (VectorDrawable) cs.newDrawable();
+                    }
+                    mVectorDrawable = (VectorDrawable) mVectorDrawable.mutate();
+                    mVectorDrawable.setCallback(owner);
+                    mVectorDrawable.setLayoutDirection(copy.mVectorDrawable.getLayoutDirection());
                     mVectorDrawable.setBounds(copy.mVectorDrawable.getBounds());
+                    mVectorDrawable.setAllowCaching(false);
                 }
                 if (copy.mAnimators != null) {
                     final int numAnimators = copy.mAnimators.size();
@@ -359,17 +375,12 @@
 
         @Override
         public Drawable newDrawable() {
-            return new AnimatedVectorDrawable(this, null, null);
+            return new AnimatedVectorDrawable(this, null);
         }
 
         @Override
         public Drawable newDrawable(Resources res) {
-            return new AnimatedVectorDrawable(this, res, null);
-        }
-
-        @Override
-        public Drawable newDrawable(Resources res, Theme theme) {
-            return new AnimatedVectorDrawable(this, res, theme);
+            return new AnimatedVectorDrawable(this, res);
         }
 
         @Override
@@ -473,4 +484,21 @@
         }
         return true;
     }
+
+    private final Callback mCallback = new Callback() {
+        @Override
+        public void invalidateDrawable(Drawable who) {
+            invalidateSelf();
+        }
+
+        @Override
+        public void scheduleDrawable(Drawable who, Runnable what, long when) {
+            scheduleSelf(what, when);
+        }
+
+        @Override
+        public void unscheduleDrawable(Drawable who, Runnable what) {
+            unscheduleSelf(what);
+        }
+    };
 }
diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java
index 9a9fd82..c730a20 100644
--- a/graphics/java/android/graphics/drawable/AnimationDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java
@@ -347,6 +347,14 @@
         return this;
     }
 
+    /**
+     * @hide
+     */
+    public void clearMutated() {
+        super.clearMutated();
+        mMutated = false;
+    }
+
     private final static class AnimationState extends DrawableContainerState {
         private int[] mDurations;
         private boolean mOneShot;
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index cf6be48..79ac651 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -132,7 +132,7 @@
      */
     @Deprecated
     public BitmapDrawable(Bitmap bitmap) {
-        this(new BitmapState(bitmap), null, null);
+        this(new BitmapState(bitmap), null);
     }
 
     /**
@@ -140,7 +140,7 @@
      * the display metrics of the resources.
      */
     public BitmapDrawable(Resources res, Bitmap bitmap) {
-        this(new BitmapState(bitmap), res, null);
+        this(new BitmapState(bitmap), res);
         mBitmapState.mTargetDensity = mTargetDensity;
     }
 
@@ -151,7 +151,7 @@
      */
     @Deprecated
     public BitmapDrawable(String filepath) {
-        this(new BitmapState(BitmapFactory.decodeFile(filepath)), null, null);
+        this(new BitmapState(BitmapFactory.decodeFile(filepath)), null);
         if (mBitmapState.mBitmap == null) {
             android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
         }
@@ -162,7 +162,7 @@
      */
     @SuppressWarnings("unused")
     public BitmapDrawable(Resources res, String filepath) {
-        this(new BitmapState(BitmapFactory.decodeFile(filepath)), null, null);
+        this(new BitmapState(BitmapFactory.decodeFile(filepath)), null);
         mBitmapState.mTargetDensity = mTargetDensity;
         if (mBitmapState.mBitmap == null) {
             android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
@@ -176,7 +176,7 @@
      */
     @Deprecated
     public BitmapDrawable(java.io.InputStream is) {
-        this(new BitmapState(BitmapFactory.decodeStream(is)), null, null);
+        this(new BitmapState(BitmapFactory.decodeStream(is)), null);
         if (mBitmapState.mBitmap == null) {
             android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
         }
@@ -187,7 +187,7 @@
      */
     @SuppressWarnings("unused")
     public BitmapDrawable(Resources res, java.io.InputStream is) {
-        this(new BitmapState(BitmapFactory.decodeStream(is)), null, null);
+        this(new BitmapState(BitmapFactory.decodeStream(is)), null);
         mBitmapState.mTargetDensity = mTargetDensity;
         if (mBitmapState.mBitmap == null) {
             android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
@@ -684,6 +684,14 @@
         return this;
     }
 
+    /**
+     * @hide
+     */
+    public void clearMutated() {
+        super.clearMutated();
+        mMutated = false;
+    }
+
     @Override
     protected boolean onStateChange(int[] stateSet) {
         final BitmapState state = mBitmapState;
@@ -911,17 +919,12 @@
 
         @Override
         public Drawable newDrawable() {
-            return new BitmapDrawable(this, null, null);
+            return new BitmapDrawable(this, null);
         }
 
         @Override
         public Drawable newDrawable(Resources res) {
-            return new BitmapDrawable(this, res, null);
-        }
-
-        @Override
-        public Drawable newDrawable(Resources res, Theme theme) {
-            return new BitmapDrawable(this, res, theme);
+            return new BitmapDrawable(this, res);
         }
 
         @Override
@@ -934,16 +937,10 @@
      * The one constructor to rule them all. This is called by all public
      * constructors to set the state and initialize local properties.
      */
-    private BitmapDrawable(BitmapState state, Resources res, Theme theme) {
-        if (theme != null && state.canApplyTheme()) {
-            // If we need to apply a theme, implicitly mutate.
-            mBitmapState = new BitmapState(state);
-            applyTheme(theme);
-        } else {
-            mBitmapState = state;
-        }
+    private BitmapDrawable(BitmapState state, Resources res) {
+        mBitmapState = state;
 
-        initializeWithState(state, res);
+        initializeWithState(mBitmapState, res);
     }
 
     /**
diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java
index 40711cf..669cef2 100644
--- a/graphics/java/android/graphics/drawable/ClipDrawable.java
+++ b/graphics/java/android/graphics/drawable/ClipDrawable.java
@@ -55,6 +55,8 @@
     public static final int HORIZONTAL = 1;
     public static final int VERTICAL = 2;
 
+    private boolean mMutated;
+
     ClipDrawable() {
         this(null, null);
     }
@@ -112,6 +114,26 @@
         dr.setCallback(this);
     }
 
+    @Override
+    public void applyTheme(Theme t) {
+        super.applyTheme(t);
+
+        final ClipState state = mClipState;
+        if (state == null) {
+            return;
+        }
+
+        if (state.mDrawable != null) {
+            state.mDrawable.applyTheme(t);
+        }
+    }
+
+    @Override
+    public boolean canApplyTheme() {
+        final ClipState state = mClipState;
+        return state != null && state.mDrawable != null && state.mDrawable.canApplyTheme();
+    }
+
     // overrides from Drawable.Callback
 
     @Override
@@ -268,6 +290,24 @@
         super.setLayoutDirection(layoutDirection);
     }
 
+    @Override
+    public Drawable mutate() {
+        if (!mMutated && super.mutate() == this) {
+            mClipState.mDrawable.mutate();
+            mMutated = true;
+        }
+        return this;
+    }
+
+    /**
+     * @hide
+     */
+    public void clearMutated() {
+        super.clearMutated();
+        mClipState.mDrawable.clearMutated();
+        mMutated = false;
+    }
+
     final static class ClipState extends ConstantState {
         Drawable mDrawable;
         int mChangingConfigurations;
diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java
index 1253c46..0f0c844 100644
--- a/graphics/java/android/graphics/drawable/ColorDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorDrawable.java
@@ -88,6 +88,14 @@
         return this;
     }
 
+    /**
+     * @hide
+     */
+    public void clearMutated() {
+        super.clearMutated();
+        mMutated = false;
+    }
+
     @Override
     public void draw(Canvas canvas) {
         final ColorFilter colorFilter = mPaint.getColorFilter();
@@ -291,17 +299,12 @@
 
         @Override
         public Drawable newDrawable() {
-            return new ColorDrawable(this, null, null);
+            return new ColorDrawable(this);
         }
 
         @Override
         public Drawable newDrawable(Resources res) {
-            return new ColorDrawable(this, res, null);
-        }
-
-        @Override
-        public Drawable newDrawable(Resources res, Theme theme) {
-            return new ColorDrawable(this, res, theme);
+            return new ColorDrawable(this);
         }
 
         @Override
@@ -310,14 +313,8 @@
         }
     }
 
-    private ColorDrawable(ColorState state, Resources res, Theme theme) {
-        if (theme != null && state.canApplyTheme()) {
-            mColorState = new ColorState(state);
-            applyTheme(theme);
-        } else {
-            mColorState = state;
-        }
-
+    private ColorDrawable(ColorState state) {
+        mColorState = state;
         mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
     }
 }
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 9ae788c..1fac5b6 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -917,6 +917,20 @@
     }
 
     /**
+     * Clears the mutated state, allowing this drawable to be cached and
+     * mutated again.
+     * <p>
+     * This is hidden because only framework drawables can be cached, so
+     * custom drawables don't need to support constant state, mutate(), or
+     * clearMutated().
+     *
+     * @hide
+     */
+    public void clearMutated() {
+        // Default implementation is no-op.
+    }
+
+    /**
      * Create a drawable from an inputstream
      */
     public static Drawable createFromStream(InputStream is, String srcName) {
@@ -1044,54 +1058,72 @@
         final Drawable drawable;
 
         final String name = parser.getName();
-        if (name.equals("selector")) {
-            drawable = new StateListDrawable();
-        } else if (name.equals("animated-selector")) {
-            drawable = new AnimatedStateListDrawable();
-        } else if (name.equals("level-list")) {
-            drawable = new LevelListDrawable();
-        } else if (name.equals("layer-list")) {
-            drawable = new LayerDrawable();
-        } else if (name.equals("transition")) {
-            drawable = new TransitionDrawable();
-        } else if (name.equals("ripple")) {
-            drawable = new RippleDrawable();
-        } else if (name.equals("color")) {
-            drawable = new ColorDrawable();
-        } else if (name.equals("shape")) {
-            drawable = new GradientDrawable();
-        } else if (name.equals("vector")) {
-            drawable = new VectorDrawable();
-        } else if (name.equals("animated-vector")) {
-            drawable = new AnimatedVectorDrawable();
-        } else if (name.equals("scale")) {
-            drawable = new ScaleDrawable();
-        } else if (name.equals("clip")) {
-            drawable = new ClipDrawable();
-        } else if (name.equals("rotate")) {
-            drawable = new RotateDrawable();
-        } else if (name.equals("animated-rotate")) {
-            drawable = new AnimatedRotateDrawable();
-        } else if (name.equals("animation-list")) {
-            drawable = new AnimationDrawable();
-        } else if (name.equals("inset")) {
-            drawable = new InsetDrawable();
-        } else if (name.equals("bitmap")) {
-            //noinspection deprecation
-            drawable = new BitmapDrawable(r);
-            if (r != null) {
-               ((BitmapDrawable) drawable).setTargetDensity(r.getDisplayMetrics());
-            }
-        } else if (name.equals("nine-patch")) {
-            drawable = new NinePatchDrawable();
-            if (r != null) {
-                ((NinePatchDrawable) drawable).setTargetDensity(r.getDisplayMetrics());
-             }
-        } else {
-            throw new XmlPullParserException(parser.getPositionDescription() +
-                    ": invalid drawable tag " + name);
-        }
+        switch (name) {
+            case "selector":
+                drawable = new StateListDrawable();
+                break;
+            case "animated-selector":
+                drawable = new AnimatedStateListDrawable();
+                break;
+            case "level-list":
+                drawable = new LevelListDrawable();
+                break;
+            case "layer-list":
+                drawable = new LayerDrawable();
+                break;
+            case "transition":
+                drawable = new TransitionDrawable();
+                break;
+            case "ripple":
+                drawable = new RippleDrawable();
+                break;
+            case "color":
+                drawable = new ColorDrawable();
+                break;
+            case "shape":
+                drawable = new GradientDrawable();
+                break;
+            case "vector":
+                drawable = new VectorDrawable();
+                break;
+            case "animated-vector":
+                drawable = new AnimatedVectorDrawable();
+                break;
+            case "scale":
+                drawable = new ScaleDrawable();
+                break;
+            case "clip":
+                drawable = new ClipDrawable();
+                break;
+            case "rotate":
+                drawable = new RotateDrawable();
+                break;
+            case "animated-rotate":
+                drawable = new AnimatedRotateDrawable();
+                break;
+            case "animation-list":
+                drawable = new AnimationDrawable();
+                break;
+            case "inset":
+                drawable = new InsetDrawable();
+                break;
+            case "bitmap":
+                drawable = new BitmapDrawable(r);
+                if (r != null) {
+                    ((BitmapDrawable) drawable).setTargetDensity(r.getDisplayMetrics());
+                }
+                break;
+            case "nine-patch":
+                drawable = new NinePatchDrawable();
+                if (r != null) {
+                    ((NinePatchDrawable) drawable).setTargetDensity(r.getDisplayMetrics());
+                }
+                break;
+            default:
+                throw new XmlPullParserException(parser.getPositionDescription() +
+                        ": invalid drawable tag " + name);
 
+        }
         drawable.inflate(r, parser, attrs, theme);
         return drawable;
     }
@@ -1202,7 +1234,7 @@
          * implemented for drawables that can have a theme applied.
          */
         public Drawable newDrawable(Resources res, Theme theme) {
-            return newDrawable();
+            return newDrawable(null);
         }
 
         /**
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 4a719fe..a903288 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -574,6 +574,15 @@
     }
 
     /**
+     * @hide
+     */
+    public void clearMutated() {
+        super.clearMutated();
+        mDrawableContainerState.clearMutated();
+        mMutated = false;
+    }
+
+    /**
      * A ConstantState that can contain several {@link Drawable}s.
      *
      * This class was made public to enable testing, and its visibility may change in a future
@@ -583,8 +592,6 @@
         final DrawableContainer mOwner;
         final Resources mRes;
 
-        Theme mTheme;
-
         SparseArray<ConstantStateFuture> mDrawableFutures;
 
         int mChangingConfigurations;
@@ -792,17 +799,17 @@
         }
 
         final void applyTheme(Theme theme) {
-            // No need to call createAllFutures, since future drawables will
-            // apply the theme when they are prepared.
-            final int N = mNumChildren;
-            final Drawable[] drawables = mDrawables;
-            for (int i = 0; i < N; i++) {
-                if (drawables[i] != null) {
-                    drawables[i].applyTheme(theme);
+            if (theme != null) {
+                createAllFutures();
+
+                final int N = mNumChildren;
+                final Drawable[] drawables = mDrawables;
+                for (int i = 0; i < N; i++) {
+                    if (drawables[i] != null && drawables[i].canApplyTheme()) {
+                        drawables[i].applyTheme(theme);
+                    }
                 }
             }
-
-            mTheme = theme;
         }
 
         @Override
@@ -840,6 +847,18 @@
             mMutated = true;
         }
 
+        final void clearMutated() {
+            final int N = mNumChildren;
+            final Drawable[] drawables = mDrawables;
+            for (int i = 0; i < N; i++) {
+                if (drawables[i] != null) {
+                    drawables[i].clearMutated();
+                }
+            }
+
+            mMutated = false;
+        }
+
         /**
          * A boolean value indicating whether to use the maximum padding value
          * of all frames in the set (false), or to use the padding value of the
@@ -1047,10 +1066,8 @@
                 final Drawable result;
                 if (state.mRes == null) {
                     result = mConstantState.newDrawable();
-                } else if (state.mTheme == null) {
-                    result = mConstantState.newDrawable(state.mRes);
                 } else {
-                    result = mConstantState.newDrawable(state.mRes, state.mTheme);
+                    result = mConstantState.newDrawable(state.mRes);
                 }
                 result.setLayoutDirection(state.mLayoutDirection);
                 result.setCallback(state.mOwner);
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index cd6297b..f6a78f1 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -29,6 +29,8 @@
 import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
 import android.graphics.RadialGradient;
 import android.graphics.Rect;
 import android.graphics.RectF;
@@ -134,6 +136,7 @@
     private Rect mPadding;
     private Paint mStrokePaint;   // optional, set by the caller
     private ColorFilter mColorFilter;   // optional, set by the caller
+    private PorterDuffColorFilter mTintFilter;
     private int mAlpha = 0xFF;  // modified by the caller
 
     private final Path mPath = new Path();
@@ -171,7 +174,7 @@
     }
 
     public GradientDrawable() {
-        this(new GradientState(Orientation.TOP_BOTTOM, null), null);
+        this(new GradientState(Orientation.TOP_BOTTOM, null));
     }
 
     /**
@@ -179,7 +182,7 @@
      * of colors for the gradient.
      */
     public GradientDrawable(Orientation orientation, int[] colors) {
-        this(new GradientState(orientation, colors), null);
+        this(new GradientState(orientation, colors));
     }
 
     @Override
@@ -523,13 +526,15 @@
                 mStrokePaint.getStrokeWidth() > 0;
         final boolean haveFill = currFillAlpha > 0;
         final GradientState st = mGradientState;
+        final ColorFilter colorFilter = mColorFilter != null ? mColorFilter : mTintFilter;
+
         /*  we need a layer iff we're drawing both a fill and stroke, and the
             stroke is non-opaque, and our shapetype actually supports
             fill+stroke. Otherwise we can just draw the stroke (if any) on top
             of the fill (if any) without worrying about blending artifacts.
          */
-         final boolean useLayer = haveStroke && haveFill && st.mShape != LINE &&
-                 currStrokeAlpha < 255 && (mAlpha < 255 || mColorFilter != null);
+        final boolean useLayer = haveStroke && haveFill && st.mShape != LINE &&
+                 currStrokeAlpha < 255 && (mAlpha < 255 || colorFilter != null);
 
         /*  Drawing with a layer is slower than direct drawing, but it
             allows us to apply paint effects like alpha and colorfilter to
@@ -544,7 +549,7 @@
             }
             mLayerPaint.setDither(st.mDither);
             mLayerPaint.setAlpha(mAlpha);
-            mLayerPaint.setColorFilter(mColorFilter);
+            mLayerPaint.setColorFilter(colorFilter);
 
             float rad = mStrokePaint.getStrokeWidth();
             canvas.saveLayer(mRect.left - rad, mRect.top - rad,
@@ -561,14 +566,14 @@
             */
             mFillPaint.setAlpha(currFillAlpha);
             mFillPaint.setDither(st.mDither);
-            mFillPaint.setColorFilter(mColorFilter);
-            if (mColorFilter != null && st.mColorStateList == null) {
+            mFillPaint.setColorFilter(colorFilter);
+            if (colorFilter != null && st.mColorStateList == null) {
                 mFillPaint.setColor(mAlpha << 24);
             }
             if (haveStroke) {
                 mStrokePaint.setAlpha(currStrokeAlpha);
                 mStrokePaint.setDither(st.mDither);
-                mStrokePaint.setColorFilter(mColorFilter);
+                mStrokePaint.setColorFilter(colorFilter);
             }
         }
 
@@ -593,7 +598,7 @@
                         canvas.drawRoundRect(mRect, rad, rad, mStrokePaint);
                     }
                 } else {
-                    if (mFillPaint.getColor() != 0 || mColorFilter != null ||
+                    if (mFillPaint.getColor() != 0 || colorFilter != null ||
                             mFillPaint.getShader() != null) {
                         canvas.drawRect(mRect, mFillPaint);
                     }
@@ -768,6 +773,11 @@
             }
         }
 
+        if (s.mTint != null && s.mTintMode != null) {
+            mTintFilter = updateTintFilter(mTintFilter, s.mTint, s.mTintMode);
+            invalidateSelf = true;
+        }
+
         if (invalidateSelf) {
             invalidateSelf();
             return true;
@@ -781,7 +791,8 @@
         final GradientState s = mGradientState;
         return super.isStateful()
                 || (s.mColorStateList != null && s.mColorStateList.isStateful())
-                || (s.mStrokeColorStateList != null && s.mStrokeColorStateList.isStateful());
+                || (s.mStrokeColorStateList != null && s.mStrokeColorStateList.isStateful())
+                || (s.mTint != null && s.mTint.isStateful());
     }
 
     @Override
@@ -824,6 +835,20 @@
     }
 
     @Override
+    public void setTintList(ColorStateList tint) {
+        mGradientState.mTint = tint;
+        mTintFilter = updateTintFilter(mTintFilter, tint, mGradientState.mTintMode);
+        invalidateSelf();
+    }
+
+    @Override
+    public void setTintMode(PorterDuff.Mode tintMode) {
+        mGradientState.mTintMode = tintMode;
+        mTintFilter = updateTintFilter(mTintFilter, mGradientState.mTint, tintMode);
+        invalidateSelf();
+    }
+
+    @Override
     public int getOpacity() {
         return (mAlpha == 255 && mGradientState.mOpaqueOverBounds && isOpaqueForState()) ?
                 PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT;
@@ -997,13 +1022,16 @@
         super.applyTheme(t);
 
         final GradientState state = mGradientState;
-        if (state == null || state.mThemeAttrs == null) {
+        if (state == null) {
             return;
         }
 
-        final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.GradientDrawable);
-        updateStateFromTypedArray(a);
-        a.recycle();
+        if (state.mThemeAttrs != null) {
+            final TypedArray a = t.resolveAttributes(
+                    state.mThemeAttrs, R.styleable.GradientDrawable);
+            updateStateFromTypedArray(a);
+            a.recycle();
+        }
 
         applyThemeChildElements(t);
 
@@ -1045,15 +1073,23 @@
             state.mUseLevelForShape = a.getBoolean(
                     R.styleable.GradientDrawable_useLevel, state.mUseLevelForShape);
         }
+
+        final int tintMode = a.getInt(R.styleable.GradientDrawable_tintMode, -1);
+        if (tintMode != -1) {
+            state.mTintMode = Drawable.parseTintMode(tintMode, PorterDuff.Mode.SRC_IN);
+        }
+
+        final ColorStateList tint = a.getColorStateList(R.styleable.GradientDrawable_tint);
+        if (tint != null) {
+            state.mTint = tint;
+        }
+
+        mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
     }
 
     @Override
     public boolean canApplyTheme() {
-        final GradientState st = mGradientState;
-        return st != null && (st.mThemeAttrs != null || st.mAttrSize != null
-                || st.mAttrGradient != null || st.mAttrSolid != null
-                || st.mAttrStroke != null || st.mAttrCorners != null
-                || st.mAttrPadding != null);
+        return super.canApplyTheme() || mGradientState != null && mGradientState.canApplyTheme();
     }
 
     private void applyThemeChildElements(Theme t) {
@@ -1359,9 +1395,12 @@
                     } else {
                         radiusType = RADIUS_TYPE_FRACTION;
                     }
-                } else {
+                } else if (tv.type == TypedValue.TYPE_DIMENSION) {
                     radius = tv.getDimension(r.getDisplayMetrics());
                     radiusType = RADIUS_TYPE_PIXELS;
+                } else {
+                    radius = tv.getFloat();
+                    radiusType = RADIUS_TYPE_PIXELS;
                 }
 
                 st.mGradientRadius = radius;
@@ -1479,6 +1518,14 @@
         return this;
     }
 
+    /**
+     * @hide
+     */
+    public void clearMutated() {
+        super.clearMutated();
+        mMutated = false;
+    }
+
     final static class GradientState extends ConstantState {
         public int mChangingConfigurations;
         public int mShape = RECTANGLE;
@@ -1514,6 +1561,9 @@
         private boolean mOpaqueOverBounds;
         private boolean mOpaqueOverShape;
 
+        ColorStateList mTint = null;
+        PorterDuff.Mode mTintMode = DEFAULT_TINT_MODE;
+
         int[] mThemeAttrs;
         int[] mAttrSize;
         int[] mAttrGradient;
@@ -1566,6 +1616,8 @@
             mUseLevelForShape = state.mUseLevelForShape;
             mOpaqueOverBounds = state.mOpaqueOverBounds;
             mOpaqueOverShape = state.mOpaqueOverShape;
+            mTint = state.mTint;
+            mTintMode = state.mTintMode;
             mThemeAttrs = state.mThemeAttrs;
             mAttrSize = state.mAttrSize;
             mAttrGradient = state.mAttrGradient;
@@ -1577,22 +1629,19 @@
 
         @Override
         public boolean canApplyTheme() {
-            return mThemeAttrs != null;
+            return mThemeAttrs != null || mAttrSize != null || mAttrGradient != null
+                    || mAttrSolid != null || mAttrStroke != null || mAttrCorners != null
+                    || mAttrPadding != null;
         }
 
         @Override
         public Drawable newDrawable() {
-            return new GradientDrawable(this, null);
+            return new GradientDrawable(this);
         }
 
         @Override
         public Drawable newDrawable(Resources res) {
-            return new GradientDrawable(this, null);
-        }
-
-        @Override
-        public Drawable newDrawable(Resources res, Theme theme) {
-            return new GradientDrawable(this, theme);
+            return new GradientDrawable(this);
         }
 
         @Override
@@ -1696,18 +1745,11 @@
      * The resulting drawable is guaranteed to have a new constant state.
      *
      * @param state Constant state from which the drawable inherits
-     * @param theme Theme to apply to the drawable
      */
-    private GradientDrawable(GradientState state, Theme theme) {
-        if (theme != null && state.canApplyTheme()) {
-            // If we need to apply a theme, implicitly mutate.
-            mGradientState = new GradientState(state);
-            applyTheme(theme);
-        } else {
-            mGradientState = state;
-        }
+    private GradientDrawable(GradientState state) {
+        mGradientState = state;
 
-        initializeWithState(state);
+        initializeWithState(mGradientState);
 
         mGradientIsDirty = true;
         mMutated = false;
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index 961d1607..f1800e5 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -170,24 +170,30 @@
         super.applyTheme(t);
 
         final InsetState state = mInsetState;
-        if (state == null || state.mThemeAttrs == null) {
+        if (state == null) {
             return;
         }
 
-        final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.InsetDrawable);
-        try {
-            updateStateFromTypedArray(a);
-            verifyRequiredAttributes(a);
-        } catch (XmlPullParserException e) {
-            throw new RuntimeException(e);
-        } finally {
-            a.recycle();
+        if (state.mThemeAttrs != null) {
+            final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.InsetDrawable);
+            try {
+                updateStateFromTypedArray(a);
+                verifyRequiredAttributes(a);
+            } catch (XmlPullParserException e) {
+                throw new RuntimeException(e);
+            } finally {
+                a.recycle();
+            }
+        }
+
+        if (state.mDrawable != null && state.mDrawable.canApplyTheme()) {
+            state.mDrawable.applyTheme(t);
         }
     }
 
     @Override
     public boolean canApplyTheme() {
-        return mInsetState != null && mInsetState.mThemeAttrs != null;
+        return super.canApplyTheme() || mInsetState != null && mInsetState.canApplyTheme();
     }
 
     @Override
@@ -339,12 +345,14 @@
 
     @Override
     public int getIntrinsicWidth() {
-        return mInsetState.mDrawable.getIntrinsicWidth();
+        return mInsetState.mDrawable.getIntrinsicWidth()
+                + mInsetState.mInsetLeft + mInsetState.mInsetRight;
     }
 
     @Override
     public int getIntrinsicHeight() {
-        return mInsetState.mDrawable.getIntrinsicHeight();
+        return mInsetState.mDrawable.getIntrinsicHeight()
+                + mInsetState.mInsetTop + mInsetState.mInsetBottom;
     }
 
     @Override
@@ -371,6 +379,15 @@
     }
 
     /**
+     * @hide
+     */
+    public void clearMutated() {
+        super.clearMutated();
+        mInsetState.mDrawable.clearMutated();
+        mMutated = false;
+    }
+
+    /**
      * Returns the drawable wrapped by this InsetDrawable. May be null.
      */
     public Drawable getDrawable() {
@@ -427,6 +444,12 @@
             return mChangingConfigurations;
         }
 
+        @Override
+        public boolean canApplyTheme() {
+            return super.canApplyTheme() || mThemeAttrs != null
+                    || mDrawable != null && mDrawable.canApplyTheme();
+        }
+
         boolean canConstantState() {
             if (!mCheckedConstantState) {
                 mCanConstantState = mDrawable.getConstantState() != null;
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 001ed88..5107e10 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -100,10 +100,10 @@
      * @param state The constant drawable state.
      */
     LayerDrawable(Drawable[] layers, LayerState state) {
-        this(state, null, null);
-        int length = layers.length;
-        ChildDrawable[] r = new ChildDrawable[length];
+        this(state, null);
 
+        final int length = layers.length;
+        final ChildDrawable[] r = new ChildDrawable[length];
         for (int i = 0; i < length; i++) {
             r[i] = new ChildDrawable();
             r[i].mDrawable = layers[i];
@@ -117,18 +117,14 @@
     }
 
     LayerDrawable() {
-        this((LayerState) null, null, null);
+        this((LayerState) null, null);
     }
 
-    LayerDrawable(LayerState state, Resources res, Theme theme) {
-        final LayerState as = createConstantState(state, res);
-        mLayerState = as;
-        if (as.mNum > 0) {
+    LayerDrawable(LayerState state, Resources res) {
+        mLayerState = createConstantState(state, res);
+        if (mLayerState.mNum > 0) {
             ensurePadding();
         }
-        if (theme != null && canApplyTheme()) {
-            applyTheme(theme);
-        }
     }
 
     LayerState createConstantState(LayerState state, Resources res) {
@@ -256,8 +252,8 @@
             a.recycle();
         }
 
-        final ChildDrawable[] array = mLayerState.mChildren;
-        final int N = mLayerState.mNum;
+        final ChildDrawable[] array = state.mChildren;
+        final int N = state.mNum;
         for (int i = 0; i < N; i++) {
             final ChildDrawable layer = array[i];
             if (layer.mThemeAttrs != null) {
@@ -279,25 +275,7 @@
 
     @Override
     public boolean canApplyTheme() {
-        final LayerState state = mLayerState;
-        if (state == null) {
-            return false;
-        }
-
-        if (state.mThemeAttrs != null) {
-            return true;
-        }
-
-        final ChildDrawable[] array = state.mChildren;
-        final int N = state.mNum;
-        for (int i = 0; i < N; i++) {
-            final ChildDrawable layer = array[i];
-            if (layer.mThemeAttrs != null || layer.mDrawable.canApplyTheme()) {
-                return true;
-            }
-        }
-
-        return false;
+        return super.canApplyTheme() || mLayerState != null && mLayerState.canApplyTheme();
     }
 
     /**
@@ -940,6 +918,19 @@
         return this;
     }
 
+    /**
+     * @hide
+     */
+    public void clearMutated() {
+        super.clearMutated();
+        final ChildDrawable[] array = mLayerState.mChildren;
+        final int N = mLayerState.mNum;
+        for (int i = 0; i < N; i++) {
+            array[i].mDrawable.clearMutated();
+        }
+        mMutated = false;
+    }
+
     /** @hide */
     @Override
     public void setLayoutDirection(int layoutDirection) {
@@ -1029,22 +1020,30 @@
 
         @Override
         public boolean canApplyTheme() {
-            return mThemeAttrs != null;
+            if (mThemeAttrs != null) {
+                return true;
+            }
+
+            final ChildDrawable[] array = mChildren;
+            final int N = mNum;
+            for (int i = 0; i < N; i++) {
+                final ChildDrawable layer = array[i];
+                if (layer.mThemeAttrs != null || layer.mDrawable.canApplyTheme()) {
+                    return true;
+                }
+            }
+
+            return false;
         }
 
         @Override
         public Drawable newDrawable() {
-            return new LayerDrawable(this, null, null);
+            return new LayerDrawable(this, null);
         }
 
         @Override
         public Drawable newDrawable(Resources res) {
-            return new LayerDrawable(this, res, null);
-        }
-
-        @Override
-        public Drawable newDrawable(Resources res, Theme theme) {
-            return new LayerDrawable(this, res, theme);
+            return new LayerDrawable(this, res);
         }
 
         @Override
diff --git a/graphics/java/android/graphics/drawable/LevelListDrawable.java b/graphics/java/android/graphics/drawable/LevelListDrawable.java
index bc1c61d..9e918f6 100644
--- a/graphics/java/android/graphics/drawable/LevelListDrawable.java
+++ b/graphics/java/android/graphics/drawable/LevelListDrawable.java
@@ -153,6 +153,14 @@
         return this;
     }
 
+    /**
+     * @hide
+     */
+    public void clearMutated() {
+        super.clearMutated();
+        mMutated = false;
+    }
+
     private final static class LevelListState extends DrawableContainerState {
         private int[] mLows;
         private int[] mHighs;
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 6c62ccf..d821224 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -90,7 +90,7 @@
      */
     @Deprecated
     public NinePatchDrawable(Bitmap bitmap, byte[] chunk, Rect padding, String srcName) {
-        this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), null, null);
+        this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), null);
     }
 
     /**
@@ -99,7 +99,7 @@
      */
     public NinePatchDrawable(Resources res, Bitmap bitmap, byte[] chunk,
             Rect padding, String srcName) {
-        this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), res, null);
+        this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), res);
         mNinePatchState.mTargetDensity = mTargetDensity;
     }
 
@@ -112,7 +112,7 @@
     public NinePatchDrawable(Resources res, Bitmap bitmap, byte[] chunk,
             Rect padding, Rect opticalInsets, String srcName) {
         this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding, opticalInsets),
-                res, null);
+                res);
         mNinePatchState.mTargetDensity = mTargetDensity;
     }
 
@@ -123,7 +123,7 @@
      */
     @Deprecated
     public NinePatchDrawable(NinePatch patch) {
-        this(new NinePatchState(patch, new Rect()), null, null);
+        this(new NinePatchState(patch, new Rect()), null);
     }
 
     /**
@@ -131,7 +131,7 @@
      * based on the display metrics of the resources.
      */
     public NinePatchDrawable(Resources res, NinePatch patch) {
-        this(new NinePatchState(patch, new Rect()), res, null);
+        this(new NinePatchState(patch, new Rect()), res);
         mNinePatchState.mTargetDensity = mTargetDensity;
     }
 
@@ -563,6 +563,14 @@
         return this;
     }
 
+    /**
+     * @hide
+     */
+    public void clearMutated() {
+        super.clearMutated();
+        mMutated = false;
+    }
+
     @Override
     protected boolean onStateChange(int[] stateSet) {
         final NinePatchState state = mNinePatchState;
@@ -646,17 +654,12 @@
 
         @Override
         public Drawable newDrawable() {
-            return new NinePatchDrawable(this, null, null);
+            return new NinePatchDrawable(this, null);
         }
 
         @Override
         public Drawable newDrawable(Resources res) {
-            return new NinePatchDrawable(this, res, null);
-        }
-
-        @Override
-        public Drawable newDrawable(Resources res, Theme theme) {
-            return new NinePatchDrawable(this, res, theme);
+            return new NinePatchDrawable(this, res);
         }
 
         @Override
@@ -669,16 +672,10 @@
      * The one constructor to rule them all. This is called by all public
      * constructors to set the state and initialize local properties.
      */
-    private NinePatchDrawable(NinePatchState state, Resources res, Theme theme) {
-        if (theme != null && state.canApplyTheme()) {
-            // If we need to apply a theme, implicitly mutate.
-            mNinePatchState = new NinePatchState(state);
-            applyTheme(theme);
-        } else {
-            mNinePatchState = state;
-        }
+    private NinePatchDrawable(NinePatchState state, Resources res) {
+        mNinePatchState = state;
 
-        initializeWithState(state, res);
+        initializeWithState(mNinePatchState, res);
     }
 
     /**
diff --git a/graphics/java/android/graphics/drawable/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java
index faa89bf..21d865f 100644
--- a/graphics/java/android/graphics/drawable/RippleBackground.java
+++ b/graphics/java/android/graphics/drawable/RippleBackground.java
@@ -43,10 +43,12 @@
     private static final float WAVE_OPACITY_DECAY_VELOCITY = 3.0f / GLOBAL_SPEED;
     private static final float WAVE_OUTER_OPACITY_EXIT_VELOCITY_MAX = 4.5f * GLOBAL_SPEED;
     private static final float WAVE_OUTER_OPACITY_EXIT_VELOCITY_MIN = 1.5f * GLOBAL_SPEED;
-    private static final float WAVE_OUTER_OPACITY_ENTER_VELOCITY = 10.0f * GLOBAL_SPEED;
     private static final float WAVE_OUTER_SIZE_INFLUENCE_MAX = 200f;
     private static final float WAVE_OUTER_SIZE_INFLUENCE_MIN = 40f;
 
+    private static final int ENTER_DURATION = 667;
+    private static final int ENTER_DURATION_FAST = 100;
+
     // Hardware animators.
     private final ArrayList<RenderNodeAnimator> mRunningAnimations =
             new ArrayList<RenderNodeAnimator>();
@@ -224,21 +226,20 @@
     /**
      * Starts the enter animation.
      */
-    public void enter() {
+    public void enter(boolean fast) {
         cancel();
 
-        final int outerDuration = (int) (1000 * 1.0f / WAVE_OUTER_OPACITY_ENTER_VELOCITY);
-        final ObjectAnimator outer = ObjectAnimator.ofFloat(this, "outerOpacity", 0, 1);
-        outer.setAutoCancel(true);
-        outer.setDuration(outerDuration);
-        outer.setInterpolator(LINEAR_INTERPOLATOR);
+        final ObjectAnimator opacity = ObjectAnimator.ofFloat(this, "outerOpacity", 0, 1);
+        opacity.setAutoCancel(true);
+        opacity.setDuration(fast ? ENTER_DURATION_FAST : ENTER_DURATION);
+        opacity.setInterpolator(LINEAR_INTERPOLATOR);
 
-        mAnimOuterOpacity = outer;
+        mAnimOuterOpacity = opacity;
 
         // Enter animations always run on the UI thread, since it's unlikely
         // that anything interesting is happening until the user lifts their
         // finger.
-        outer.start();
+        opacity.start();
     }
 
     /**
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index c7aa98e..316139b 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -167,7 +167,7 @@
      * Constructor used for drawable inflation.
      */
     RippleDrawable() {
-        this(new RippleState(null, null, null), null, null);
+        this(new RippleState(null, null, null), null);
     }
 
     /**
@@ -180,7 +180,7 @@
      */
     public RippleDrawable(@NonNull ColorStateList color, @Nullable Drawable content,
             @Nullable Drawable mask) {
-        this(new RippleState(null, null, null), null, null);
+        this(new RippleState(null, null, null), null);
 
         if (color == null) {
             throw new IllegalArgumentException("RippleDrawable requires a non-null color");
@@ -280,7 +280,7 @@
         }
 
         setRippleActive(enabled && pressed);
-        setBackgroundActive(focused || (enabled && pressed));
+        setBackgroundActive(focused || (enabled && pressed), focused);
 
         return changed;
     }
@@ -296,11 +296,11 @@
         }
     }
 
-    private void setBackgroundActive(boolean active) {
+    private void setBackgroundActive(boolean active, boolean focused) {
         if (mBackgroundActive != active) {
             mBackgroundActive = active;
             if (active) {
-                tryBackgroundEnter();
+                tryBackgroundEnter(focused);
             } else {
                 tryBackgroundExit();
             }
@@ -333,8 +333,11 @@
             }
 
             if (mBackgroundActive) {
-                tryBackgroundEnter();
+                tryBackgroundEnter(false);
             }
+
+            // Skip animations, just show the correct final states.
+            jumpToCurrentState();
         }
 
         return changed;
@@ -470,7 +473,7 @@
 
     @Override
     public boolean canApplyTheme() {
-        return super.canApplyTheme() || mState != null && mState.mTouchThemeAttrs != null;
+        return super.canApplyTheme() || mState != null && mState.canApplyTheme();
     }
 
     @Override
@@ -489,14 +492,14 @@
     /**
      * Creates an active hotspot at the specified location.
      */
-    private void tryBackgroundEnter() {
+    private void tryBackgroundEnter(boolean focused) {
         if (mBackground == null) {
             mBackground = new RippleBackground(this, mHotspotBounds);
         }
 
         final int color = mState.mColor.getColorForState(getState(), Color.TRANSPARENT);
         mBackground.setup(mState.mMaxRadius, color, mDensity);
-        mBackground.enter();
+        mBackground.enter(focused);
     }
 
     private void tryBackgroundExit() {
@@ -715,10 +718,12 @@
         final ChildDrawable[] array = mLayerState.mChildren;
         final int count = mLayerState.mNum;
 
-        // We don't need a layer if we don't expect to draw any ripples, we have
-        // an explicit mask, or if the non-mask content is all opaque.
+        // We don't need a layer if we don't expect to draw any ripples or
+        // a background, we have an explicit mask, or if the non-mask content
+        // is all opaque.
         boolean needsLayer = false;
-        if ((mExitingRipplesCount > 0 || mBackground != null) && mMask == null) {
+        if ((mExitingRipplesCount > 0 || (mBackground != null && mBackground.shouldDraw()))
+                && mMask == null) {
             for (int i = 0; i < count; i++) {
                 if (array[i].mId != R.id.mask
                         && array[i].mDrawable.getOpacity() != PixelFormat.OPAQUE) {
@@ -924,17 +929,12 @@
 
         @Override
         public Drawable newDrawable() {
-            return new RippleDrawable(this, null, null);
+            return new RippleDrawable(this, null);
         }
 
         @Override
         public Drawable newDrawable(Resources res) {
-            return new RippleDrawable(this, res, null);
-        }
-
-        @Override
-        public Drawable newDrawable(Resources res, Theme theme) {
-            return new RippleDrawable(this, res, theme);
+            return new RippleDrawable(this, res);
         }
     }
 
@@ -968,37 +968,18 @@
         return mState.mMaxRadius;
     }
 
-    private RippleDrawable(RippleState state, Resources res, Theme theme) {
-        boolean needsTheme = false;
+    private RippleDrawable(RippleState state, Resources res) {
+        mState = new RippleState(state, this, res);
+        mLayerState = mState;
 
-        final RippleState ns;
-        if (theme != null && state != null && state.canApplyTheme()) {
-            ns = new RippleState(state, this, res);
-            needsTheme = true;
-        } else if (state == null) {
-            ns = new RippleState(null, this, res);
-        } else {
-            // We always need a new state since child drawables contain local
-            // state but live within the parent's constant state.
-            // TODO: Move child drawables into local state.
-            ns = new RippleState(state, this, res);
+        if (mState.mNum > 0) {
+            ensurePadding();
         }
 
         if (res != null) {
             mDensity = res.getDisplayMetrics().density;
         }
 
-        mState = ns;
-        mLayerState = ns;
-
-        if (ns.mNum > 0) {
-            ensurePadding();
-        }
-
-        if (needsTheme) {
-            applyTheme(theme);
-        }
-
         initializeFromState();
     }
 
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index 55c9637..3f75bc3 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -16,6 +16,8 @@
 
 package android.graphics.drawable;
 
+import com.android.internal.R;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -476,6 +478,26 @@
     }
 
     @Override
+    public void applyTheme(Theme t) {
+        super.applyTheme(t);
+
+        final RotateState state = mState;
+        if (state == null) {
+            return;
+        }
+
+        if (state.mDrawable != null) {
+            state.mDrawable.applyTheme(t);
+        }
+    }
+
+    @Override
+    public boolean canApplyTheme() {
+        final RotateState state = mState;
+        return state != null && state.mDrawable != null && state.mDrawable.canApplyTheme();
+    }
+
+    @Override
     public Drawable mutate() {
         if (!mMutated && super.mutate() == this) {
             mState.mDrawable.mutate();
@@ -485,6 +507,15 @@
     }
 
     /**
+     * @hide
+     */
+    public void clearMutated() {
+        super.clearMutated();
+        mState.mDrawable.clearMutated();
+        mMutated = false;
+    }
+
+    /**
      * Represents the state of a rotation for a given drawable. The same
      * rotate drawable can be invoked with different states to drive several
      * rotations at the same time.
diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java
index b990249..9a5b8fb 100644
--- a/graphics/java/android/graphics/drawable/ScaleDrawable.java
+++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java
@@ -128,6 +128,26 @@
         }
     }
 
+    @Override
+    public void applyTheme(Theme t) {
+        super.applyTheme(t);
+
+        final ScaleState state = mScaleState;
+        if (state == null) {
+            return;
+        }
+
+        if (state.mDrawable != null) {
+            state.mDrawable.applyTheme(t);
+        }
+    }
+
+    @Override
+    public boolean canApplyTheme() {
+        final ScaleState state = mScaleState;
+        return state != null && state.mDrawable != null && state.mDrawable.canApplyTheme();
+    }
+
     // overrides from Drawable.Callback
 
     public void invalidateDrawable(Drawable who) {
@@ -276,6 +296,15 @@
         return this;
     }
 
+    /**
+     * @hide
+     */
+    public void clearMutated() {
+        super.clearMutated();
+        mScaleState.mDrawable.clearMutated();
+        mMutated = false;
+    }
+
     final static class ScaleState extends ConstantState {
         Drawable mDrawable;
         int mChangingConfigurations;
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index bd69d76..a3d8c92 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -76,7 +76,7 @@
      * ShapeDrawable constructor.
      */
     public ShapeDrawable() {
-        this(new ShapeState(null), null, null);
+        this(new ShapeState(null), null);
     }
 
     /**
@@ -85,7 +85,7 @@
      * @param s the Shape that this ShapeDrawable should be
      */
     public ShapeDrawable(Shape s) {
-        this(new ShapeState(null), null, null);
+        this(new ShapeState(null), null);
 
         mShapeState.mShape = s;
     }
@@ -508,6 +508,14 @@
     }
 
     /**
+     * @hide
+     */
+    public void clearMutated() {
+        super.clearMutated();
+        mMutated = false;
+    }
+
+    /**
      * Defines the intrinsic properties of this ShapeDrawable's Shape.
      */
     final static class ShapeState extends ConstantState {
@@ -547,17 +555,12 @@
 
         @Override
         public Drawable newDrawable() {
-            return new ShapeDrawable(this, null, null);
+            return new ShapeDrawable(this, null);
         }
 
         @Override
         public Drawable newDrawable(Resources res) {
-            return new ShapeDrawable(this, res, null);
-        }
-
-        @Override
-        public Drawable newDrawable(Resources res, Theme theme) {
-            return new ShapeDrawable(this, res, theme);
+            return new ShapeDrawable(this, res);
         }
 
         @Override
@@ -570,13 +573,8 @@
      * The one constructor to rule them all. This is called by all public
      * constructors to set the state and initialize local properties.
      */
-    private ShapeDrawable(ShapeState state, Resources res, Theme theme) {
-        if (theme != null && state.canApplyTheme()) {
-            mShapeState = new ShapeState(state);
-            applyTheme(theme);
-        } else {
-            mShapeState = state;
-        }
+    private ShapeDrawable(ShapeState state, Resources res) {
+        mShapeState = state;
 
         initializeWithState(state, res);
     }
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
index 2eb8a80..a299b3c 100644
--- a/graphics/java/android/graphics/drawable/StateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -263,6 +263,14 @@
         return this;
     }
 
+    /**
+     * @hide
+     */
+    public void clearMutated() {
+        super.clearMutated();
+        mMutated = false;
+    }
+
     /** @hide */
     @Override
     public void setLayoutDirection(int layoutDirection) {
@@ -280,7 +288,16 @@
             super(orig, owner, res);
 
             if (orig != null) {
-                mStateSets = Arrays.copyOf(orig.mStateSets, orig.mStateSets.length);
+                // Perform a deep copy.
+                final int[][] sets = orig.mStateSets;
+                final int count = sets.length;
+                mStateSets = new int[count][];
+                for (int i = 0; i < count; i++) {
+                    final int[] set = sets[i];
+                    if (set != null) {
+                        mStateSets[i] = set.clone();
+                    }
+                }
             } else {
                 mStateSets = new int[getCapacity()][];
             }
@@ -322,6 +339,13 @@
         }
     }
 
+    @Override
+    public void applyTheme(Theme theme) {
+        super.applyTheme(theme);
+
+        onStateChange(getState());
+    }
+
     void setConstantState(StateListState state) {
         super.setConstantState(state);
 
diff --git a/graphics/java/android/graphics/drawable/TransitionDrawable.java b/graphics/java/android/graphics/drawable/TransitionDrawable.java
index 4380ca4e..e5c235e 100644
--- a/graphics/java/android/graphics/drawable/TransitionDrawable.java
+++ b/graphics/java/android/graphics/drawable/TransitionDrawable.java
@@ -17,7 +17,6 @@
 package android.graphics.drawable;
 
 import android.content.res.Resources;
-import android.content.res.Resources.Theme;
 import android.graphics.Canvas;
 import android.os.SystemClock;
 
@@ -86,11 +85,11 @@
      * @see #TransitionDrawable(Drawable[])
      */
     TransitionDrawable() {
-        this(new TransitionState(null, null, null), null, null);
+        this(new TransitionState(null, null, null), (Resources) null);
     }
 
-    private TransitionDrawable(TransitionState state, Resources res, Theme theme) {
-        super(state, res, theme);
+    private TransitionDrawable(TransitionState state, Resources res) {
+        super(state, res);
     }
 
     private TransitionDrawable(TransitionState state, Drawable[] layers) {
@@ -245,24 +244,18 @@
     }
 
     static class TransitionState extends LayerState {
-        TransitionState(TransitionState orig, TransitionDrawable owner,
-                Resources res) {
+        TransitionState(TransitionState orig, TransitionDrawable owner, Resources res) {
             super(orig, owner, res);
         }
 
         @Override
         public Drawable newDrawable() {
-            return new TransitionDrawable(this, null, null);
+            return new TransitionDrawable(this, (Resources) null);
         }
 
         @Override
         public Drawable newDrawable(Resources res) {
-            return new TransitionDrawable(this, res, null);
-        }
-
-        @Override
-        public Drawable newDrawable(Resources res, Theme theme) {
-            return new TransitionDrawable(this, res, theme);
+            return new TransitionDrawable(this, res);
         }
 
         @Override
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index db0c94f..848fc53 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -14,6 +14,7 @@
 
 package android.graphics.drawable;
 
+import android.annotation.NonNull;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
@@ -212,15 +213,8 @@
         mVectorState = new VectorDrawableState();
     }
 
-    private VectorDrawable(VectorDrawableState state, Resources res, Theme theme) {
-        if (theme != null && state.canApplyTheme()) {
-            // If we need to apply a theme, implicitly mutate.
-            mVectorState = new VectorDrawableState(state);
-            applyTheme(theme);
-        } else {
-            mVectorState = state;
-        }
-
+    private VectorDrawable(@NonNull VectorDrawableState state) {
+        mVectorState = state;
         mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
     }
 
@@ -233,6 +227,14 @@
         return this;
     }
 
+    /**
+     * @hide
+     */
+    public void clearMutated() {
+        super.clearMutated();
+        mMutated = false;
+    }
+
     Object getTargetByName(String name) {
         return mVectorState.mVPathRenderer.mVGTargetsMap.get(name);
     }
@@ -758,17 +760,12 @@
 
         @Override
         public Drawable newDrawable() {
-            return new VectorDrawable(this, null, null);
+            return new VectorDrawable(this);
         }
 
         @Override
         public Drawable newDrawable(Resources res) {
-            return new VectorDrawable(this, res, null);
-        }
-
-        @Override
-        public Drawable newDrawable(Resources res, Theme theme) {
-            return new VectorDrawable(this, res, theme);
+            return new VectorDrawable(this);
         }
 
         @Override
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index cb3ef9b..d78c1cb 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -212,10 +212,13 @@
 
         // check state/paint for transparency
         if (mPaint) {
+            if (mPaint->getAlpha() != 0xFF) {
+                return false;
+            }
             if (mPaint->getShader() && !mPaint->getShader()->isOpaque()) {
                 return false;
             }
-            if (mPaint->getAlpha() != 0xFF) {
+            if (Renderer::isBlendedColorFilter(mPaint->getColorFilter())) {
                 return false;
             }
         }
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index ce1d09f..7a094fd 100755
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -51,6 +51,21 @@
     #define EVENT_LOGD(...)
 #endif
 
+static void atraceFormatBegin(const char* fmt, ...) {
+    const int BUFFER_SIZE = 256;
+    va_list ap;
+    char buf[BUFFER_SIZE];
+
+    va_start(ap, fmt);
+    vsnprintf(buf, BUFFER_SIZE, fmt, ap);
+    va_end(ap);
+
+    ATRACE_BEGIN(buf);
+}
+
+#define ATRACE_FORMAT_BEGIN(fmt, ...) \
+    if (CC_UNLIKELY(ATRACE_ENABLED())) atraceFormatBegin(fmt, ##__VA_ARGS__)
+
 namespace android {
 namespace uirenderer {
 
@@ -537,17 +552,18 @@
 
         // Note: it is very important to update the layers in order
         for (int i = 0; i < count; i++) {
+            Layer* layer = mLayerUpdates.itemAt(i);
+
             sprintf(layerName, "Layer #%d", i);
             startMark(layerName);
+            ATRACE_FORMAT_BEGIN("flushLayer %ux%u", layer->getWidth(), layer->getHeight());
 
-            ATRACE_BEGIN("flushLayer");
-            Layer* layer = mLayerUpdates.itemAt(i);
             layer->flush();
+
             ATRACE_END();
+            endMark();
 
             mCaches.resourceCache.decrementRefcount(layer);
-
-            endMark();
         }
 
         mLayerUpdates.clear();
@@ -631,6 +647,7 @@
 
     if (restoreLayer) {
         endMark(); // Savelayer
+        ATRACE_END(); // SaveLayer
         startMark("ComposeLayer");
         composeLayer(removed, restored);
         endMark();
@@ -814,6 +831,9 @@
     mSnapshot->flags |= Snapshot::kFlagIsLayer;
     mSnapshot->layer = layer;
 
+    ATRACE_FORMAT_BEGIN("%ssaveLayer %ux%u",
+            fboLayer ? "" : "unclipped ",
+            layer->getWidth(), layer->getHeight());
     startMark("SaveLayer");
     if (fboLayer) {
         return createFboLayer(layer, bounds, clip);
@@ -1714,13 +1734,6 @@
     }
 }
 
-static bool isBlendedColorFilter(const SkColorFilter* filter) {
-    if (filter == NULL) {
-        return false;
-    }
-    return (filter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag) == 0;
-}
-
 void OpenGLRenderer::setupDrawBlending(const Layer* layer, bool swapSrcDst) {
     SkXfermode::Mode mode = layer->getMode();
     // When the blending mode is kClear_Mode, we need to use a modulate color
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 254492f..40cd13e 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -50,10 +50,13 @@
     fprintf(file, "\nRecent DisplayList operations\n");
     logBuffer.outputCommands(file);
 
-    String8 cachesLog;
-    Caches::getInstance().dumpMemoryUsage(cachesLog);
-    fprintf(file, "\nCaches:\n%s", cachesLog.string());
-    fprintf(file, "\n");
+    if (Caches::hasInstance()) {
+        String8 cachesLog;
+        Caches::getInstance().dumpMemoryUsage(cachesLog);
+        fprintf(file, "\nCaches:\n%s\n", cachesLog.string());
+    } else {
+        fprintf(file, "\nNo caches instance.\n");
+    }
 
     fflush(file);
 }
@@ -293,6 +296,9 @@
                 mStagingDisplayListData->children()[i]->mRenderNode->incParentRefCount();
             }
         }
+        // Damage with the old display list first then the new one to catch any
+        // changes in isRenderable or, in the future, bounds
+        damageSelf(info);
         deleteDisplayListData();
         mDisplayListData = mStagingDisplayListData;
         mStagingDisplayListData = NULL;
diff --git a/libs/hwui/Renderer.h b/libs/hwui/Renderer.h
index 9cedd5a..a2f8c05 100644
--- a/libs/hwui/Renderer.h
+++ b/libs/hwui/Renderer.h
@@ -17,12 +17,13 @@
 #ifndef ANDROID_HWUI_RENDERER_H
 #define ANDROID_HWUI_RENDERER_H
 
+#include <SkColorFilter.h>
+#include <SkPaint.h>
 #include <SkRegion.h>
 
 #include <utils/String8.h>
 
 #include "AssetAtlas.h"
-#include "SkPaint.h"
 
 namespace android {
 
@@ -81,6 +82,14 @@
                 && !paint.getColorFilter()
                 && getXfermode(paint.getXfermode()) == SkXfermode::kSrcOver_Mode;
     }
+
+    static bool isBlendedColorFilter(const SkColorFilter* filter) {
+        if (filter == NULL) {
+            return false;
+        }
+        return (filter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag) == 0;
+    }
+
 // ----------------------------------------------------------------------------
 // Frame state operations
 // ----------------------------------------------------------------------------
diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp
index dbedf94..df28ae8 100644
--- a/libs/hwui/SpotShadow.cpp
+++ b/libs/hwui/SpotShadow.cpp
@@ -60,7 +60,7 @@
 namespace android {
 namespace uirenderer {
 
-static const double EPSILON = 1e-7;
+static const float EPSILON = 1e-7;
 
 /**
  * For each polygon's vertex, the light center will project it to the receiver
@@ -118,17 +118,17 @@
     // intersection point should stay on both the ray and the edge of (p1, p2).
     // solve([p1x+t*(p2x-p1x)=dx*t2+px,p1y+t*(p2y-p1y)=dy*t2+py],[t,t2]);
 
-    double divisor = (dx * (p1.y - p2.y) + dy * p2.x - dy * p1.x);
+    float divisor = (dx * (p1.y - p2.y) + dy * p2.x - dy * p1.x);
     if (divisor == 0) return -1.0f; // error, invalid divisor
 
 #if DEBUG_SHADOW
-    double interpVal = (dx * (p1.y - rayOrigin.y) + dy * rayOrigin.x - dy * p1.x) / divisor;
+    float interpVal = (dx * (p1.y - rayOrigin.y) + dy * rayOrigin.x - dy * p1.x) / divisor;
     if (interpVal < 0 || interpVal > 1) {
         ALOGW("rayIntersectPoints is hitting outside the segment %f", interpVal);
     }
 #endif
 
-    double distance = (p1.x * (rayOrigin.y - p2.y) + p2.x * (p1.y - rayOrigin.y) +
+    float distance = (p1.x * (rayOrigin.y - p2.y) + p2.x * (p1.y - rayOrigin.y) +
             rayOrigin.x * (p2.y - p1.y)) / divisor;
 
     return distance; // may be negative in error cases
@@ -217,146 +217,12 @@
  *
  * @return true if a right hand turn
  */
-bool SpotShadow::ccw(double ax, double ay, double bx, double by,
-        double cx, double cy) {
+bool SpotShadow::ccw(float ax, float ay, float bx, float by,
+        float cx, float cy) {
     return (bx - ax) * (cy - ay) - (by - ay) * (cx - ax) > EPSILON;
 }
 
 /**
- * Calculates the intersection of poly1 with poly2 and put in poly2.
- * Note that both poly1 and poly2 must be in CW order already!
- *
- * @param poly1 The 1st polygon, as a Vector2 array.
- * @param poly1Length The number of vertices of 1st polygon.
- * @param poly2 The 2nd and output polygon, as a Vector2 array.
- * @param poly2Length The number of vertices of 2nd polygon.
- * @return number of vertices in output polygon as poly2.
- */
-int SpotShadow::intersection(const Vector2* poly1, int poly1Length,
-        Vector2* poly2, int poly2Length) {
-#if DEBUG_SHADOW
-    if (!ShadowTessellator::isClockwise(poly1, poly1Length)) {
-        ALOGW("Poly1 is not clockwise! Intersection is wrong!");
-    }
-    if (!ShadowTessellator::isClockwise(poly2, poly2Length)) {
-        ALOGW("Poly2 is not clockwise! Intersection is wrong!");
-    }
-#endif
-    Vector2 poly[poly1Length * poly2Length + 2];
-    int count = 0;
-    int pcount = 0;
-
-    // If one vertex from one polygon sits inside another polygon, add it and
-    // count them.
-    for (int i = 0; i < poly1Length; i++) {
-        if (testPointInsidePolygon(poly1[i], poly2, poly2Length)) {
-            poly[count] = poly1[i];
-            count++;
-            pcount++;
-
-        }
-    }
-
-    int insidePoly2 = pcount;
-    for (int i = 0; i < poly2Length; i++) {
-        if (testPointInsidePolygon(poly2[i], poly1, poly1Length)) {
-            poly[count] = poly2[i];
-            count++;
-        }
-    }
-
-    int insidePoly1 = count - insidePoly2;
-    // If all vertices from poly1 are inside poly2, then just return poly1.
-    if (insidePoly2 == poly1Length) {
-        memcpy(poly2, poly1, poly1Length * sizeof(Vector2));
-        return poly1Length;
-    }
-
-    // If all vertices from poly2 are inside poly1, then just return poly2.
-    if (insidePoly1 == poly2Length) {
-        return poly2Length;
-    }
-
-    // Since neither polygon fully contain the other one, we need to add all the
-    // intersection points.
-    Vector2 intersection = {0, 0};
-    for (int i = 0; i < poly2Length; i++) {
-        for (int j = 0; j < poly1Length; j++) {
-            int poly2LineStart = i;
-            int poly2LineEnd = ((i + 1) % poly2Length);
-            int poly1LineStart = j;
-            int poly1LineEnd = ((j + 1) % poly1Length);
-            bool found = lineIntersection(
-                    poly2[poly2LineStart].x, poly2[poly2LineStart].y,
-                    poly2[poly2LineEnd].x, poly2[poly2LineEnd].y,
-                    poly1[poly1LineStart].x, poly1[poly1LineStart].y,
-                    poly1[poly1LineEnd].x, poly1[poly1LineEnd].y,
-                    intersection);
-            if (found) {
-                poly[count].x = intersection.x;
-                poly[count].y = intersection.y;
-                count++;
-            } else {
-                Vector2 delta = poly2[i] - poly1[j];
-                if (delta.lengthSquared() < EPSILON) {
-                    poly[count] = poly2[i];
-                    count++;
-                }
-            }
-        }
-    }
-
-    if (count == 0) {
-        return 0;
-    }
-
-    // Sort the result polygon around the center.
-    Vector2 center = {0.0f, 0.0f};
-    for (int i = 0; i < count; i++) {
-        center += poly[i];
-    }
-    center /= count;
-    sort(poly, count, center);
-
-#if DEBUG_SHADOW
-    // Since poly2 is overwritten as the result, we need to save a copy to do
-    // our verification.
-    Vector2 oldPoly2[poly2Length];
-    int oldPoly2Length = poly2Length;
-    memcpy(oldPoly2, poly2, sizeof(Vector2) * poly2Length);
-#endif
-
-    // Filter the result out from poly and put it into poly2.
-    poly2[0] = poly[0];
-    int lastOutputIndex = 0;
-    for (int i = 1; i < count; i++) {
-        Vector2 delta = poly[i] - poly2[lastOutputIndex];
-        if (delta.lengthSquared() >= EPSILON) {
-            poly2[++lastOutputIndex] = poly[i];
-        } else {
-            // If the vertices are too close, pick the inner one, because the
-            // inner one is more likely to be an intersection point.
-            Vector2 delta1 = poly[i] - center;
-            Vector2 delta2 = poly2[lastOutputIndex] - center;
-            if (delta1.lengthSquared() < delta2.lengthSquared()) {
-                poly2[lastOutputIndex] = poly[i];
-            }
-        }
-    }
-    int resultLength = lastOutputIndex + 1;
-
-#if DEBUG_SHADOW
-    testConvex(poly2, resultLength, "intersection");
-    testConvex(poly1, poly1Length, "input poly1");
-    testConvex(oldPoly2, oldPoly2Length, "input poly2");
-
-    testIntersection(poly1, poly1Length, oldPoly2, oldPoly2Length, poly2, resultLength);
-#endif
-
-    return resultLength;
-}
-
-/**
  * Sort points about a center point
  *
  * @param poly The in and out polyogon as a Vector2 array.
@@ -441,13 +307,13 @@
 bool SpotShadow::testPointInsidePolygon(const Vector2 testPoint,
         const Vector2* poly, int len) {
     bool c = false;
-    double testx = testPoint.x;
-    double testy = testPoint.y;
+    float testx = testPoint.x;
+    float testy = testPoint.y;
     for (int i = 0, j = len - 1; i < len; j = i++) {
-        double startX = poly[j].x;
-        double startY = poly[j].y;
-        double endX = poly[i].x;
-        double endY = poly[i].y;
+        float startX = poly[j].x;
+        float startY = poly[j].y;
+        float endX = poly[i].x;
+        float endY = poly[i].y;
 
         if (((endY > testy) != (startY > testy))
             && (testx < (startX - endX) * (testy - endY)
@@ -490,46 +356,6 @@
 }
 
 /**
- * Intersects two lines in parametric form. This function is called in a tight
- * loop, and we need double precision to get things right.
- *
- * @param x1 the x coordinate point 1 of line 1
- * @param y1 the y coordinate point 1 of line 1
- * @param x2 the x coordinate point 2 of line 1
- * @param y2 the y coordinate point 2 of line 1
- * @param x3 the x coordinate point 1 of line 2
- * @param y3 the y coordinate point 1 of line 2
- * @param x4 the x coordinate point 2 of line 2
- * @param y4 the y coordinate point 2 of line 2
- * @param ret the x,y location of the intersection
- * @return true if it found an intersection
- */
-inline bool SpotShadow::lineIntersection(double x1, double y1, double x2, double y2,
-        double x3, double y3, double x4, double y4, Vector2& ret) {
-    double d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
-    if (d == 0.0) return false;
-
-    double dx = (x1 * y2 - y1 * x2);
-    double dy = (x3 * y4 - y3 * x4);
-    double x = (dx * (x3 - x4) - (x1 - x2) * dy) / d;
-    double y = (dx * (y3 - y4) - (y1 - y2) * dy) / d;
-
-    // The intersection should be in the middle of the point 1 and point 2,
-    // likewise point 3 and point 4.
-    if (((x - x1) * (x - x2) > EPSILON)
-        || ((x - x3) * (x - x4) > EPSILON)
-        || ((y - y1) * (y - y2) > EPSILON)
-        || ((y - y3) * (y - y4) > EPSILON)) {
-        // Not interesected
-        return false;
-    }
-    ret.x = x;
-    ret.y = y;
-    return true;
-
-}
-
-/**
  * Compute a horizontal circular polygon about point (x , y , height) of radius
  * (size)
  *
@@ -542,7 +368,7 @@
         float size, Vector3* ret) {
     // TODO: Caching all the sin / cos values and store them in a look up table.
     for (int i = 0; i < points; i++) {
-        double angle = 2 * i * M_PI / points;
+        float angle = 2 * i * M_PI / points;
         ret[i].x = cosf(angle) * size + lightCenter.x;
         ret[i].y = sinf(angle) * size + lightCenter.y;
         ret[i].z = lightCenter.z;
@@ -853,21 +679,6 @@
     return true;
 }
 
-int SpotShadow::calculateOccludedUmbra(const Vector2* umbra, int umbraLength,
-        const Vector3* poly, int polyLength, Vector2* occludedUmbra) {
-    // Occluded umbra area is computed as the intersection of the projected 2D
-    // poly and umbra.
-    for (int i = 0; i < polyLength; i++) {
-        occludedUmbra[i].x = poly[i].x;
-        occludedUmbra[i].y = poly[i].y;
-    }
-
-    // Both umbra and incoming polygon are guaranteed to be CW, so we can call
-    // intersection() directly.
-    return intersection(umbra, umbraLength,
-            occludedUmbra, polyLength);
-}
-
 /**
  * This is only for experimental purpose.
  * After intersections are calculated, we could smooth the polygon if needed.
@@ -1585,8 +1396,8 @@
         Vector2 middle = polygon[(i + 1) % polygonLength];
         Vector2 end = polygon[(i + 2) % polygonLength];
 
-        double delta = (double(middle.x) - start.x) * (double(end.y) - start.y) -
-                (double(middle.y) - start.y) * (double(end.x) - start.x);
+        float delta = (float(middle.x) - start.x) * (float(end.y) - start.y) -
+                (float(middle.y) - start.y) * (float(end.x) - start.x);
         bool isCCWOrCoLinear = (delta >= EPSILON);
 
         if (isCCWOrCoLinear) {
@@ -1621,8 +1432,8 @@
     bool dumpPoly = false;
     for (int k = 0; k < TEST_POINT_NUMBER; k++) {
         // Generate a random point between minX, minY and maxX, maxY.
-        double randomX = rand() / double(RAND_MAX);
-        double randomY = rand() / double(RAND_MAX);
+        float randomX = rand() / float(RAND_MAX);
+        float randomY = rand() / float(RAND_MAX);
 
         Vector2 testPoint;
         testPoint.x = lowerBound.x + randomX * (upperBound.x - lowerBound.x);
diff --git a/libs/hwui/SpotShadow.h b/libs/hwui/SpotShadow.h
index 23fdca9..6fa2028f 100644
--- a/libs/hwui/SpotShadow.h
+++ b/libs/hwui/SpotShadow.h
@@ -35,8 +35,6 @@
 
     static float projectCasterToOutline(Vector2& outline,
             const Vector3& lightCenter, const Vector3& polyVertex);
-    static int calculateOccludedUmbra(const Vector2* umbra, int umbraLength,
-            const Vector3* poly, int polyLength, Vector2* occludedUmbra);
 
     static int setupAngleList(VertexAngleData* angleDataList,
             int polyLength, const Vector2* polygon, const Vector2& centroid,
@@ -81,8 +79,7 @@
 
     static void xsort(Vector2* points, int pointsLength);
     static int hull(Vector2* points, int pointsLength, Vector2* retPoly);
-    static bool ccw(double ax, double ay, double bx, double by, double cx, double cy);
-    static int intersection(const Vector2* poly1, int poly1length, Vector2* poly2, int poly2length);
+    static bool ccw(float ax, float ay, float bx, float by, float cx, float cy);
     static void sort(Vector2* poly, int polyLength, const Vector2& center);
 
     static void swap(Vector2* points, int i, int j);
@@ -92,8 +89,6 @@
     static bool testPointInsidePolygon(const Vector2 testPoint, const Vector2* poly, int len);
     static void makeClockwise(Vector2* polygon, int len);
     static void reverse(Vector2* polygon, int len);
-    static inline bool lineIntersection(double x1, double y1, double x2, double y2,
-            double x3, double y3, double x4, double y4, Vector2& ret);
 
     static void generateTriangleStrip(bool isCasterOpaque, float shadowStrengthScale,
             Vector2* penumbra, int penumbraLength, Vector2* umbra, int umbraLength,
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index b50a433..9d2ae8b 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -42,7 +42,8 @@
         : mRenderThread(thread)
         , mEglManager(thread.eglManager())
         , mEglSurface(EGL_NO_SURFACE)
-        , mDirtyRegionsEnabled(false)
+        , mBufferPreserved(false)
+        , mSwapBehavior(kSwap_default)
         , mOpaque(!translucent)
         , mCanvas(NULL)
         , mHaveNewSurface(false)
@@ -82,7 +83,8 @@
     }
 
     if (mEglSurface != EGL_NO_SURFACE) {
-        mDirtyRegionsEnabled = mEglManager.enableDirtyRegions(mEglSurface);
+        const bool preserveBuffer = (mSwapBehavior != kSwap_discardBuffer);
+        mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer);
         mHaveNewSurface = true;
         makeCurrent();
     } else {
@@ -103,6 +105,10 @@
     makeCurrent();
 }
 
+void CanvasContext::setSwapBehavior(SwapBehavior swapBehavior) {
+    mSwapBehavior = swapBehavior;
+}
+
 bool CanvasContext::initialize(ANativeWindow* window) {
     setSurface(window);
     if (mCanvas) return false;
@@ -200,7 +206,7 @@
     if (width != mCanvas->getViewportWidth() || height != mCanvas->getViewportHeight()) {
         mCanvas->setViewport(width, height);
         dirty.setEmpty();
-    } else if (!mDirtyRegionsEnabled || mHaveNewSurface) {
+    } else if (!mBufferPreserved || mHaveNewSurface) {
         dirty.setEmpty();
     } else {
         if (!dirty.isEmpty() && !dirty.intersect(0, 0, width, height)) {
@@ -330,6 +336,7 @@
     // No context means nothing to free
     if (!thread.eglManager().hasEglContext()) return;
 
+    ATRACE_CALL();
     thread.eglManager().requireGlContext();
     if (level >= TRIM_MEMORY_COMPLETE) {
         Caches::getInstance().flush(Caches::kFlushMode_Full);
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index d4282fa..e20564b 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -48,6 +48,11 @@
 
 class EglManager;
 
+enum SwapBehavior {
+    kSwap_default,
+    kSwap_discardBuffer,
+};
+
 // This per-renderer class manages the bridge between the global EGL context
 // and the render surface.
 // TODO: Rename to Renderer or some other per-window, top-level manager
@@ -57,6 +62,9 @@
             IContextFactory* contextFactory);
     virtual ~CanvasContext();
 
+    // Won't take effect until next EGLSurface creation
+    void setSwapBehavior(SwapBehavior swapBehavior);
+
     bool initialize(ANativeWindow* window);
     void updateSurface(ANativeWindow* window);
     void pauseSurface(ANativeWindow* window);
@@ -111,7 +119,8 @@
     EglManager& mEglManager;
     sp<ANativeWindow> mNativeWindow;
     EGLSurface mEglSurface;
-    bool mDirtyRegionsEnabled;
+    bool mBufferPreserved;
+    SwapBehavior mSwapBehavior;
 
     bool mOpaque;
     OpenGLRenderer* mCanvas;
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index a87834e..760fc15 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -70,12 +70,12 @@
         , mEglConfig(0)
         , mEglContext(EGL_NO_CONTEXT)
         , mPBufferSurface(EGL_NO_SURFACE)
-        , mRequestDirtyRegions(load_dirty_regions_property())
+        , mAllowPreserveBuffer(load_dirty_regions_property())
         , mCurrentSurface(EGL_NO_SURFACE)
         , mAtlasMap(NULL)
         , mAtlasMapSize(0) {
-    mCanSetDirtyRegions = mRequestDirtyRegions;
-    ALOGD("Render dirty regions requested: %s", mRequestDirtyRegions ? "true" : "false");
+    mCanSetPreserveBuffer = mAllowPreserveBuffer;
+    ALOGD("Use EGL_SWAP_BEHAVIOR_PRESERVED: %s", mAllowPreserveBuffer ? "true" : "false");
 }
 
 void EglManager::initialize() {
@@ -113,7 +113,7 @@
 }
 
 void EglManager::loadConfig() {
-    EGLint swapBehavior = mCanSetDirtyRegions ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
+    EGLint swapBehavior = mCanSetPreserveBuffer ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
     EGLint attribs[] = {
             EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
             EGL_RED_SIZE, 8,
@@ -131,10 +131,10 @@
     if (!eglChooseConfig(mEglDisplay, attribs, &mEglConfig, num_configs, &num_configs)
             || num_configs != 1) {
         // Failed to get a valid config
-        if (mCanSetDirtyRegions) {
+        if (mCanSetPreserveBuffer) {
             ALOGW("Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without...");
             // Try again without dirty regions enabled
-            mCanSetDirtyRegions = false;
+            mCanSetPreserveBuffer = false;
             loadConfig();
         } else {
             LOG_ALWAYS_FATAL("Failed to choose config, error = %s", egl_error_str());
@@ -273,25 +273,30 @@
     return false;
 }
 
-bool EglManager::enableDirtyRegions(EGLSurface surface) {
-    if (!mRequestDirtyRegions) return false;
+bool EglManager::setPreserveBuffer(EGLSurface surface, bool preserve) {
+    if (CC_UNLIKELY(!mAllowPreserveBuffer)) return false;
 
-    if (mCanSetDirtyRegions) {
-        if (!eglSurfaceAttrib(mEglDisplay, surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED)) {
+    bool preserved = false;
+    if (mCanSetPreserveBuffer) {
+        preserved = eglSurfaceAttrib(mEglDisplay, surface, EGL_SWAP_BEHAVIOR,
+                preserve ? EGL_BUFFER_PRESERVED : EGL_BUFFER_DESTROYED);
+        if (CC_UNLIKELY(!preserved)) {
             ALOGW("Failed to set EGL_SWAP_BEHAVIOR on surface %p, error=%s",
                     (void*) surface, egl_error_str());
-            return false;
         }
-        return true;
     }
-    // Perhaps it is already enabled?
-    EGLint value;
-    if (!eglQuerySurface(mEglDisplay, surface, EGL_SWAP_BEHAVIOR, &value)) {
-        ALOGW("Failed to query EGL_SWAP_BEHAVIOR on surface %p, error=%p",
-                (void*) surface, egl_error_str());
-        return false;
+    if (CC_UNLIKELY(!preserved)) {
+        // Maybe it's already set?
+        EGLint swapBehavior;
+        if (eglQuerySurface(mEglDisplay, surface, EGL_SWAP_BEHAVIOR, &swapBehavior)) {
+            preserved = (swapBehavior == EGL_BUFFER_PRESERVED);
+        } else {
+            ALOGW("Failed to query EGL_SWAP_BEHAVIOR on surface %p, error=%p",
+                                (void*) surface, egl_error_str());
+        }
     }
-    return value == EGL_BUFFER_PRESERVED;
+
+    return preserved;
 }
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h
index 71213fb..ae03ea1 100644
--- a/libs/hwui/renderthread/EglManager.h
+++ b/libs/hwui/renderthread/EglManager.h
@@ -49,7 +49,8 @@
     void beginFrame(EGLSurface surface, EGLint* width, EGLint* height);
     bool swapBuffers(EGLSurface surface);
 
-    bool enableDirtyRegions(EGLSurface surface);
+    // Returns true iff the surface is now preserving buffers.
+    bool setPreserveBuffer(EGLSurface surface, bool preserve);
 
     void setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t mapSize);
 
@@ -71,8 +72,8 @@
     EGLContext mEglContext;
     EGLSurface mPBufferSurface;
 
-    const bool mRequestDirtyRegions;
-    bool mCanSetDirtyRegions;
+    const bool mAllowPreserveBuffer;
+    bool mCanSetPreserveBuffer;
 
     EGLSurface mCurrentSurface;
 
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 047819d..8f99b4e 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -103,6 +103,18 @@
     post(task);
 }
 
+CREATE_BRIDGE2(setSwapBehavior, CanvasContext* context, SwapBehavior swapBehavior) {
+    args->context->setSwapBehavior(args->swapBehavior);
+    return NULL;
+}
+
+void RenderProxy::setSwapBehavior(SwapBehavior swapBehavior) {
+    SETUP_TASK(setSwapBehavior);
+    args->context = mContext;
+    args->swapBehavior = swapBehavior;
+    post(task);
+}
+
 CREATE_BRIDGE1(loadSystemProperties, CanvasContext* context) {
     bool needsRedraw = false;
     if (Caches::hasInstance()) {
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 678e7e2..dddf0c7 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -31,6 +31,7 @@
 
 #include "../Caches.h"
 #include "../IContextFactory.h"
+#include "CanvasContext.h"
 #include "DrawFrameTask.h"
 
 namespace android {
@@ -44,7 +45,6 @@
 
 namespace renderthread {
 
-class CanvasContext;
 class ErrorChannel;
 class RenderThread;
 class RenderProxyBridge;
@@ -63,6 +63,8 @@
     ANDROID_API virtual ~RenderProxy();
 
     ANDROID_API void setFrameInterval(nsecs_t frameIntervalNanos);
+    // Won't take effect until next EGLSurface creation
+    ANDROID_API void setSwapBehavior(SwapBehavior swapBehavior);
     ANDROID_API bool loadSystemProperties();
 
     ANDROID_API bool initialize(const sp<ANativeWindow>& window);
diff --git a/libs/hwui/tests/Android.mk b/libs/hwui/tests/Android.mk
new file mode 100644
index 0000000..9622073
--- /dev/null
+++ b/libs/hwui/tests/Android.mk
@@ -0,0 +1,55 @@
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+local_target_dir := $(TARGET_OUT_DATA)/local/tmp
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES
+LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_VIEW -DLOG_TAG=\"OpenGLRenderer\"
+
+LOCAL_SRC_FILES:= \
+	TestContext.cpp \
+	main.cpp
+
+LOCAL_C_INCLUDES += \
+	$(LOCAL_PATH)/.. \
+	external/skia/src/core
+
+LOCAL_SHARED_LIBRARIES := \
+	liblog \
+	libcutils \
+	libutils \
+	libskia \
+	libgui \
+	libui \
+	libhwui
+
+ifeq ($(WITH_MALLOC_LEAK_CHECK),true)
+	LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK
+endif
+
+LOCAL_MODULE_PATH := $(local_target_dir)
+LOCAL_MODULE:= hwuitest
+LOCAL_MODULE_TAGS := tests
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := hwuitest
+LOCAL_MODULE_STEM_64 := hwuitest64
+
+include external/stlport/libstlport.mk
+include $(BUILD_EXECUTABLE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libs/hwui/tests/TestContext.cpp b/libs/hwui/tests/TestContext.cpp
new file mode 100644
index 0000000..35e402d
--- /dev/null
+++ b/libs/hwui/tests/TestContext.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TestContext.h"
+
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+
+using namespace android;
+
+DisplayInfo gDisplay;
+sp<SurfaceComposerClient> gSession;
+
+void createTestEnvironment() {
+    gSession = new SurfaceComposerClient();
+    sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
+                ISurfaceComposer::eDisplayIdMain));
+    status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &gDisplay);
+    LOG_ALWAYS_FATAL_IF(status, "Failed to get display info\n");
+}
+
+sp<SurfaceControl> createWindow(int width, int height) {
+    sp<SurfaceControl> control = gSession->createSurface(String8("HwuiTest"),
+            width, height, PIXEL_FORMAT_RGBX_8888);
+
+    SurfaceComposerClient::openGlobalTransaction();
+    control->setLayer(0x7FFFFFF);
+    control->show();
+    SurfaceComposerClient::closeGlobalTransaction();
+
+    return control;
+}
diff --git a/libs/hwui/tests/TestContext.h b/libs/hwui/tests/TestContext.h
new file mode 100644
index 0000000..8a5d530
--- /dev/null
+++ b/libs/hwui/tests/TestContext.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TESTCONTEXT_H
+#define TESTCONTEXT_H
+
+#include <ui/DisplayInfo.h>
+#include <gui/SurfaceControl.h>
+
+extern android::DisplayInfo gDisplay;
+#define dp(x) ((x) * gDisplay.density)
+
+// Initializes all the static globals that are shared across all contexts
+// such as display info
+void createTestEnvironment();
+
+// Defaults to fullscreen
+android::sp<android::SurfaceControl> createWindow(int width = -1, int height = -1);
+
+#endif
diff --git a/libs/hwui/tests/main.cpp b/libs/hwui/tests/main.cpp
new file mode 100644
index 0000000..2d99e9f
--- /dev/null
+++ b/libs/hwui/tests/main.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+
+#include <cutils/log.h>
+#include <gui/Surface.h>
+#include <ui/PixelFormat.h>
+
+#include <AnimationContext.h>
+#include <DisplayListRenderer.h>
+#include <RenderNode.h>
+#include <renderthread/RenderProxy.h>
+
+#include "TestContext.h"
+
+using namespace android;
+using namespace android::uirenderer;
+using namespace android::uirenderer::renderthread;
+
+class ContextFactory : public IContextFactory {
+public:
+    virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) {
+        return new AnimationContext(clock);
+    }
+};
+
+static DisplayListRenderer* startRecording(RenderNode* node) {
+    DisplayListRenderer* renderer = new DisplayListRenderer();
+    renderer->setViewport(node->getWidth(), node->getHeight());
+    renderer->prepare(false);
+    return renderer;
+}
+
+static void endRecording(DisplayListRenderer* renderer, RenderNode* node) {
+    renderer->finish();
+    node->setStagingDisplayList(renderer->finishRecording());
+    delete renderer;
+}
+
+sp<RenderNode> createCard(int x, int y, int width, int height) {
+    sp<RenderNode> node = new RenderNode();
+    node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
+    node->mutateStagingProperties().setElevation(dp(16));
+    node->mutateStagingProperties().mutableOutline().setRoundRect(0, 0, width, height, dp(10), 1);
+    node->mutateStagingProperties().mutableOutline().setShouldClip(true);
+    node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y | RenderNode::Z);
+
+    DisplayListRenderer* renderer = startRecording(node.get());
+    renderer->drawColor(0xFFEEEEEE, SkXfermode::kSrcOver_Mode);
+    endRecording(renderer, node.get());
+
+    return node;
+}
+
+int main(int argc, char* argv[]) {
+    createTestEnvironment();
+
+    // create the native surface
+    const int width = gDisplay.w;
+    const int height = gDisplay.h;
+    sp<SurfaceControl> control = createWindow(width, height);
+    sp<Surface> surface = control->getSurface();
+
+    RenderNode* rootNode = new RenderNode();
+    rootNode->incStrong(0);
+    rootNode->mutateStagingProperties().setLeftTopRightBottom(0, 0, width, height);
+    rootNode->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+    rootNode->mutateStagingProperties().setClipToBounds(false);
+    rootNode->setPropertyFieldsDirty(RenderNode::GENERIC);
+
+    ContextFactory factory;
+    RenderProxy* proxy = new RenderProxy(false, rootNode, &factory);
+    proxy->loadSystemProperties();
+    proxy->initialize(surface);
+    float lightX = width / 2.0;
+    proxy->setup(width, height, (Vector3){lightX, dp(-200.0f), dp(800.0f)},
+            dp(800.0f), 255 * 0.075, 255 * 0.15);
+
+    android::uirenderer::Rect DUMMY;
+
+    std::vector< sp<RenderNode> > cards;
+
+    DisplayListRenderer* renderer = startRecording(rootNode);
+    renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
+    renderer->insertReorderBarrier(true);
+
+    for (int x = dp(16); x < (width - dp(116)); x += dp(116)) {
+        for (int y = dp(16); y < (height - dp(116)); y += dp(116)) {
+            sp<RenderNode> card = createCard(x, y, dp(100), dp(100));
+            renderer->drawRenderNode(card.get(), DUMMY, 0);
+            cards.push_back(card);
+        }
+    }
+
+    renderer->insertReorderBarrier(false);
+    endRecording(renderer, rootNode);
+
+    for (int i = 0; i < 150; i++) {
+        ATRACE_NAME("UI-Draw Frame");
+        for (int ci = 0; ci < cards.size(); ci++) {
+            cards[ci]->mutateStagingProperties().setTranslationX(i);
+            cards[ci]->mutateStagingProperties().setTranslationY(i);
+            cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+        }
+        nsecs_t frameTimeNs = systemTime(CLOCK_MONOTONIC);
+        proxy->syncAndDrawFrame(frameTimeNs, 0, gDisplay.density);
+        usleep(12000);
+    }
+
+    sleep(5);
+
+    delete proxy;
+    rootNode->decStrong(0);
+
+    printf("Success!\n");
+    return 0;
+}
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 4f8facb..5d5ea02 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -332,8 +332,13 @@
         }
 
         /**
-         * Sends the change on the track information. This is expected to be called whenever a track
-         * is added/removed and the metadata of a track is modified.
+         * Sends the list of all audio/video/subtitle tracks. The is used by the framework to
+         * maintain the track information for a given session, which in turn is used by
+         * {@link TvView#getTracks} for the application to retrieve metadata for a given track type.
+         * The TV input service must call this method as soon as the track information becomes
+         * available or is updated. Note that in a case where a part of the information for a
+         * certain track is updated, it is not necessary to create a new {@link TvTrackInfo} object
+         * with a different track ID.
          *
          * @param tracks A list which includes track information.
          * @throws IllegalArgumentException if {@code tracks} contains redundant tracks.
@@ -364,8 +369,12 @@
         }
 
         /**
-         * Sends the ID of the selected track for a given track type. This is expected to be called
-         * whenever there is a change on track selection.
+         * Sends the type and ID of a selected track. This is used to inform the application that a
+         * specific track is selected. The TV input service must call this method as soon as a track
+         * is selected either by default or in response to a call to {@link #onSelectTrack}. The
+         * selected track ID for a given type is maintained in the framework until the next call to
+         * this method even after the entire track list is updated (but is reset when the session is
+         * tuned to a new channel), so care must be taken not to result in an obsolete track ID.
          *
          * @param type The type of the selected track. The type can be
          *            {@link TvTrackInfo#TYPE_AUDIO}, {@link TvTrackInfo#TYPE_VIDEO} or
@@ -1067,9 +1076,19 @@
 
     /**
      * Base class for a TV input session which represents an external device connected to a
-     * hardware TV input. Once TV input returns an implementation of this class on
-     * {@link #onCreateSession(String)}, the framework will create a hardware session and forward
-     * the application's surface to the hardware TV input.
+     * hardware TV input.
+     * <p>
+     * This class is for an input which provides channels for the external set-top box to the
+     * application. Once a TV input returns an implementation of this class on
+     * {@link #onCreateSession(String)}, the framework will create a separate session for
+     * a hardware TV Input (e.g. HDMI 1) and forward the application's surface to the session so
+     * that the user can see the screen of the hardware TV Input when she tunes to a channel from
+     * this TV input. The implementation of this class is expected to change the channel of the
+     * external set-top box via a proprietary protocol when {@link HardwareSession#onTune(Uri)} is
+     * requested by the application.
+     * </p><p>
+     * Note that this class is not for inputs for internal hardware like built-in tuner and HDMI 1.
+     * </p>
      * @see #onCreateSession(String)
      */
     public abstract static class HardwareSession extends Session {
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index 19b54a6..62b4a36 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -207,7 +207,8 @@
         return; // Already threw.
     }
     mLongBuffer = (jlongArray)env->NewGlobalRef(longArray);
-    jcharArray charArray = env->NewCharArray(256);
+    // Needs to be long enough to hold a file path for getObjectFilePath()
+    jcharArray charArray = env->NewCharArray(PATH_MAX + 1);
     if (!charArray) {
         return; // Already threw.
     }
@@ -761,7 +762,7 @@
     return result;
 }
 
-static void foreachentry(ExifEntry *entry, void *user) {
+static void foreachentry(ExifEntry *entry, void * /*user*/) {
     char buf[1024];
     ALOGI("entry %x, format %d, size %d: %s",
             entry->tag, entry->format, entry->size, exif_entry_get_value(entry, buf, sizeof(buf)));
diff --git a/media/tests/omxjpegdecoder/Android.mk b/media/tests/omxjpegdecoder/Android.mk
deleted file mode 100644
index b0bc5d4..0000000
--- a/media/tests/omxjpegdecoder/Android.mk
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright (C) 2009 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-        omx_jpeg_decoder.cpp \
-        jpeg_decoder_bench.cpp \
-        StreamSource.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    libskia \
-    libstagefright \
-    libstagefright_foundation \
-    libbinder \
-    libutils \
-    liblog \
-    libjpeg
-
-LOCAL_C_INCLUDES := \
-    $(TOP)/external/jpeg \
-    $(TOP)/frameworks/base/media/libstagefright \
-    $(TOP)/frameworks/base/include/ \
-    $(TOP)/frameworks/base/ \
-    $(TOP)/frameworks/native/include/media/openmax
-
-LOCAL_MODULE := jpeg_bench
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
diff --git a/media/tests/omxjpegdecoder/StreamSource.cpp b/media/tests/omxjpegdecoder/StreamSource.cpp
deleted file mode 100644
index f764121a..0000000
--- a/media/tests/omxjpegdecoder/StreamSource.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <media/stagefright/foundation/ADebug.h>
-
-#include "StreamSource.h"
-
-namespace android {
-
-StreamSource::StreamSource(SkStream *stream)
-        : mStream(stream) {
-    CHECK(stream != NULL);
-    mSize = stream->getLength();
-}
-
-StreamSource::~StreamSource() {
-    delete mStream;
-    mStream = NULL;
-}
-
-status_t StreamSource::initCheck() const {
-    return mStream != NULL ? OK : NO_INIT;
-}
-
-ssize_t StreamSource::readAt(off64_t offset, void *data, size_t size) {
-    Mutex::Autolock autoLock(mLock);
-
-    mStream->rewind();
-    mStream->skip(offset);
-    ssize_t result = mStream->read(data, size);
-
-    return result;
-}
-
-status_t StreamSource::getSize(off64_t *size) {
-      *size = mSize;
-      return OK;
-}
-
-}  // namespace android
diff --git a/media/tests/omxjpegdecoder/StreamSource.h b/media/tests/omxjpegdecoder/StreamSource.h
deleted file mode 100644
index 9807385..0000000
--- a/media/tests/omxjpegdecoder/StreamSource.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef STREAM_SOURCE_H_
-
-#define STREAM_SOURCE_H_
-
-#include <stdio.h>
-
-#include <SkStream.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaErrors.h>
-#include <utils/threads.h>
-
-namespace android {
-
-class StreamSource : public DataSource {
-public:
-    // Pass the ownership of SkStream to StreamSource.
-    StreamSource(SkStream *SkStream);
-    virtual status_t initCheck() const;
-    virtual ssize_t readAt(off64_t offset, void *data, size_t size);
-    virtual status_t getSize(off64_t *size);
-
-protected:
-    virtual ~StreamSource();
-
-private:
-    SkStream *mStream;
-    size_t mSize;
-    Mutex mLock;
-
-    StreamSource(const StreamSource &);
-    StreamSource &operator=(const StreamSource &);
-};
-
-}  // namespace android
-
-#endif  // STREAM_SOURCE_H_
diff --git a/media/tests/omxjpegdecoder/jpeg_decoder_bench.cpp b/media/tests/omxjpegdecoder/jpeg_decoder_bench.cpp
deleted file mode 100644
index de6294d..0000000
--- a/media/tests/omxjpegdecoder/jpeg_decoder_bench.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "OmxJpegDecoder"
-#include <sys/time.h>
-#include <utils/Log.h>
-
-#include <binder/ProcessState.h>
-
-#include "SkBitmap.h"
-#include "SkImageDecoder.h"
-#include "SkStream.h"
-#include "omx_jpeg_decoder.h"
-
-class SkJPEGImageDecoder : public SkImageDecoder {
-public:
-    virtual Format getFormat() const {
-        return kJPEG_Format;
-    }
-
-protected:
-    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode);
-};
-
-int nullObjectReturn(const char msg[]) {
-    if (msg) {
-        SkDebugf("--- %s\n", msg);
-    }
-    return -1;
-}
-
-static int64_t getNowUs() {
-    struct timeval tv;
-    gettimeofday(&tv, NULL);
-
-    return tv.tv_usec + (int64_t) tv.tv_sec * 1000000;
-}
-
-int testDecodeBounds(SkImageDecoder* decoder, SkStream* stream,
-        SkBitmap* bitmap) {
-    int64_t startTime = getNowUs();
-    SkColorType prefColorType = kN32_SkColorType;
-    SkImageDecoder::Mode decodeMode = SkImageDecoder::kDecodeBounds_Mode;
-
-    // Decode the input stream and then use the bitmap.
-    if (!decoder->decode(stream, bitmap, prefColorType, decodeMode)) {
-        return nullObjectReturn("decoder->decode returned false");
-    } else {
-        int64_t delay = getNowUs() - startTime;
-        printf("WidthxHeight: %dx%d\n", bitmap->width(), bitmap->height());
-        printf("Decoding Time in BoundsMode %.1f msec.\n", delay / 1000.0f);
-        return 0;
-    }
-}
-
-int testDecodePixels(SkImageDecoder* decoder, SkStream* stream,
-        SkBitmap* bitmap) {
-    int64_t startTime = getNowUs();
-    SkColorType prefColorType = kN32_SkColorType;
-    SkImageDecoder::Mode decodeMode = SkImageDecoder::kDecodePixels_Mode;
-
-    // Decode the input stream and then use the bitmap.
-    if (!decoder->decode(stream, bitmap, prefColorType, decodeMode)) {
-        return nullObjectReturn("decoder->decode returned false");
-    } else {
-        int64_t delay = getNowUs() - startTime;
-        printf("Decoding Time in PixelsMode %.1f msec.\n", delay / 1000.0f);
-        const char* filename = "/sdcard/omxJpegDecodedBitmap.rgba";
-        return storeBitmapToFile(bitmap, filename);
-    }
-}
-
-int testDecoder(SkImageDecoder* decoder, char* filename) {
-    // test DecodeMode == Pixels
-    SkStream* stream = new SkFILEStream(filename);
-    SkBitmap* bitmap = new SkBitmap;
-    testDecodePixels(decoder, stream, bitmap);
-    delete bitmap;
-
-    // test DecodeMode == Bounds
-    stream = new SkFILEStream(filename);
-    bitmap = new SkBitmap;
-    testDecodeBounds(decoder, stream, bitmap);
-    delete bitmap;
-
-    delete decoder;
-    return 0;
-}
-
-int main(int argc, char** argv) {
-    android::ProcessState::self()->startThreadPool();
-
-    printf("Decoding jpeg with libjpeg...\n");
-    SkJPEGImageDecoder* libjpeg = new SkJPEGImageDecoder;
-    testDecoder(libjpeg, argv[1]);
-
-    printf("\nDecoding jpeg with OMX...\n");
-    OmxJpegImageDecoder* omx = new OmxJpegImageDecoder;
-    testDecoder(omx, argv[1]);
-    return 0;
-}
diff --git a/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp b/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
deleted file mode 100644
index 229bfdb..0000000
--- a/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "OmxJpegDecoder"
-#include <sys/time.h>
-#include <utils/Log.h>
-
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <binder/IServiceManager.h>
-#include <binder/ProcessState.h>
-#include <media/IMediaPlayerService.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/OMXClient.h>
-#include <media/stagefright/OMXCodec.h>
-#include <SkImage.h>
-#include <SkMallocPixelRef.h>
-
-#include "omx_jpeg_decoder.h"
-#include "StreamSource.h"
-
-using namespace android;
-
-static void getJpegOutput(MediaBuffer* buffer, const char* filename) {
-    int size = buffer->range_length();
-    int offset = buffer->range_offset();
-    FILE *pFile = fopen(filename, "w+");
-
-    if (pFile == NULL) {
-        printf("Error: cannot open %s.\n", filename);
-    } else {
-        char* data = (char*) buffer->data();
-        data += offset;
-        while (size > 0) {
-            int numChars = fwrite(data, sizeof(char), 1024, pFile);
-            int numBytes = numChars * sizeof(char);
-            size -= numBytes;
-            data += numBytes;
-        }
-        fclose(pFile);
-    }
-    return;
-}
-
-extern int storeBitmapToFile(SkBitmap* bitmap, const char* filename) {
-    bitmap->lockPixels();
-    uint8_t* data = (uint8_t *)bitmap->getPixels();
-    int size = bitmap->getSize();
-    FILE* fp = fopen(filename, "w+");
-
-    if (NULL == fp) {
-        printf("Cannot open the output file! \n");
-        return -1;
-    } else {
-        while (size > 0) {
-            int numChars = fwrite(data, sizeof(char), 1024, fp);
-            int numBytes = numChars * sizeof(char);
-            size -= numBytes;
-            data += numBytes;
-        }
-        fclose(fp);
-    }
-    return 0;
-}
-
-static int64_t getNowUs() {
-    struct timeval tv;
-    gettimeofday(&tv, NULL);
-
-    return (int64_t)tv.tv_usec + tv.tv_sec * 1000000;
-}
-
-OmxJpegImageDecoder::OmxJpegImageDecoder() {
-    status_t err = mClient.connect();
-    CHECK_EQ(err, (status_t)OK);
-}
-
-OmxJpegImageDecoder::~OmxJpegImageDecoder() {
-    mClient.disconnect();
-}
-
-bool OmxJpegImageDecoder::onDecode(SkStream* stream,
-        SkBitmap* bm, Mode mode) {
-    sp<MediaSource> source = prepareMediaSource(stream);
-    sp<MetaData> meta = source->getFormat();
-    int width;
-    int height;
-    meta->findInt32(kKeyWidth, &width);
-    meta->findInt32(kKeyHeight, &height);
-    configBitmapSize(
-            bm, getPrefColorType(k32Bit_SrcDepth, false),
-            width, height);
-
-    // mode == DecodeBounds
-    if (mode == SkImageDecoder::kDecodeBounds_Mode) {
-        return true;
-    }
-
-    // mode == DecodePixels
-    if (!this->allocPixelRef(bm, NULL)) {
-        ALOGI("Cannot allocPixelRef()!");
-        return false;
-    }
-
-    sp<MediaSource> decoder = getDecoder(&mClient, source);
-    return decodeSource(decoder, source, bm);
-}
-
-JPEGSource* OmxJpegImageDecoder::prepareMediaSource(SkStream* stream) {
-    DataSource::RegisterDefaultSniffers();
-    sp<DataSource> dataSource = new StreamSource(stream);
-    return new JPEGSource(dataSource);
-}
-
-sp<MediaSource> OmxJpegImageDecoder::getDecoder(
-        OMXClient *client, const sp<MediaSource>& source) {
-    sp<MetaData> meta = source->getFormat();
-    sp<MediaSource> decoder = OMXCodec::Create(
-            client->interface(), meta, false /* createEncoder */, source);
-
-    CHECK(decoder != NULL);
-    return decoder;
-}
-
-bool OmxJpegImageDecoder::decodeSource(sp<MediaSource> decoder,
-        const sp<MediaSource>& source, SkBitmap* bm) {
-    status_t rt = decoder->start();
-    if (rt != OK) {
-        ALOGE("Cannot start OMX Decoder!");
-        return false;
-    }
-    int64_t startTime = getNowUs();
-    MediaBuffer *buffer;
-
-    // decode source
-    status_t err = decoder->read(&buffer, NULL);
-    int64_t duration = getNowUs() - startTime;
-
-    if (err != OK) {
-        CHECK(buffer == NULL);
-    }
-    printf("Duration in decoder->read(): %.1f (msecs). \n",
-                duration / 1E3 );
-
-    // Copy pixels from buffer to bm.
-    // May need to check buffer->rawBytes() == bm->rawBytes().
-    CHECK_EQ(buffer->size(), bm->getSize());
-    memcpy(bm->getPixels(), buffer->data(), buffer->size());
-    buffer->release();
-    decoder->stop();
-
-    return true;
-}
-
-void OmxJpegImageDecoder::configBitmapSize(SkBitmap* bm, SkColorType pref,
-        int width, int height) {
-    // Set the color space to ARGB_8888 for now (ignoring pref)
-    // because of limitation in hardware support.
-    bm->setInfo(SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType));
-}
diff --git a/media/tests/omxjpegdecoder/omx_jpeg_decoder.h b/media/tests/omxjpegdecoder/omx_jpeg_decoder.h
deleted file mode 100644
index e487245..0000000
--- a/media/tests/omxjpegdecoder/omx_jpeg_decoder.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef OMXJPEGIMAGEDECODER
-#define OMXJPEGIMAGEDECODER
-
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <media/stagefright/JPEGSource.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/OMXClient.h>
-#include <media/stagefright/OMXCodec.h>
-#include <SkImageDecoder.h>
-#include <SkStream.h>
-
-using namespace android;
-
-extern int storeBitmapToFile(SkBitmap* bitmap, const char* filename);
-
-class OmxJpegImageDecoder : public SkImageDecoder {
-public:
-    OmxJpegImageDecoder();
-    ~OmxJpegImageDecoder();
-
-    virtual Format getFormat() const {
-        return kJPEG_Format;
-    }
-
-protected:
-    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode);
-
-private:
-    JPEGSource* prepareMediaSource(SkStream* stream);
-    sp<MediaSource> getDecoder(OMXClient* client, const sp<MediaSource>& source);
-    bool decodeSource(sp<MediaSource> decoder, const sp<MediaSource>& source,
-            SkBitmap* bm);
-    void configBitmapSize(SkBitmap* bm, SkColorType, int width, int height);
-
-    OMXClient mClient;
-};
-
-#endif
diff --git a/packages/BackupRestoreConfirmation/res/values-hi/strings.xml b/packages/BackupRestoreConfirmation/res/values-hi/strings.xml
index 3621ebf..71a319f 100644
--- a/packages/BackupRestoreConfirmation/res/values-hi/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-hi/strings.xml
@@ -26,7 +26,7 @@
     <string name="deny_restore_button_label" msgid="1724367334453104378">"पुनर्स्‍थापित न करें"</string>
     <string name="current_password_text" msgid="8268189555578298067">"कृपया नीचे अपना वर्तमान सुरक्षित करने का पासवर्ड डालें:"</string>
     <string name="device_encryption_restore_text" msgid="1570864916855208992">"कृपया नीचे अपना उपकरण एन्‍क्रिप्शन पासवर्ड डालें."</string>
-    <string name="device_encryption_backup_text" msgid="5866590762672844664">"कृपया अपना उपकरण सुरक्षित तरीका पासवर्ड नीचे दर्ज करें. बैकअप मेमोरी को एन्‍क्रिप्‍ट करने के लिए भी इसका उपयोग किया जाएगा."</string>
+    <string name="device_encryption_backup_text" msgid="5866590762672844664">"कृपया अपना उपकरण सुरक्षित तरीका पासवर्ड नीचे दर्ज करें. बैकअप संग्रहण को एन्‍क्रिप्‍ट करने के लिए भी इसका उपयोग किया जाएगा."</string>
     <string name="backup_enc_password_text" msgid="4981585714795233099">"कृपया संपूर्ण सुरक्षित डेटा को एन्‍क्रि‍प्‍ट करने में उपयोग के लि‍ए पासवर्ड डालें. यदि‍ यह खाली छोड़ दि‍या जाता है, तो आपके वर्तमान बैकअप पासवर्ड का उपयोग कि‍या जाएगा:"</string>
     <string name="backup_enc_password_optional" msgid="1350137345907579306">"यदि‍ आप संपूर्ण सुरक्षित डेटा को एन्‍क्रि‍प्‍ट करना चाहते हैं, तो नीचे पासवर्ड डालें:"</string>
     <string name="backup_enc_password_required" msgid="7889652203371654149">"चूंकि आपका उपकरण एन्क्रिप्ट किया हुआ है, इसलिए आपको अपने बैकअप को एन्क्रिप्ट करना आवश्यक है. कृपया नीचे पासवर्ड डालें:"</string>
diff --git a/packages/Keyguard/res/values-hi/strings.xml b/packages/Keyguard/res/values-hi/strings.xml
index b8c3358..423c2765 100644
--- a/packages/Keyguard/res/values-hi/strings.xml
+++ b/packages/Keyguard/res/values-hi/strings.xml
@@ -36,19 +36,19 @@
     <string name="keyguard_low_battery" msgid="8143808018719173859">"अपना चार्जर कनेक्‍ट करें."</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"अनलॉक करने के लिए मेनू दबाएं."</string>
     <string name="keyguard_network_locked_message" msgid="9169717779058037168">"नेटवर्क लॉक किया गया"</string>
-    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"कोई सिम कार्ड नहीं है"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"टेबलेट में कोई सिम कार्ड नहीं है."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"फ़ोन में कोई सिम कार्ड नहीं है."</string>
-    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"सिम कार्ड डालें."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"सिम कार्ड गुम है या पढ़ने योग्‍य नहीं है. सिम कार्ड डालें."</string>
-    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"अनुपयोगी सिम कार्ड."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"आपका सिम कार्ड स्‍थायी रूप से अक्षम कर दिया गया है.\n दूसरे सिम कार्ड के लिए अपने वायरलेस सेवा प्रदाता से संपर्क करें."</string>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"कोई SIM कार्ड नहीं है"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"टेबलेट में कोई SIM कार्ड नहीं है."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"फ़ोन में कोई SIM कार्ड नहीं है."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"SIM कार्ड डालें."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM कार्ड गुम है या पढ़ने योग्‍य नहीं है. SIM कार्ड डालें."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"अनुपयोगी SIM कार्ड."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"आपका SIM कार्ड स्‍थायी रूप से अक्षम कर दिया गया है.\n दूसरे SIM कार्ड के लिए अपने वायरलेस सेवा प्रदाता से संपर्क करें."</string>
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"सिम कार्ड लॉक है."</string>
-    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"सिम कार्ड PUK द्वारा लॉक किया हुआ है."</string>
-    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"सिम कार्ड अनलॉक हो रहा है…"</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM कार्ड PUK द्वारा लॉक किया हुआ है."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM कार्ड अनलॉक हो रहा है…"</string>
     <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. %3$d विजेट में से %2$d."</string>
     <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"विजेट जोड़ें"</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"खाली"</string>
+    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"रिक्त"</string>
     <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"अनलॉक क्षेत्र को विस्तृत कर दिया गया."</string>
     <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"अनलॉक क्षेत्र को संक्षिप्त कर दिया गया."</string>
     <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> विजेट."</string>
@@ -83,7 +83,7 @@
     <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
     <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"रहने दें"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"रद्द करें"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"हटाएं"</string>
     <string name="keyboardview_keycode_done" msgid="1992571118466679775">"पूर्ण"</string>
     <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Mode change"</string>
@@ -112,7 +112,7 @@
     <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"सिम अब अक्षम हो गई है. जारी रखने के लिए PUK कोड डालें. विवरण के लिए कैरियर से संपर्क करें."</string>
     <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"इच्छित पिन कोड डालें"</string>
     <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"इच्छित पिन कोड की पुष्टि करें"</string>
-    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"सिम कार्ड अनलॉक कर रहा है…"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM कार्ड अनलॉक कर रहा है…"</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"ऐसा PIN लिखें, जो 4 से 8 अंकों का हो."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK कोड 8 या अधिक संख्या वाला होना चाहिए."</string>
     <string name="kg_invalid_puk" msgid="3638289409676051243">"सही PUK कोड पुन: डालें. बार-बार प्रयास करने से सिम स्थायी रूप से अक्षम हो जाएगी."</string>
diff --git a/packages/Keyguard/res/values-sw/strings.xml b/packages/Keyguard/res/values-sw/strings.xml
index 7b4f46b..814dc90 100644
--- a/packages/Keyguard/res/values-sw/strings.xml
+++ b/packages/Keyguard/res/values-sw/strings.xml
@@ -39,8 +39,8 @@
     <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Hakuna SIM kadi"</string>
     <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Hakuna SIM kadi katika kompyuta ndogo."</string>
     <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Hakuna SIM kadi kwenye simu."</string>
-    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Weka SIM kadi."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM kadi haiko au haisomeki. Weka SIM kadi."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Ingiza SIM kadi."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM kadi haiko au haisomeki. Ingiza SIM kadi."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"SIM kadi isiyotumika."</string>
     <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"SIM kadi yako imefungwa kabisa.\n Wasiliana na mtoa huduma wako wa pasi waya ili upate SIM kadi nyingine."</string>
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM kadi imefungwa."</string>
diff --git a/packages/Keyguard/res/values-sw600dp/bools.xml b/packages/Keyguard/res/values-sw600dp/bools.xml
index ddc48c5..00f45c1 100644
--- a/packages/Keyguard/res/values-sw600dp/bools.xml
+++ b/packages/Keyguard/res/values-sw600dp/bools.xml
@@ -19,7 +19,6 @@
     <bool name="show_ongoing_ime_switcher">true</bool>
     <bool name="kg_share_status_area">false</bool>
     <bool name="kg_sim_puk_account_full_screen">false</bool>
-    <bool name="kg_show_ime_at_screen_on">false</bool>
     <!-- No camera for you, tablet user -->
     <bool name="kg_enable_camera_default_widget">false</bool>
     <bool name="kg_center_small_widgets_vertically">true</bool>
diff --git a/packages/Keyguard/res/values-zh-rCN/strings.xml b/packages/Keyguard/res/values-zh-rCN/strings.xml
index 295df9c..8e8c4c8 100644
--- a/packages/Keyguard/res/values-zh-rCN/strings.xml
+++ b/packages/Keyguard/res/values-zh-rCN/strings.xml
@@ -21,14 +21,14 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="719438068451601849">"Keyguard"</string>
-    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"输入PIN码"</string>
-    <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"请输入SIM卡PUK码和新的PIN码"</string>
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"输入 PIN 码"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"请输入SIM卡PUK码和新的 PIN 码"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM卡PUK码"</string>
     <string name="keyguard_password_enter_pin_prompt" msgid="3201151840570492538">"新SIM卡PIN码"</string>
     <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"触摸可输入密码"</font></string>
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"输入密码以解锁"</string>
-    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"输入PIN码进行解锁"</string>
-    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN码有误。"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"输入 PIN 进行解锁"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN 码有误。"</string>
     <string name="keyguard_label_text" msgid="861796461028298424">"要解锁,请先按 MENU 再按 0。"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"已超过“人脸解锁”尝试次数上限"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"充电完成"</string>
@@ -62,7 +62,7 @@
     <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"滑动解锁。"</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"图案解锁。"</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"人脸解锁。"</string>
-    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PIN码解锁。"</string>
+    <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PIN 解锁。"</string>
     <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"密码解锁。"</string>
     <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"图案区域。"</string>
     <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"滑动区域。"</string>
@@ -103,20 +103,20 @@
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"忘记了图案"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"图案错误"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"密码错误"</string>
-    <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN码有误"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN 有误"</string>
     <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"请在 <xliff:g id="NUMBER">%d</xliff:g> 秒后重试。"</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"绘制您的图案"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"输入SIM卡PIN码"</string>
-    <string name="kg_pin_instructions" msgid="2377242233495111557">"输入PIN码"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"输入 PIN"</string>
     <string name="kg_password_instructions" msgid="5753646556186936819">"输入密码"</string>
     <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM卡已被停用,需要输入PUK码才能继续使用。有关详情,请联系您的运营商。"</string>
-    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"请输入所需的PIN码"</string>
-    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"请确认所需的PIN码"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"请输入所需 PIN 码"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"请确认所需 PIN 码"</string>
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"正在解锁SIM卡..."</string>
-    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"请输入4至8位数的PIN码。"</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"请输入 4 至 8 位数的 PIN。"</string>
     <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK码应至少包含8位数字。"</string>
     <string name="kg_invalid_puk" msgid="3638289409676051243">"请重新输入正确的PUK码。如果尝试错误次数过多,SIM卡将永久停用。"</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN码不匹配"</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN 码不匹配"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"图案尝试次数过多"</string>
     <string name="kg_login_instructions" msgid="1100551261265506448">"要解锁,请登录您的Google帐户。"</string>
     <string name="kg_login_username_hint" msgid="5718534272070920364">"用户名(电子邮件地址)"</string>
@@ -125,13 +125,13 @@
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"用户名或密码无效。"</string>
     <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"忘记了用户名或密码?\n请访问 "<b>"google.com/accounts/recovery"</b>"。"</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"正在检查帐户…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"您已经<xliff:g id="NUMBER_0">%d</xliff:g>次输错了PIN码。\n\n请在<xliff:g id="NUMBER_1">%d</xliff:g>秒后重试。"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地输入了 PIN。\n\n请在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒后重试。"</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地输入了密码。\n\n请在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒后重试。"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地绘制了解锁图案。\n\n请在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒后重试。"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"您已经<xliff:g id="NUMBER_0">%d</xliff:g>次错误地尝试解锁平板电脑。如果再尝试<xliff:g id="NUMBER_1">%d</xliff:g>次后仍不成功,平板电脑就会恢复为出厂默认设置,而且所有用户数据都会丢失。"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"您已经<xliff:g id="NUMBER_0">%d</xliff:g>次错误地尝试解锁手机。如果再尝试<xliff:g id="NUMBER_1">%d</xliff:g>次后仍不成功,手机就会恢复为出厂默认设置,而且所有用户数据都会丢失。"</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"您已经<xliff:g id="NUMBER">%d</xliff:g>次错误地尝试解锁平板电脑。平板电脑现在将恢复为出厂默认设置。"</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"您已经<xliff:g id="NUMBER">%d</xliff:g>次错误地尝试解锁手机。手机现在将恢复为出厂默认设置。"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地尝试解锁平板电脑。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,平板电脑就会重置为出厂默认设置,而且所有用户数据都会丢失。"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地尝试解锁手机。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,手机就会重置为出厂默认设置,而且所有用户数据都会丢失。"</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"您已经 <xliff:g id="NUMBER">%d</xliff:g> 次错误地尝试解锁平板电脑。平板电脑现在将重置为出厂默认设置。"</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"您已经 <xliff:g id="NUMBER">%d</xliff:g> 次错误地尝试解锁手机。手机现在将重置为出厂默认设置。"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地绘制了解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐户解锁平板电脑。\n\n请在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒后重试。"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地绘制了解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐户解锁手机。\n\n请在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒后重试。"</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
diff --git a/packages/Keyguard/res/values-zh-rHK/strings.xml b/packages/Keyguard/res/values-zh-rHK/strings.xml
index f196ffd..064c6df 100644
--- a/packages/Keyguard/res/values-zh-rHK/strings.xml
+++ b/packages/Keyguard/res/values-zh-rHK/strings.xml
@@ -52,7 +52,7 @@
     <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"解鎖區域已展開。"</string>
     <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"解鎖區域已收合。"</string>
     <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>小工具。"</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"使用者選取工具"</string>
+    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"用戶選取工具"</string>
     <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"相機"</string>
     <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"媒體控制"</string>
     <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"已開始為小工具重新排列次序。"</string>
@@ -98,7 +98,7 @@
     <string name="description_direction_down" msgid="5087739728639014595">"向下滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
     <string name="description_direction_left" msgid="7207478719805562165">"向左滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
     <string name="description_direction_right" msgid="8034433242579600980">"向右滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
-    <string name="user_switched" msgid="3768006783166984410">"目前的使用者是<xliff:g id="NAME">%1$s</xliff:g>。"</string>
+    <string name="user_switched" msgid="3768006783166984410">"目前的用戶是<xliff:g id="NAME">%1$s</xliff:g>。"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"緊急電話"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"忘記圖案"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"圖案錯誤"</string>
@@ -119,17 +119,17 @@
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN 碼不符"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"圖案嘗試次數過多"</string>
     <string name="kg_login_instructions" msgid="1100551261265506448">"如要解鎖,請以 Google 帳戶登入。"</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"使用者名稱 (電子郵件)"</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"用戶名稱 (電子郵件)"</string>
     <string name="kg_login_password_hint" msgid="9057289103827298549">"密碼"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"登入"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"無效的使用者名稱或密碼。"</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"忘記使用者名稱或密碼?\n請瀏覽 "<b>"google.com/accounts/recovery"</b>"。"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"無效的用戶名稱或密碼。"</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"忘記用戶名稱或密碼?\n請瀏覽 "<b>"google.com/accounts/recovery"</b>"。"</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"正在檢查帳戶…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"您已輸入錯誤的 PIN 碼 <xliff:g id="NUMBER_0">%d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"您已輸入錯誤的密碼 <xliff:g id="NUMBER_0">%d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"您嘗試了 <xliff:g id="NUMBER_0">%d</xliff:g> 次仍未能成功解開這部上鎖的平板電腦。如果再嘗試 <xliff:g id="NUMBER_1">%d</xliff:g> 次仍未成功,平板電腦將回復原廠設定,所有使用者資料均會失去。"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"您嘗試了 <xliff:g id="NUMBER_0">%d</xliff:g> 次仍未能成功解開這部上鎖的手機。如果再嘗試 <xliff:g id="NUMBER_1">%d</xliff:g> 次仍未成功,手機將回復原廠設定,所有使用者資料均會失去。"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"您嘗試了 <xliff:g id="NUMBER_0">%d</xliff:g> 次仍未能成功解開這部上鎖的平板電腦。如果再嘗試 <xliff:g id="NUMBER_1">%d</xliff:g> 次仍未成功,平板電腦將回復原廠設定,所有用戶資料均會失去。"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"您嘗試了 <xliff:g id="NUMBER_0">%d</xliff:g> 次仍未能成功解開這部上鎖的手機。如果再嘗試 <xliff:g id="NUMBER_1">%d</xliff:g> 次仍未成功,手機將回復原廠設定,所有用戶資料均會失去。"</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"您嘗試了 <xliff:g id="NUMBER">%d</xliff:g> 次仍未能成功解開這部上鎖的平板電腦。平板電腦現在將回復原廠設定。"</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"您嘗試了 <xliff:g id="NUMBER">%d</xliff:g> 次仍未能成功解開這部上鎖的手機。手機現在將回復原廠設定。"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解開上鎖的平板電腦。\n\n請在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒後再試一次。"</string>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index 20254f0..01ea3c8 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -688,43 +688,63 @@
         PrintAttributes currAttributes = mPrintJob.getAttributes();
         PrintAttributes newAttributes = printJobInfo.getAttributes();
 
-        // Take the media size only if the current printer supports is.
-        MediaSize oldMediaSize = currAttributes.getMediaSize();
-        MediaSize newMediaSize = newAttributes.getMediaSize();
-        if (!oldMediaSize.equals(newMediaSize)) {
-            final int mediaSizeCount = mMediaSizeSpinnerAdapter.getCount();
-            MediaSize newMediaSizePortrait = newAttributes.getMediaSize().asPortrait();
-            for (int i = 0; i < mediaSizeCount; i++) {
-                MediaSize supportedSizePortrait = mMediaSizeSpinnerAdapter.getItem(i)
-                        .value.asPortrait();
-                if (supportedSizePortrait.equals(newMediaSizePortrait)) {
-                    currAttributes.setMediaSize(newMediaSize);
-                    mMediaSizeSpinner.setSelection(i);
-                    if (currAttributes.getMediaSize().isPortrait()) {
-                        if (mOrientationSpinner.getSelectedItemPosition() != 0) {
-                            mOrientationSpinner.setSelection(0);
+        if (newAttributes != null) {
+            // Take the media size only if the current printer supports is.
+            MediaSize oldMediaSize = currAttributes.getMediaSize();
+            MediaSize newMediaSize = newAttributes.getMediaSize();
+            if (!oldMediaSize.equals(newMediaSize)) {
+                final int mediaSizeCount = mMediaSizeSpinnerAdapter.getCount();
+                MediaSize newMediaSizePortrait = newAttributes.getMediaSize().asPortrait();
+                for (int i = 0; i < mediaSizeCount; i++) {
+                    MediaSize supportedSizePortrait = mMediaSizeSpinnerAdapter.getItem(i)
+                            .value.asPortrait();
+                    if (supportedSizePortrait.equals(newMediaSizePortrait)) {
+                        currAttributes.setMediaSize(newMediaSize);
+                        mMediaSizeSpinner.setSelection(i);
+                        if (currAttributes.getMediaSize().isPortrait()) {
+                            if (mOrientationSpinner.getSelectedItemPosition() != 0) {
+                                mOrientationSpinner.setSelection(0);
+                            }
+                        } else {
+                            if (mOrientationSpinner.getSelectedItemPosition() != 1) {
+                                mOrientationSpinner.setSelection(1);
+                            }
                         }
-                    } else {
-                        if (mOrientationSpinner.getSelectedItemPosition() != 1) {
-                            mOrientationSpinner.setSelection(1);
-                        }
+                        break;
                     }
-                    break;
                 }
             }
-        }
 
-        // Take the color mode only if the current printer supports it.
-        final int currColorMode = currAttributes.getColorMode();
-        final int newColorMode = newAttributes.getColorMode();
-        if (currColorMode != newColorMode) {
-            final int colorModeCount = mColorModeSpinner.getCount();
-            for (int i = 0; i < colorModeCount; i++) {
-                final int supportedColorMode = mColorModeSpinnerAdapter.getItem(i).value;
-                if (supportedColorMode == newColorMode) {
-                    currAttributes.setColorMode(newColorMode);
-                    mColorModeSpinner.setSelection(i);
-                    break;
+            // Take the resolution only if the current printer supports is.
+            Resolution oldResolution = currAttributes.getResolution();
+            Resolution newResolution = newAttributes.getResolution();
+            if (!oldResolution.equals(newResolution)) {
+                PrinterCapabilitiesInfo capabilities = mCurrentPrinter.getCapabilities();
+                if (capabilities != null) {
+                    List<Resolution> resolutions = capabilities.getResolutions();
+                    final int resolutionCount = resolutions.size();
+                    for (int i = 0; i < resolutionCount; i++) {
+                        Resolution resolution = resolutions.get(i);
+                        if (resolution.equals(newResolution)) {
+                            currAttributes.setResolution(resolution);
+                            break;
+                        }
+                    }
+                }
+            }
+
+            // Take the color mode only if the current printer supports it.
+            final int currColorMode = currAttributes.getColorMode();
+            final int newColorMode = newAttributes.getColorMode();
+            if (currColorMode != newColorMode) {
+                final int colorModeCount = mColorModeSpinner.getCount();
+                for (int i = 0; i < colorModeCount; i++) {
+                    final int supportedColorMode = mColorModeSpinnerAdapter.getItem(i).value;
+                    if (supportedColorMode == newColorMode) {
+                        currAttributes.setColorMode(newColorMode);
+                        mColorModeSpinner.setSelection(i);
+                        break;
+                    }
                 }
             }
         }
diff --git a/packages/SettingsProvider/Android.mk b/packages/SettingsProvider/Android.mk
index da929ae..c16f7b6 100644
--- a/packages/SettingsProvider/Android.mk
+++ b/packages/SettingsProvider/Android.mk
@@ -5,7 +5,7 @@
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
-LOCAL_JAVA_LIBRARIES := telephony-common
+LOCAL_JAVA_LIBRARIES := telephony-common ims-common
 
 LOCAL_PACKAGE_NAME := SettingsProvider
 LOCAL_CERTIFICATE := platform
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 8ac1c96..e56806a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -43,6 +43,7 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.android.ims.ImsConfig;
 import com.android.internal.content.PackageHelper;
 import com.android.internal.telephony.RILConstants;
 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
@@ -70,7 +71,7 @@
     // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
     // is properly propagated through your change.  Not doing so will result in a loss of user
     // settings.
-    private static final int DATABASE_VERSION = 114;
+    private static final int DATABASE_VERSION = 116;
 
     private Context mContext;
     private int mUserHandle;
@@ -1827,20 +1828,41 @@
             upgradeVersion = 113;
         }
 
-        if (upgradeVersion < 114) {
-            db.beginTransaction();
-            SQLiteStatement stmt = null;
-            try {
-                stmt = db.compileStatement("INSERT OR IGNORE INTO global(name,value)"
-                        + " VALUES(?,?);");
-                loadBooleanSetting(stmt, Global.THEATER_MODE_ON,
-                        R.bool.def_theater_mode_on);
-                db.setTransactionSuccessful();
-            } finally {
-                db.endTransaction();
-                if (stmt != null) stmt.close();
+        // We skipped 114 to handle a merge conflict with the introduction of theater mode.
+
+        if (upgradeVersion < 115) {
+            if (mUserHandle == UserHandle.USER_OWNER) {
+                db.beginTransaction();
+                SQLiteStatement stmt = null;
+                try {
+                    stmt = db.compileStatement("INSERT OR IGNORE INTO global(name,value)"
+                            + " VALUES(?,?);");
+                    loadBooleanSetting(stmt, Global.THEATER_MODE_ON,
+                            R.bool.def_theater_mode_on);
+                    db.setTransactionSuccessful();
+                } finally {
+                    db.endTransaction();
+                    if (stmt != null) stmt.close();
+                }
             }
-            upgradeVersion = 114;
+            upgradeVersion = 115;
+        }
+
+        if (upgradeVersion < 116) {
+            if (mUserHandle == UserHandle.USER_OWNER) {
+                db.beginTransaction();
+                SQLiteStatement stmt = null;
+                try {
+                    stmt = db.compileStatement("INSERT OR IGNORE INTO global(name,value)"
+                            + " VALUES(?,?);");
+                    loadSetting(stmt, Settings.Global.ENHANCED_4G_MODE_ENABLED, ImsConfig.FeatureValueConstants.ON);
+                    db.setTransactionSuccessful();
+                } finally {
+                    db.endTransaction();
+                    if (stmt != null) stmt.close();
+                }
+            }
+            upgradeVersion = 116;
         }
 
         // *** Remember to update DATABASE_VERSION above!
@@ -2588,6 +2610,7 @@
 
             loadBooleanSetting(stmt, Settings.Global.GUEST_USER_ENABLED,
                     R.bool.def_guest_user_enabled);
+            loadSetting(stmt, Settings.Global.ENHANCED_4G_MODE_ENABLED, ImsConfig.FeatureValueConstants.ON);
             // --- New global settings start here
         } finally {
             if (stmt != null) stmt.close();
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 7e6afa6..3c44245 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -92,6 +92,7 @@
     <uses-permission android:name="android.permission.FRAME_STATS" />
     <uses-permission android:name="android.permission.BIND_APPWIDGET" />
     <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
+    <uses-permission android:name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"/>
 
     <application android:label="@string/app_label">
         <provider
diff --git a/packages/SystemUI/res/drawable/qs_background_primary.xml b/packages/SystemUI/res/drawable/qs_background_primary.xml
index b4e311f..e33ff1e 100644
--- a/packages/SystemUI/res/drawable/qs_background_primary.xml
+++ b/packages/SystemUI/res/drawable/qs_background_primary.xml
@@ -13,11 +13,8 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:top="@dimen/notification_material_rounded_rect_radius_negative" >
     <solid android:color="@color/system_primary_color" />
-    <corners
-        android:topLeftRadius="0dp"
-        android:topRightRadius="0dp"
-        android:bottomLeftRadius="@dimen/notification_material_rounded_rect_radius"
-        android:bottomRightRadius="@dimen/notification_material_rounded_rect_radius"/>
+    <corners android:radius="@dimen/notification_material_rounded_rect_radius"/>
 </shape>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 7810d91..df8f728 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Voortdurend"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Kennisgewings"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Battery is amper pap"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> oor"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> oor. Batteryspaarder is aan."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> oor"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> oor. Batterybespaarder is aan."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB-laaiery nie ondersteun nie.\nGebruik net die laaier wat verskaf is."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Laai met USB word nie gesteun nie."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Gebruik slegs die laaier wat verskaf is."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Sluimer"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Vliegtuigmodus"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Laai, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Gelaai"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> toestelle)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth af"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Batteryspaarder is aan"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Verminder werkverrigting en agtergronddata"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Skakel batterybespaarder af"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Inhoud versteek"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sal alles begin vasvang wat op jou skerm gewys word."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Moenie weer wys nie"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index fdc465f..c8038a8 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"በመካሄድ ላይ ያለ"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"ማሳወቂያዎች"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"የባትሪ ኃይል አነስተኛ ነው"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> ቀሪ"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> ይቀራል። የባትሪ ኃይል ቆጣቢ በርቷል።"</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> ይቀራል"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> ይቀራል። የባትሪ መቆጠቢያ በርቷል።"</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB ኃይል መሙያ አይታገዝም።\n የቀረበውን ኃይል መሙያ ብቻ ተጠቀም።"</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"የUSB ኃይል መሙላት አይደገፍም።"</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"የቀረበውን ኃይል መሙያ ብቻ ይጠቀሙ።"</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"የቀን ህልም"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"ኤተርኔት"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"የአውሮፕላን ሁነታ"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"ባትሪ በመሙላት ላይ፣ <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"ባትሪ ሞልቷል።"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"ብሉቱዝ"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"ብሉቱዝ (<xliff:g id="NUMBER">%d</xliff:g> መሣሪያዎች)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"ብሉቱዝ ጠፍቷል"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"የባትሪ ኃይል ቆጣቢ በርቷል"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"አፈጻጸምን እና የጀርባ ውሂብ ይቀንሳል"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"ባትሪ ቆጣቢን አጥፋ"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"ይዘቶች ተደብቀዋል"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> በማያ ገጽዎ ላይ የታየውን ነገር በሙሉ ማንሳት ይጀምራል።"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"ዳግመኛ አታሳይ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 7d8bc62..fa46a41 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"مستمر"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"الإشعارات"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"البطارية منخفضة"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"المتبقي: <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"يتبقى <xliff:g id="NUMBER">%d%%</xliff:g>. وضع توفير الطاقة قيد التشغيل."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"متبقي <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"متبقي <xliff:g id="PERCENTAGE">%s</xliff:g>. وضع توفير الطاقة قيد التشغيل."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"‏شحن USB غير معتمد.\nاستخدم الشاحن الموفر فقط."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"‏لا يمكن إجراء الشحن عبر USB."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"لا تستخدم سوى الشاحن المزوّد."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"حلم اليقظة"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"وضع الطائرة"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"جارٍ الشحن، <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"تم الشحن"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"بلوتوث"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"بلوتوث (<xliff:g id="NUMBER">%d</xliff:g> من الأجهزة)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"إيقاف البلوتوث"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"وضع توفير الطاقة قيد التشغيل"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"لخفض مستوى الأداء وبيانات الخلفية"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"إيقاف توفير شحن البطارية"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"المحتويات مخفية"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> سيبدأ التقاط كل شيء يتم عرضه على الشاشة."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"عدم الإظهار مرة أخرى"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 1132337..59e5ece 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"В момента"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Известия"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Батерията е изтощена"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"Остава: <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Остава: <xliff:g id="NUMBER">%d%%</xliff:g>. Режимът за запазване на батерията е включен."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"Остава/т <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Остава/т <xliff:g id="PERCENTAGE">%s</xliff:g>. Включен е режимът за запазване на батерията."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Не се поддържа зареждане през USB.\nИзползвайте само доставеното зарядно устройство."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Зареждането през USB не се поддържа."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Използвайте само предоставеното зарядно устройство."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Мечта"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Самолетен режим"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Зарежда се, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Заредена"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> устройства)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth е изключен"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Режимът за запазване на батерията е включен"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Намалява ефективността и данните на заден план"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Изключване на режима за запазване на батерията"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Скрито съдържание"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ще започне да заснема всичко, което се показва на екрана ви."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Да не се показва отново"</string>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index 43782ea..10be3ee 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"চলতে-থাকা"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"বিজ্ঞপ্তিগুলি"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"ব্যাটারি কম"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> অবশিষ্ট রয়েছে"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> অবশিষ্ট। ব্যাটারি সেভার চালু আছে।"</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> অবশিষ্ট আছে"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> অবশিষ্ট আছে৷ ব্যাটারি সাশ্রয়কারী চালু আছে৷"</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB চার্জিং সমর্থিত নয়৷\nকেবলমাত্র সরবহারকৃত চার্জার ব্যবহার করুন৷"</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"USB চার্জিং সমর্থিত নয়।"</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"শুধুমাত্র সরবরাহকৃত চার্জার ব্যবহার করুন।"</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"স্ক্রিনসেভার"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"ইথারনেট"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"বিমান মোড"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"চার্জ হচ্ছে, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"চার্জ হয়েছে"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> টি ডিভাইস)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth বন্ধ"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"ব্যাটারি সেভার চালু রয়েছে"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"কার্য-সম্পাদনা ও পশ্চাদপট ডেটাকে কমিয়ে দেয়"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"ব্যাটারি সঞ্চয়কারী বন্ধ করুন"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"লুকানো বিষয়বস্তু"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> আপনার স্ক্রীনে দেখানো সব কিছু ক্যাপচার করা শুরু করবে।"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"আর দেখাবেন না"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index ee27139..a18dda8 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Continu"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificacions"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Queda poca bateria"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> restant"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Queda un <xliff:g id="NUMBER">%d%%</xliff:g>. Estalvi de bateria està activat."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g>."</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g>. L\'estalvi de bateria està activat."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Càrrega d\'USB no admesa.\nUtilitza només el carregador proporcionat."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"La càrrega per USB no és compatible."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Fes servir només el carregador proporcionat amb el dispositiu."</string>
@@ -226,8 +226,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Estalvi de pantalla"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Mode d\'avió"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"S\'està carregant, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Carregada"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> dispositius)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth desactivat"</string>
@@ -326,7 +324,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Estalvi de bateria activada"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Redueix el rendiment i l\'ús de les dades en segon pla."</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desactiva l\'estalvi de bateria"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contingut amagat"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> començarà a enregistrar tot el que es mostri a la pantalla."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"No ho tornis a mostrar"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 666c29a..da61fcb 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Probíhající"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Oznámení"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Baterie je slabá"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"Zbývá <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Zbývá <xliff:g id="NUMBER">%d%%</xliff:g>. Režim Úspora baterie je zapnutý."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"Zbývá <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Zbývá <xliff:g id="PERCENTAGE">%s</xliff:g>. Spořič baterie je zapnutý."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Nabíjení pomocí rozhraní USB není podporováno.\nPoužívejte pouze nabíječku, která byla dodána se zařízením."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Nabíjení přes USB není podporováno."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Používejte pouze nabíječku, která je součástí balení."</string>
@@ -226,8 +226,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Spořič obrazovky"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Režim Letadlo"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Nabíjení, <xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Nabito"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> zařízení)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Rozhraní Bluetooth je vypnuto"</string>
@@ -326,7 +324,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Režim Úspora baterie je zapnutý."</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Omezuje výkon a data na pozadí"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Vypnout úsporu baterie"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g> %%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Skrytý obsah"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"Aplikace <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> začne zaznamenávat vše, co je zobrazeno na obrazovce."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Tuto zprávu příště nezobrazovat"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 66e5f42..d18c2fa 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"I gang"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Underretninger"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Batteriniveauet er lavt"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> tilbage"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> tilbage. Batteribesparelse er slået til."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> tilbage"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> tilbage. Batterisparefunktionen er slået til."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Opladning via USB understøttes ikke.\nBrug kun den medfølgende oplader."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"USB-opladning understøttes ikke."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Brug kun den oplader, der føler med."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Dagdrøm"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Flytilstand"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Oplader, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Opladet"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> enheder)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth slået fra"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Batteribesparelse er slået til"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Reducerer ydeevne og baggrundsdata"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Deaktiver batterisparefunktion"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g> %%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Indholdet er skjult"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vil begynde at optage alt, hvad der vises på din skærm."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Vis ikke igen"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 2c5cfce..ec34296 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Aktuell"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Benachrichtigungen"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Akku ist schwach"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"Noch <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Noch <xliff:g id="NUMBER">%d%%</xliff:g>. Energiesparmodus ist aktiviert."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> verbleibend"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> verbleibend. Der Energiesparmodus ist aktiviert."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB-Aufladung wird nicht unterstützt.\nVerwenden Sie das mitgelieferte Aufladegerät."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Laden per USB wird nicht unterstützt."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Verwenden Sie nur das im Lieferumfang enthaltene Ladegerät."</string>
@@ -226,8 +226,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Flugmodus"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Lädt, <xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Aufgeladen"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Geräte)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth aus"</string>
@@ -326,7 +324,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Energiesparmodus ist aktiviert"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Reduzierung der Leistung und Hintergrunddaten"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Energiesparmodus deaktivieren"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g> %%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Inhalte ausgeblendet"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> nimmt alle auf Ihrem Bildschirm angezeigten Aktivitäten auf."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Nicht erneut anzeigen"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 9b9e56d..1e2d72c 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Εν εξελίξει"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Ειδοποιήσεις"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Χαμηλή στάθμη μπαταρίας"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"Απομένει <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Απομένει <xliff:g id="NUMBER">%d%%</xliff:g>. Η Εξοικονόμηση μπαταρίας είναι ενεργή."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"Απομένουν <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Απομένουν <xliff:g id="PERCENTAGE">%s</xliff:g>. Η λειτουργία εξοικονόμησης μπαταρίας είναι ενεργή."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Δεν υποστηρίζεται η φόρτιση USB.\nΧρησιμοποιείτε μόνο τον φορτιστή που παρέχεται."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Δεν υποστηρίζεται η φόρτιση μέσω USB."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Χρήση μόνο του παρεχόμενου φορτιστή."</string>
@@ -226,8 +226,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Λειτουργία πτήσης"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Φόρτιση, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Μπαταρία πλήρης"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> συσκευές)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Απενεργοποιημένο Bluetooth"</string>
@@ -326,7 +324,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Η Εξοικονόμηση μπαταρίας είναι ενεργή"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Μειώνει την απόδοση και τα δεδομένα παρασκηνίου"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Απενεργοποίηση εξοικονόμησης μπαταρίας"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Κρυφό περιεχόμενο"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"Θα ξεκινήσει η καταγραφή του περιεχομένου που εμφανίζεται στην οθόνη σας από την εφαρμογή <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Να μην εμφανιστεί ξανά"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 3898d02..c587701 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Ongoing"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifications"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Battery is low"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> remaining"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> remaining. Battery saver is on."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> remaining"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> remaining. Battery saver is on."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB charging not supported.\nUse only the supplied charger."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"USB charging not supported."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Use only the supplied charger."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Aeroplane mode"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Charging, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Charged"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Devices)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth Off"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Battery saver is on"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Reduces performance and background data"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Turn off battery saver"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contents hidden"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will start capturing everything that\'s displayed on your screen."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Don\'t show again"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 3898d02..c587701 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Ongoing"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifications"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Battery is low"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> remaining"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> remaining. Battery saver is on."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> remaining"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> remaining. Battery saver is on."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB charging not supported.\nUse only the supplied charger."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"USB charging not supported."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Use only the supplied charger."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Aeroplane mode"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Charging, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Charged"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Devices)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth Off"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Battery saver is on"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Reduces performance and background data"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Turn off battery saver"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contents hidden"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will start capturing everything that\'s displayed on your screen."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Don\'t show again"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 71516f1..3fcc1fd 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Continuo"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificaciones"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Batería baja"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"Quedan <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> restante. El ahorro de batería está activado."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g> de batería."</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g> de batería. La función de ahorro de batería está activada."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"No admite la carga USB.\nUsa sólo el cargador provisto."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"No se admite la carga por USB."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Usa solo el cargador suministrado."</string>
@@ -226,8 +226,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Activar protector"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Modo avión"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Cargando (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Cargada"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> dispositivos)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth desactivado"</string>
@@ -326,7 +324,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Ahorro de batería activado"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Reduce el rendimiento y el uso de datos en segundo plano."</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desactivar el ahorro de batería"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contenidos ocultos"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> comenzará la captura de todo lo que se muestre en la pantalla."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"No volver a mostrar"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 1924ad6e..fba17ca 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Entrante"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificaciones"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Nivel de batería bajo"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> restante"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> restante. Ahorro de batería activado."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g> de batería"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g> de batería. La función de ahorro de energía está activada."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"No se admite la carga por USB.\nUtiliza solo el cargador proporcionado."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"No se admite la carga por USB."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Utiliza solo el cargador proporcionado."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Salvapantallas"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Modo avión"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Cargando (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Cargada"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> dispositivos)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth desactivado"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Ahorro de batería activado"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Reduce el rendimiento y el envío de datos en segundo plano"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desactivar ahorro de batería"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contenidos ocultos"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> empezará a capturar todo lo que aparezca en la pantalla."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"No volver a mostrar"</string>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 2413994..1cb4259 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Jätkuv"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Teadistused"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Aku hakkab tühjaks saama"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> on alles"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Alles: <xliff:g id="NUMBER">%d%%</xliff:g>. Akusäästja on sisse lülitatud."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"Jäänud on <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Jäänud on <xliff:g id="PERCENTAGE">%s</xliff:g>. Akusäästja on sisse lülitatud."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB laadimist ei toetata.\nKasutage ainult tootja laadija."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"USB-ga laadimist ei toetata."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Kasutage ainult kaasasolevat laadijat."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Unistus"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Lennurežiim"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Laadimine, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Laetud"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> seadet)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth on väljas"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Akusäästja on sisse lülitatud"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Vähendab jõudlust ja taustaandmeid"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Akusäästja väljalülitamine"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Sisu on peidetud"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> hakkab jäädvustama kõike, mida ekraanil kuvatakse."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Ära kuva uuesti"</string>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index ae0ae53..138c7b1 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Abian"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Jakinarazpenak"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Bateria agortzen ari da"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> geratzen da"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Bateriaren <xliff:g id="NUMBER">%d%%</xliff:g> geratzen da. Bateria aurrezlea aktibatu da."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> gelditzen da"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> gelditzen da. Bateria-aurrezteko aukera aktibatuta dago."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Ez da USB bidez kargatzea onartzen.\nErabili hornitu zaizun kargagailua soilik."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Ez da USB bidez kargatzea onartzen."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Erabili jatorrizko kargagailua soilik."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Pantaila-babeslea"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Hegaldi modua"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Kargatzen: <xliff:g id="PERCENT">%%</xliff:g> <xliff:g id="NUMBER">%d</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Kargatuta"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetootha (<xliff:g id="NUMBER">%d</xliff:g> gailu)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetootha desaktibatuta"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Bateria aurrezlea aktibatuta dago"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Errendimendua eta atzeko planoko datuak murrizten ditu"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desaktibatu bateria aurrezteko aukera"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"%% <xliff:g id="LEVEL">%d</xliff:g>"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Edukiak ezkutatuta daude"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aplikazioak pantailan bistaratzen den guztia grabatuko du."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Ez erakutsi berriro"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index ebddd5b..c3efc17 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"در حال انجام"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"اعلان‌ها"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"شارژ باتری کم است"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> باقیمانده است"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> باقی مانده است. ذخیره کننده باتری روشن است."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> باقی مانده است"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> باقی مانده است. ذخیره کننده باتری روشن است."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"‏شارژ USB پشتیبانی نمی‌شود.\nفقط از شارژر ارائه شده استفاده کنید."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"‏شارژ با USB پشتیبانی نمی‌شود."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"فقط از شارژر ارائه شده استفاده کنید."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"رویاپردازی"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"اترنت"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"حالت هواپیما"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"در حال شارژ، <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"شارژ شد"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"بلوتوث"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"بلوتوث ( <xliff:g id="NUMBER">%d</xliff:g> دستگاه)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"بلوتوث خاموش"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"ذخیره کننده باتری روشن است."</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"عملکرد و اطلاعات پس‌زمینه را کاهش می‌دهد"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"خاموش کردن ذخیره‌کننده باتری"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"محتواها پنهان هستند"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> شروع به ضبط هر چیزی می‌کند که در صفحه‌نمایش شما نمایش داده می‌شود."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"دوباره نشان داده نشود"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 01b936a..d9b3985 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Käynnissä olevat"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Ilmoitukset"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Akku on vähissä"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> jäljellä"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> jäljellä. Virransäästö on käytössä."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> jäljellä"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> jäljellä. Virransäästö on käytössä."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB-latausta ei tueta.\nKäytä laitteen mukana tullutta laturia."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"USB-latausta ei tueta."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Käytä vain laitteen mukana toimitettua laturia."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Unelmat"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Lentokonetila"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Ladataan (<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>)"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Täynnä"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> laitetta)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth pois käytöstä"</string>
@@ -324,9 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Virransäästö on käytössä"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Rajoittaa suorituskykyä ja taustatiedonsiirtoa"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Poista virransäästö käytöstä"</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for battery_level_template (1609636980292580020) -->
-    <skip />
     <string name="notification_hidden_text" msgid="1135169301897151909">"Sisältö piilotettu"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> alkaa tallentaa kaiken näytölläsi näkyvän."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Älä näytä uudelleen"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 1c1ef65..7c625d1 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"En cours"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifications"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Pile faible"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> restant(s)"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Il reste : <xliff:g id="NUMBER">%d%%</xliff:g>. La fonction Économie d\'énergie est activée."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> restants"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> restants. L\'économiseur d\'énergie est activé."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Chargement USB non compatible.\nVous devez utiliser le chargeur fourni."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Le chargement par USB n\'est pas pris en charge."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Utilisez uniquement le chargeur fourni."</string>
@@ -226,8 +226,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Écran de veille"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Mode Avion"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"En charge (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Chargée"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> appareils)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"BLUETOOTH DÉSACTIVÉ"</string>
@@ -326,7 +324,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"La fonction Économie d\'énergie est activée"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Réduire les performances et de fond"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Désactiver l\'économiseur d\'énergie"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g> %%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contenus masqués"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> commencer à enregistrer tout ce qui s\'affiche sur votre écran."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Ne plus afficher"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 36436b7..13f3f55 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"En cours"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifications"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Batterie faible"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> restant(s)"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Il reste <xliff:g id="NUMBER">%d%%</xliff:g>. L\'économiseur de batterie est activé."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> restants"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> restants. L\'économiseur de batterie est activé."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Chargement USB non disponible.\nVous devez utiliser le chargeur fourni."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Chargeur USB non compatible."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Veuillez n\'utiliser que le chargeur fourni."</string>
@@ -226,8 +226,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Écran de veille interactif"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Mode avion"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"En charge (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Chargée"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> appareils)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth désactivé"</string>
@@ -326,7 +324,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"L\'économiseur de batterie est activé"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Limite les performances et les données en arrière-plan."</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Désactiver l\'économiseur de batterie"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g> %%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contenus masqués"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> va commencer à capturer tous les contenus affichés à l\'écran."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Ne plus afficher"</string>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index 51f0d57..e94f007 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"En curso"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificacións"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Queda pouca batería"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> restante"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Queda un <xliff:g id="NUMBER">%d%%</xliff:g>. O aforro de batería está activado."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> restante"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> restante. A función aforro de batería está activada."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Non compatible coa carga por USB.\nUtiliza só o cargador proporcionado."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Non se admite a carga mediante USB."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Utiliza soamente o cargador fornecido."</string>
@@ -226,8 +226,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Protector pantalla"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Modo avión"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Cargando, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Cargada"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> dispositivos)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth desactivado"</string>
@@ -326,7 +324,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"O aforro de batería está activado"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Reduce o rendemento e os datos en segundo plano"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desactivar o aforro de batería"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contido oculto"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> comezará a capturar todo o que apareza na túa pantalla."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Non mostrar outra vez"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 962bcac..da20f7d 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"ऑनगोइंग"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"सूचनाएं"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"बैटरी कम है"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> शेष"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> शेष. बैटरी सेवर चालू है."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> शेष"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> शेष. बैटरी सेवर चालू है."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB चार्जिंग समर्थित नहीं है.\nकेवल आपूर्ति किए गए चार्जर का उपयोग करें."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"USB चार्जिंग समर्थित नहीं है."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"केवल आपूर्ति किए गए चार्जर का उपयोग करें."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"स्क्रीनसेवर"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"ईथरनेट"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"हवाई जहाज़ मोड"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"चार्ज हो रही है, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"चार्ज हो गई है"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"ब्लूटूथ"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"ब्लूटूथ (<xliff:g id="NUMBER">%d</xliff:g> डिवाइस)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"ब्लूटूथ बंद"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"बैटरी सेवर चालू है"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"निष्‍पादन और पृष्ठभूमि डेटा को कम करता है"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"बैटरी बचतकर्ता को बंद करें"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"छिपी हुई सामग्री"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> आपके स्क्रीन पर प्रदर्शित प्रत्येक सामग्री को कैप्चर करना प्रारंभ कर देगी."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"फिर से न दिखाएं"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 00bb24f..1d97c9f 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"U tijeku"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Obavijesti"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Niska razina baterije"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> preostalo"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Preostalo je <xliff:g id="NUMBER">%d%%</xliff:g>. Štednja baterije je uključena."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"Preostalo <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Preostalo <xliff:g id="PERCENTAGE">%s</xliff:g>. Uključena je štednja baterije."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB punjenje nije podržano.\nUpotrijebite samo priloženi punjač."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Punjenje putem USB-a nije podržano."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Upotrebljavajte samo priloženi punjač."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Sanjarenje"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Način rada u zrakoplovu"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Puni se, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Napunjena"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (broj uređaja: <xliff:g id="NUMBER">%d</xliff:g>)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth isključen"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Štednja baterije je uključena"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Smanjuje količinu rada i pozadinske podatke"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Isključi uštedu baterije"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Sadržaj je skriven"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"Aplikacija <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> počet će snimati sve što se prikazuje na zaslonu."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Ne prikazuj ponovo"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 4b60d3b..451684e 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Folyamatban van"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Értesítések"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Alacsony az energiaszint"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> maradt"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> maradt. Az Akkumulátorkímélő mód bekapcsol."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> maradt"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> maradt. A takarékos akkumulátorhasználat engedélyezve van."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Az USB-n keresztüli töltés nincs támogatva.\nHasználja a kapott töltőt."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Az USB-n keresztüli töltés nem támogatott."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Kizárólag a tartozékként kapott töltőt használja."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Álmodozás"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Repülőgép üzemmód"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Töltés (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Feltöltve"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> eszköz)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth kikapcsolva"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Akkumulátorkímélő mód bekapcsolva"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Csökkenti a teljesítményt és a háttéradatok használatát"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Akkumulátorkímélő mód kikapcsolása"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>. szint"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Tartalomjegyzék elrejtve"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"A(z) <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> alkalmazás rögzíteni fog mindent, ami megjelenik a képernyőn."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Ne jelenjen meg többé"</string>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index f1bdd6d..5d442a0 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Ընթացիկ"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Ծանուցումներ"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Մարտկոցը լիցքաթափվում է"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"մնում է <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Մնաց <xliff:g id="NUMBER">%d%%</xliff:g>: Մարտկոցի տնտեսումը միացված է:"</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"Մնաց <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Մնաց <xliff:g id="PERCENTAGE">%s</xliff:g>: Մարտկոցի տնտեսումը միացված է:"</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB լիցքավորումը չի աջակցվում:\nՕգտվեք միայն գործող լիցքավորիչից:"</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"USB լիցքավորումը չի աջակցվում:"</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Օգտագործեք միայն մատակարարի տրամադրած լիցքավորիչը:"</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Ցերեկային ռեժիմ"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Ինքնաթիռային ռեժիմ"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Լիցքավորում` <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Լիցքավորված է"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> սարք)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth-ն անջատված է"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Մարտկոցի տնտեսումը միացված է"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Նվազեցնում է ծանրաբեռնվածությունը և ֆոնային տվյալները"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Անջատել մարտկոցի տնտեսումը"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Բովանդակությունը թաքցված է"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ծրագիրը կսկսի հավաքագրել այն ամենն ինչ ցուցադրվում է ձեր էկրանին:"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Այլևս ցույց չտալ"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 8f750df..15d5dc7 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Berkelanjutan"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Pemberitahuan"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Baterai lemah"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> tersisa"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Tersisa <xliff:g id="NUMBER">%d%%</xliff:g>. Penghemat baterai aktif."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"Tersisa <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Tersisa <xliff:g id="PERCENTAGE">%s</xliff:g>. Penghemat baterai aktif."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Pengisian daya USB tidak didukung.\nGunakan hanya pengisi daya yang disediakan."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Pengisian daya USB tidak didukung."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Hanya gunakan pengisi daya yang disediakan."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Lamunan"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Mode pesawat"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Mengisi baterai, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Terisi"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Perangkat)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth Mati"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Penghemat baterai aktif"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Mengurangi kinerja dan data latar belakang"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Nonaktifkan penghemat baterai"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Konten tersembunyi"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> akan mulai menangkap apa saja yang ditampilkan pada layar Anda."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Jangan tampilkan lagi"</string>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index 6813096..d5e6476 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Áframhaldandi"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Tilkynningar"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Rafhlaðan er að tæmast"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> eftir"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> eftir. Kveikt er á rafhlöðusparnaði."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> eftir"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> eftir. Kveikt er á rafhlöðusparnaði."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB-hleðsla er ekki studd.\nNotaðu eingöngu hleðslutækið sem fylgdi."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Ekki er stuðningur við USB-hleðslu."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Notaðu eingöngu hleðslutækið sem fylgir með."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Skjávari"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Flugstilling"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Í hleðslu, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Fullhlaðið"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> tæki)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Slökkt á Bluetooth"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Kveikt er á rafhlöðusparnaði"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Dregur úr afköstum og bakgrunnsgögnum"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Slökkva á rafhlöðusparnaði"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Innihald falið"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> mun fanga allt sem birtist á skjánum."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Ekki sýna þetta aftur"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index abf22be..98a22ec 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"In corso"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifiche"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Batteria quasi scarica"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> rimanente"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> rimanente. La funzione Risparmio batteria è attiva."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> rimanente"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> rimanente. Risparmio energetico attivo."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Ricarica tramite USB non supportata.\nUtilizza solo il caricatore in dotazione."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Ricarica tramite USB non supportata."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Utilizza solo il caricabatterie fornito in dotazione."</string>
@@ -226,8 +226,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Modalità aereo"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"In carica (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Carica"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> dispositivi)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth spento"</string>
@@ -326,7 +324,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Risparmio batteria attivo"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Riduce le prestazioni e i dati in background"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Disattiva risparmio energetico"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contenuti nascosti"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> inizierà ad acquisire tutto ciò che è visualizzato sul tuo schermo."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Non mostrare più"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 460d2b1..55f2daf 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"מתמשך"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"התראות"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"עוצמת הסוללה נמוכה"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"נותרו <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"נותרו <xliff:g id="NUMBER">%d%%</xliff:g>. תכונת \'חיסכון בסוללה\' פועלת."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"נותרו <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"נותרו <xliff:g id="PERCENTAGE">%s</xliff:g>. הופעל שירות חיסכון בסוללה."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"‏טעינה באמצעות USB אינה נתמכת.\nהשתמש אך ורק במטען שסופק."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"‏טעינה בחיבור USB אינה נתמכת."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"השתמש רק במטען שסופק."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"חלום בהקיץ"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"מצב טיסה"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"טוען (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"מלאה"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"‏Bluetooth ‏(<xliff:g id="NUMBER">%d</xliff:g> מכשירים)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"‏Bluetooth מופסק"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"תכונת \'חיסכון בסוללה\' פועלת"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"מפחית את הביצועים ונתונים ברקע"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"כבה את החיסכון בסוללה"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"התוכן מוסתר"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> יתחיל להקליט את כל התוכן המוצג במסך שלך."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"אל תציג שוב"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 24fd627..b104450 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"実行中"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"電池残量が少なくなっています"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"残り<xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"残量が<xliff:g id="NUMBER">%d%%</xliff:g>です。バッテリーセーバーはONです。"</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"残量が<xliff:g id="PERCENTAGE">%s</xliff:g>です"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"残量が<xliff:g id="PERCENTAGE">%s</xliff:g>です。バッテリーセーバーはONです。"</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB充電には対応していません。\n付属の充電器をお使いください。"</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"USB充電には対応していません。"</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"専用の充電器のみを使用してください。"</string>
@@ -226,8 +226,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"スクリーンセーバー"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"イーサネット"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"機内モード"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"充電中: <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"充電完了"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth(端末数<xliff:g id="NUMBER">%d</xliff:g>)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth OFF"</string>
@@ -326,7 +324,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"バッテリーセーバーがON"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"パフォーマンスとバックグラウンドデータを制限します"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"バッテリーセーバーをOFFにします"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"コンテンツが非表示"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>で、画面に表示されているコンテンツのキャプチャを開始します。"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"次回から表示しない"</string>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index 33dc69f..9461ad2 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"მიმდინარე"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"შეტყობინებები"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"ბატარეა იწურება"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"დარჩენილია <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"დარჩენილია <xliff:g id="NUMBER">%d%%</xliff:g>. გააქტიურებულია ბატარეის დამზოგი."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"დარჩენილია <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"დარჩენილია <xliff:g id="PERCENTAGE">%s</xliff:g>. ბატარეის დაზოგვა ჩართულია."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB-ით დატენვა არ არის მხარდაჭერილი.\nგამოიყენეთ მხოლოდ ელექტრო-დამტენი."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"USB დატენვა მხარდაჭერილი არ არის."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"გამოიყენეთ მხოლოდ მოყოლილი დამტენი."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"ეთერნეტი"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"თვითმფრინავის რეჟიმი"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"დამუხტვა, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"დამუხტულია"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> მოწყობილობა)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth გამორთულია"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"ბატარეის დამზოგი ჩართულია"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"ამცირებს წარმადობას და უკანა ფონის მონაცემებს"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"ბატარეის დაზოგვის გამორთვა"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"შიგთავსი დამალულია"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> დაიწყებს იმ ყველაფრის აღბეჭდვას, რაც თქვენს ეკრანზე ჩანს."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"აღარ მაჩვენო"</string>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index 5c290e4..bb84471 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Ағымдағы"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Хабарлар"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Батарея заряды төмен"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> қуат қалды"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> қалды. Батарея үнемдегіш қосулы."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> қалды"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> қалды. Батарея үнемдегіш қосулы."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB зарядтауды қолдау ұсынылмаған.\nЖабдықталған зарядтағыш құрылғысын ғана қолданыңыз."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"USB арқылы зарядтауға қолдау көрсетілмейді."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Тек жинақтағы зарядтағышты пайдаланыңыз."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Қалғу"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Этернет"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Ұшақ режимі"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Зарядтауда, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Зарядталды"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> құрылғылары)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth өшірулі"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Батарея үнемдегіш қосулы"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Өнімділікті және фондық деректерді азайтады"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Батарея үнемдегішті өшіру"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Мазмұн жасырылған"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> экранда көрсетілгеннің барлығын түсіре бастайды."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Қайта көрсетпеу"</string>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index 264be48..335681a 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"បន្ត"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"ការ​ជូន​ដំណឹង"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"ជិត​អស់​ថ្ម​ហើយ"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"នៅ​សល់ <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"នៅ​សល់ <xliff:g id="NUMBER">%d%%</xliff:g> ។ កម្មវិធី​សន្សំ​ថ្ម​គឺ​បើក។"</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"នៅ​សល់ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"នៅ​សល់ <xliff:g id="PERCENTAGE">%s</xliff:g> ។ កម្មវិធី​សន្សំថ្ម​គឺ​បើក។"</string>
     <string name="invalid_charger" msgid="4549105996740522523">"មិន​គាំទ្រ​ការ​បញ្ចូល​តាម​យូអេសប៊ី។\nប្រើ​តែ​ឧបករណ៍​បញ្ចូល​ថ្ម​ដែល​បាន​ផ្ដល់។"</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"មិន​គាំទ្រ​ការ​បញ្ចូល​ថ្ម​តាម​យូអេសប៊ី​ទេ។"</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"ប្រើ​តែ​ឧបករណ៍​បញ្ចូល​ថ្ម​ដែល​បាន​ផ្ដល់​ឲ្យ។"</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"ធាតុ​រក្សា​អេក្រង់"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"អ៊ីសឺរណិត"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"របៀបពេល​​ជិះ​យន្តហោះ"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"បញ្ចូល​ថ្ម <xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"បាន​បញ្ចូល​ពេញ"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"ប៊្លូធូស"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"ប៊្លូធូស (ឧបករណ៍ <xliff:g id="NUMBER">%d</xliff:g>)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"​ប៊្លូធូស​បាន​បិទ"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"កម្មវិធី​សន្សំ​ថ្ម​គឺ​បើក"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"ការ​បន្ថយ​ការ​ប្រតិបត្តិ និង​ទិន្នន័យ​ផ្ទៃ​ខាងក្រោយ"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"បិទ​ធាតុ​រក្សា​ថាមពល​ថ្ម"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"បាន​លាក់​មាតិកា"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> នឹង​ចាប់ផ្ដើម​ចាប់​យក​អ្វីៗ​គ្រប់យ៉ាង​ដែល​បង្ហាញ​លើ​អេក្រង់​របស់​អ្នក។"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"កុំ​បង្ហាញ​ម្ដងទៀត"</string>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index c4f5731..e61f89a 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"ಚಾಲ್ತಿಯಲ್ಲಿರುವ"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"ಅಧಿಸೂಚನೆಗಳು"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"ಬ್ಯಾಟರಿ ಕಡಿಮೆ ಇದೆ"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> ಉಳಿದಿದೆ"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> ಉಳಿದಿದೆ. ಬ್ಯಾಟರಿ ರಕ್ಷಕ ಆನ್ ಆಗಿದೆ."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> ಉಳಿದಿದೆ"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> ಉಳಿದಿದೆ. ಬ್ಯಾಟರಿ ಉಳಿತಾಯ ಆನ್‌ ಆಗಿದೆ."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB ಚಾರ್ಜಿಂಗ್ ಬೆಂಬಲಿತವಾಗಿಲ್ಲ.\nಒದಗಿಸಿರುವ ಚಾರ್ಜರ್ ಮಾತ್ರ ಬಳಸಿ."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"USB ಚಾರ್ಜಿಂಗ್ ಬೆಂಬಲಿತವಾಗಿಲ್ಲ."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"ಒದಗಿಸಿರುವ ಚಾರ್ಜರ್ ಮಾತ್ರ ಬಳಸಿ."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"ಡೇಡ್ರೀಮ್"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"ಇಥರ್ನೆಟ್"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"ಏರ್‌ಪ್ಲೇನ್ ಮೋಡ್"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"ಚಾರ್ಜ್ ಆಗಿದೆ"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"ಬ್ಲೂಟೂತ್‌"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"ಬ್ಲೂಟೂತ್‌ (<xliff:g id="NUMBER">%d</xliff:g> ಸಾಧನಗಳು)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"ಬ್ಲೂಟೂತ್‌ ಆಫ್"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"ಬ್ಯಾಟರಿ ರಕ್ಷಕ ಆನ್ ಆಗಿದೆ"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"ಕಾರ್ಯಕ್ಷಮತೆ ಮತ್ತು ಹಿನ್ನೆಲೆ ಡೇಟಾವನ್ನು ಕಡಿಮೆ ಮಾಡುತ್ತದೆ"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"ಬ್ಯಾಟರಿ ಉಳಿತಾಯವನ್ನು ಆಫ್ ಮಾಡಿ"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"ವಿಷಯಗಳನ್ನು ಮರೆಮಾಡಲಾಗಿದೆ"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"ನಿಮ್ಮ ಪರದೆಯ ಮೇಲೆ ಪ್ರದರ್ಶಿಸಲಾಗುವ ಎಲ್ಲವನ್ನೂ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ಯು ಸೆರೆಹಿಡಿಯಲು ಪ್ರಾರಂಭಿಸುತ್ತದೆ."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"ಮತ್ತೊಮ್ಮೆ ತೋರಿಸದಿರಿ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 460837e..845a11e 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -33,10 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"진행 중"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"알림"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"배터리 부족"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> 남음"</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for battery_low_percent_format_saver_started (6534746636002666456) -->
-    <skip />
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> 남았습니다."</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> 남았습니다. 배터리 절약 기능을 사용 중입니다."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB 충전이 지원되지 않습니다.\n제공된 충전기만 사용하세요."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"USB 충전은 지원되지 않습니다."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"제공된 충전기만 사용하세요."</string>
@@ -226,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"화면 보호기"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"이더넷"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"비행기 모드"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"충전 중(<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"충전됨"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"블루투스"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"블루투스(<xliff:g id="NUMBER">%d</xliff:g>개의 기기)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"블루투스 사용 안함"</string>
@@ -326,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"배터리 세이버 사용 중"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"성능 및 백그라운드 데이터를 줄입니다."</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"배터리 절약 기능 사용 중지"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"숨겨진 콘텐츠"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>에서 화면에 표시된 모든 것을 캡처하기 시작합니다."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"다시 표시 안함"</string>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index c64878f..45ed9bf 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -38,9 +38,8 @@
     <!-- no translation found for status_bar_latest_events_title (6594767438577593172) -->
     <skip />
     <string name="battery_low_title" msgid="6456385927409742437">"Батареянын кубаты аз"</string>
-    <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
-    <skip />
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> калды. Батарея үнөмдөгүч күйгүзүлдү."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> калды"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> калды. Батареянын кубатын үнөмдөгүч күйүк."</string>
     <!-- no translation found for invalid_charger (4549105996740522523) -->
     <skip />
     <string name="invalid_charger_title" msgid="3515740382572798460">"USB аркылуу кубаттоого болбойт."</string>
@@ -250,8 +249,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Кыялдануу"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Учак тартиби"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Дүрмөттөлүүдө, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Дүрмөттөлгөн"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> түзмөк)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth өчүк"</string>
@@ -350,7 +347,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Батареяны үнөмдөгүч күйгүзүлдү"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Иштин майнаптуулугун начарлатып, фондук дайындарды чектейт"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Батареянын кубатын үнөмдөгүчтү өчүрүп коюу"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Мазмундар жашырылган"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> экранга чыккан нерсенин баарын сүрөткө тарта баштайт."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Экинчи көрсөтүлбөсүн"</string>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index fa634ae..4218fd1 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"ດຳເນີນຢູ່"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"ການແຈ້ງເຕືອນ"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"ແບັດເຕີຣີ​ເຫຼືອ​ໜ້ອຍ"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"ຍັງເຫຼືອອີກ <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"ຍັງເຫຼືອ <xliff:g id="NUMBER">%d%%</xliff:g>. ເປີດ​ນຳໃຊ້​ໂຕປະຢັດ​ແບັດເຕີຣີ​ຢູ່."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"ຍັງ​ເຫຼືອ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"ຍັງ​ເຫຼືອ <xliff:g id="PERCENTAGE">%s</xliff:g>. ການ​ປະ​ຢັດ​ແບັດ​ເຕີ​ຣີ​ໄດ້​ຖືກ​​ເປີດ​ໃຊ້​ແລ້ວ."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"ບໍ່ຮອງຮັບການສາກໄຟດ້ວຍ USB.\nຕ້ອງໃຊ້ສະເພາະເຄື່ອງສາກທີ່ແຖມມານຳເທົ່ານັ້ນ."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"ບໍ່​ຮອງຮັບ​ການ​ສາກ​ຜ່ານ USB."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"ໃຊ້​ສະເພາະ​ສາຍ​ສາກ​ທີ່​ມາ​ກັບ​ເຄື່ອງ."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"ໂໝດຢູ່ໃນຍົນ"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"ກຳລັງສາກ, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"ສາກເຕັມແລ້ວ"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> ອຸປະກອນ)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth ປິດ"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"ເປີດ​ໃຊ້​ໂຕ​ປະຢັດ​ແບັດເຕີຣີ​ແລ້ວ"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"ຫຼຸດ​ປະ​ສິ​ທິ​ພາບ​ແລະ​ການ​ນຳ​ໃຊ້​ຂໍ້​ມູນ​ພື້ນຫຼັງ"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"ປິດ​ໂຕ​ປະ​ຢັດ​ແບັດ​ເຕີ​ຣີ"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"ເນື້ອຫາ​ຖືກ​ເຊື່ອງ​ໄວ້"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ​ຈະ​ເລີ່ມ​ບັນ​ທຶກ​ທຸກ​ຢ່າງ​ທີ່​ສະ​ແດງ​ຜົນ​ໃນ​ໜ້າ​ຈໍ​ທ່ານ."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"ບໍ່​ຕ້ອງ​ສະ​ແດງ​ອີກ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 793c4b6..24945ca 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Vykstantys"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Pranešimai"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Akumuliatorius senka"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"Liko <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Liko <xliff:g id="NUMBER">%d%%</xliff:g>. Akumuliatoriaus tausojimo priemonė įjungta."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"Liko <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Liko <xliff:g id="PERCENTAGE">%s</xliff:g>. Akumuliatoriaus tausojimo programa įjungta."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB krovimas nepalaikomas.\nNaudokite tik pateiktą įkroviklį."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"USB įkrovimas nepalaikomas."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Naudokite tik pateiktą kroviklį."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Svajonė"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Eternetas"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Lėktuvo režimas"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Įkraunama, <xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Įkrauta"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"„Bluetooth“ (<xliff:g id="NUMBER">%d</xliff:g> įreng.)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"„Bluetooth“ išjungta"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Akumuliatoriaus tausojimo priemonė įjungta"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Sumažinamas našumas ir foninių duomenų naudojimas"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Išjungti Akumuliatoriaus tausojimo priemonę"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g> %%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Turinys paslėptas"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"„<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>“ pradės fiksuoti viską, kas rodoma jūsų ekrane."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Daugiau neberodyti"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 1f5eaef..e00514f 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Notiekošs"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Paziņojumi"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Zems akumulatora enerģijas līmenis"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"Atlicis: <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Atlikuši <xliff:g id="NUMBER">%d%%</xliff:g>. Ir ieslēgts akumulatora enerģijas taupīšanas režīms."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"Atlikuši <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Atlikuši <xliff:g id="PERCENTAGE">%s</xliff:g>. Ir ieslēgts akumulatora jaudas taupīšanas režīms."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB lādēšana netiek atbalstīta.\nIzmantojiet tikai komplektā iekļauto lādētāju."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"USB uzlāde netiek atbalstīta."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Izmantojiet tikai komplektā iekļauto lādētāju."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Ekrānsaudzētājs"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Tīkls Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Lidojuma režīms"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Notiek uzlāde, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Uzlādēts"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> ierīce(-es))"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth savienojums ir izslēgts."</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Ieslēgts akumulatora enerģijas taupīšanas režīms"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Samazina veiktspēju un fona datus"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Izslēgt akumulatora jaudas taupīšanu"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Saturs paslēpts"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sāks uzņemt visu, kas tiks rādīts jūsu ekrānā."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Vairs nerādīt"</string>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index f645a5c..14d4c11 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Во тек"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Известувања"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Батеријата е слаба"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"Преостануваат <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Преостануваат <xliff:g id="NUMBER">%d%%</xliff:g>. Штедачот на батерија е вклучен."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"Преостануваат <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Преостануваат <xliff:g id="PERCENTAGE">%s</xliff:g>. Вклучен е штедачот на батерија."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Полначот на УСБ меморијата не е поддржан.\nКористете го само полначот доставен со уредот."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Полнењето преку УСБ не е поддржано."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Користете го само доставениот полнач."</string>
@@ -226,8 +226,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Етернет"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Режим на работа во авион"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Се полни, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Наполнета"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> уреди)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth е исклучен"</string>
@@ -326,7 +324,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Штедачот на батерија е вклучен"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Ја намалува изведбата и податоците во заднина"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Исклучете го штедачот на батерија"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Содржините се скриени"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ќе започне да презема сѐ што се прикажува на вашиот екран."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Не покажувај повторно"</string>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index 4a2d80a..8084c5d 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"നടന്നുകൊണ്ടിരിക്കുന്നവ"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"അറിയിപ്പുകൾ"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"ബാറ്ററി നില കുറവാണ്"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> ശേഷിക്കുന്നു"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> ശേഷിക്കുന്നു. ബാറ്ററി സേവർ ഓണാണ്."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> ശേഷിക്കുന്നു"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> ശേഷിക്കുന്നു. ബാറ്ററി സേവർ ഓണാണ്."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB ചാർജ്ജുചെയ്യൽ പിന്തുണയ്ക്കുന്നില്ല.\nഅതിന്റെ അനുബന്ധ ചാർജ്ജർ മാത്രം ഉപയോഗിക്കുക."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"USB ചാർജ്ജുചെയ്യൽ പിന്തുണച്ചില്ല."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"വിതരണം ചെയ്‌ത ചാർജ്ജർ മാത്രം ഉപയോഗിക്കുക."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"ഡേഡ്രീം"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"ഇതർനെറ്റ്"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"ഫ്ലൈറ്റ് മോഡ്"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"ചാർജ്ജുചെയ്യുന്നു, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"ചാർജ്ജുചെയ്‌തു"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"ബ്ലൂടൂത്ത്"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"ബ്ലൂടൂത്ത് (<xliff:g id="NUMBER">%d</xliff:g> ഉപകരണങ്ങൾ)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"ബ്ലൂടൂത്ത് ഓഫുചെയ്യുക"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"ബാറ്ററി സേവർ ഓണാണ്"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"പ്രവർത്തനവും പശ്ചാത്തല ഡാറ്റയും കുറയ്‌ക്കുന്നു"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"ബാറ്ററി സേവർ ഓഫാക്കുക"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"കോൺടാക്‌റ്റുകൾ മറച്ചു"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"നിങ്ങളുടെ സ്ക്രീനിൽ പ്രദർശിപ്പിച്ചിരിക്കുന്ന എല്ലാ കാര്യങ്ങളും <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ക്യാപ്‌ചർ ചെയ്യുന്നത് ആരംഭിക്കും."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"വീണ്ടും കാണിക്കരുത്"</string>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 47b6cbf..c294f6a 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Гарсан"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Мэдэгдэл"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Батерей дуусаж байна"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> үлдсэн"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> үлдсэн. Батерей хэмнэгч асаалттай."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> үлдсэн"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> үлдсэн. Батерей хэмнэгч ассан."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB цэнэглэлт дэмжигдэхгүй байна.\nЗөвхөн нийлүүлэгдсэн цэнэглэгчийг ашиглана уу."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"USB-р цэнэглэх дэмжигддэггүй."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Зөвхөн зориулалтын ирсэн цэнэглэгч ашиглана уу."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Этернет"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Нислэгийн горим"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Цэнэглэж байна, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Цэнэглэгдсэн"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Блютүүт"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Блютүүт (<xliff:g id="NUMBER">%d</xliff:g> төхөөрөмж)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Блютүүт унтраалттай"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Батерей хэмнэгч асаалттай"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Ажиллагаа болон далд датаг бууруулна"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Батерей хэмнэгчийг унтраах"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Контентыг нуусан"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> таны дэлгэц дээр гаргасан бүх зүйлийн зургийг авч эхэлнэ."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Дахиж үл харуулах"</string>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index 22ba18f..63b2c89 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"सुरु असलेले"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"सूचना"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"बॅटरी कमी आहे"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> शिल्‍लक"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> उर्वरित. बॅटरी बचतकर्ता चालू आहे."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> शिल्लक"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> शिल्लक. बॅटरी बचतकर्ता चालू आहे."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB चार्जिंग समर्थित नाही.\nफक्त पुरवठा केलेले चार्जर वापरा."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"USB चार्जिंग समर्थित नाही."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"केवळ पुरविलेले चार्जर वापरा."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"डेड्रीम"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"इथरनेट"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"विमान मोड"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"चार्ज होत आहे, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"चार्ज झाली"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"ब"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"ब (<xliff:g id="NUMBER">%d</xliff:g> डिव्हाइसेस)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"ब बंद"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"बॅटरी बचतकर्ता चालू आहे"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"कार्यप्रदर्शन आणि पार्श्वभूमी डेटा कमी करते"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"बॅटरी बचतकर्ता बंद करा"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"लपविलेली सामग्री"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> आपल्‍या स्‍क्रीनवर प्रदर्शित होणारी प्रत्‍येक गोष्‍ट कॅप्‍चर करणे प्रारंभ करेल."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"पुन्हा दर्शवू नका"</string>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 5dcae4f..93fea9f 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Sedang berlangsung"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Pemberitahuan"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Bateri lemah"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"Berbaki <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Tinggal <xliff:g id="NUMBER">%d%%</xliff:g>. Penjimat bateri dihidupkan."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> yang tinggal"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> yang tinggal. Penjimat bateri dihidupkan."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Pengecasan USB tidak disokong.\nGunakan hanya pengecas yang dibekalkan."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Pengecasan USB tidak disokong."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Gunakan pengecas yang dibekalkan sahaja."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Lamun"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Mod kapal terbang"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Mengecas, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Sudah dicas"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Peranti)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth Dimatikan"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Penjimat bateri dihidupkan"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Mengurangkan prestasi dan data latar belakang"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Matikan penjimat bateri"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Kandungan tersembunyi"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> akan mula mengabadikan semua yang dipaparkan pada skrin anda.."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Jangan tunjukkan lagi"</string>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index b4f832c..6c573d6 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"လက်ရှိအသုံးပြုမှု"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"အကြောင်းကြားချက်များ။"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"ဘက်ထရီ အားနည်းနေ"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> ကျန်ရှိသည်"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> ကျန်နေ။ ဘက်ထရီ ချွေတာသူ ဖွင့်ထား။"</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> ကျန်ရှိနေ"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> ကျန်ရှိနေ။ ဘက်ထရီ ချွေတာမှု ဖွင့်ထား။"</string>
     <string name="invalid_charger" msgid="4549105996740522523">"လက်ရှိUSBအားသွင်းခြင်း အသုံးမပြုနိုင်ပါ \n ပေးထားသောအားသွင်းကိရိယာကိုသာ အသုံးပြုပါ"</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"USB အားသွင်းမှု မပံ့ပိုးပါ။"</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"ပေးခဲ့သည့် အားသွင်းစက်ကိုသာ အသုံးပြုပါ"</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"ဒေးဒရင်းမ်"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"အီသာနက်"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"လေယာဥ်ပျံပေါ်အသုံးပြုသောစနစ်"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"အားသွင်းနေစဉ်, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"အားပြည့်"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"ဘလူးတု"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"ဘလူးတု (<xliff:g id="NUMBER">%d</xliff:g> စက်များ)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"ဘလူးတု ပိတ်ထားရန်"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"ဘက်ထရီ ချွေတာသူ ဖွင့်ထား"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"လုပ်ကိုင်မှုကို လျှော့ချလျက် နောက်ခံ ဒေတာကို ကန့်သတ်သည်"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"ဘက်ထရီ ချွေတာမှုကို ပိတ်ထားရန်"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"အကြောင်းအရာများ ဝှက်ထား"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> က သင်၏ မျက်နှာပြင် ပေါ်မှာ ပြသထားသည့် အရာတိုင်းကို စတင် ဖမ်းယူမည်။"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"နောက်ထပ် မပြပါနှင့်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index db3dc41..b25e8a7 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Aktiviteter"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Varslinger"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Batterikapasiteten er lav"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> gjenværende"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> gjenstår. Batterisparing er på."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> gjenstår"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> gjenstår. Batterisparing er på."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB-lading støttes ikke.\nBruk kun den medfølgende laderen."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Lading via USB støttes ikke."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Bruk bare den tilhørende laderen."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Dagdrøm"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Flymodus"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Lader: <xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Oppladet"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> enheter)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth er slått av"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Batterisparing er på"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Reduserer ytelsen og begrenser bakgrunnsdataene"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Slå av batterisparing"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g> %%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Innholdet er skjult"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tar opp alt som vies på skjermen din."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Ikke vis igjen"</string>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index a8d0337..153d48d 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"चलिरहेको"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"सूचनाहरू"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"ब्याट्रि कम छ"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> बाँकी"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> बाँकी। ब्याट्रि सेभर चालु छ।"</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> बाँकी"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> बाँकी। ब्याट्री बचत खुलै छ।"</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB चार्ज गर्न समर्थित छैन।\n आपूर्ति गरिएको चार्जर मात्र प्रयोग गर्नुहोस्।"</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"USB चार्ज समर्थित छैन।"</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"आपूर्ति गरिएको चार्जर मात्र प्रयोग गर्नुहोस्।"</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"दिवासपना"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"हवाइजहाज मोड"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"चार्ज हुँदै, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"चार्ज भयो"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"ब्लुटुथ"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"ब्लुटुथ (<xliff:g id="NUMBER">%d</xliff:g> उपकरणहरू)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"ब्लुटुथ बन्द"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"ब्याट्रि सेभर चालु छ"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"प्रदर्शन र पृष्ठभूमि डेटा घटाउँनुहोस्"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"ब्याट्री बचत बन्द गर्नुहोस्"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"लुकेका सामाग्रीहरू"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ले आफ्नो स्क्रीनमा प्रदर्शित हुने सबै खिच्न शुरू गर्नेछ।"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"फेरि नदेखाउनुहोस्"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 8b474c7..a722d3a 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Actief"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Meldingen"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Accu is bijna leeg"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> resterend"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> resterend. Accubesparing is ingeschakeld."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> resterend"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> resterend. Accubesparing is ingeschakeld."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Opladen via USB niet ondersteund.\nGebruik alleen de bijgeleverde oplader."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Opladen via USB wordt niet ondersteund."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Gebruik alleen de bijgeleverde oplader."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Dagdroom"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Vliegmodus"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Opladen, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Opgeladen"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> apparaten)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth uit"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Accubesparing is ingeschakeld"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Vermindert de prestaties en achtergrondgegevens"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Accubesparing uitschakelen"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Inhoud verborgen"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> gaat alles vastleggen dat wordt weergegeven op uw scherm."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Niet opnieuw weergeven"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 399628d..8704b33 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Bieżące"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Powiadomienia"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Bateria jest słaba"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"Pozostało: <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Zostało <xliff:g id="NUMBER">%d%%</xliff:g>. Oszczędzanie baterii jest włączone."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"Pozostało <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Pozostało <xliff:g id="PERCENTAGE">%s</xliff:g>. Oszczędzanie baterii jest włączone."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Ładowanie przy użyciu złącza USB nie jest obsługiwane.\nNależy używać tylko dołączonej ładowarki."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Ładowanie przez USB nie jest obsługiwane."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Używaj tylko ładowarki dostarczonej z urządzeniem."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Wygaszacz ekranu"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Tryb samolotowy"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Ładowanie (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Naładowana"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (urządzenia: <xliff:g id="NUMBER">%d</xliff:g>)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth wył."</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Oszczędzanie baterii jest włączone"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Zmniejsza wydajność i ogranicza dane w tle"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Wyłącz oszczędzanie baterii"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Treści ukryte"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> będzie zapisywać wszystko, co wyświetli się na ekranie."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Nie pokazuj ponownie"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index c06be78..2a1de08 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Em curso"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificações"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Bateria fraca"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> restante"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> restantes. A Poupança de bateria está ligada."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> restante"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> restante. A poupança da bateria está ativada."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Carregamento USB não suportado. \nUtilize apenas o carregador fornecido."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"O carregamento por USB não é suportado."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Utilize apenas o carregador fornecido."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Modo de avião"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"A carregar, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Carregada"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Dispositivos)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth desat."</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"A poupança de bateria está ligada"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Reduz o desempenho e os dados de segundo plano"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desativar a poupança de bateria"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Conteúdo oculto"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"O(a) <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vai começar a captar tudo o que é apresentado no ecrã."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Não mostrar de novo"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 075cdf1..703eb33 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Em andamento"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificações"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Bateria fraca"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> restante"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> restante(s). A Economia de bateria está ativada."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> restantes"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> restantes. A Economia de bateria está ativada."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"O carregamento via USB não é suportado.\nUse apenas o carregador fornecido."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"O carregamento via USB não é suportado."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Use apenas o carregador fornecido."</string>
@@ -226,8 +226,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Modo avião"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Carregando, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Carregado"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> dispositivos)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth desativado"</string>
@@ -326,7 +324,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"A Economia de bateria está ativada"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Reduz o desempenho e os dados em segundo plano"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desativar a economia de bateria"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Conteúdo oculto"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> começará a capturar tudo o que for exibido na tela."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Não mostrar novamente"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index bd82615..1276588 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"În desfăşurare"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificări"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Bateria este aproape descărcată"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"Rămas: <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Procent rămas din baterie: <xliff:g id="NUMBER">%d%%</xliff:g>. Economisirea bateriei este activată."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"Procent rămas din baterie: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Procent rămas din baterie: <xliff:g id="PERCENTAGE">%s</xliff:g>. Economisirea bateriei este activată."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Încărcarea USB nu este acceptată. \nUtilizaţi numai încărcătorul furnizat."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Încărcarea prin USB nu este acceptată."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Utilizați numai încărcătorul furnizat."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Mod Avion"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Se încarcă, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Încărcată"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> dispozitive)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth dezactivat"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Economisirea bateriei este activată"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Reduce performanța și datele de fundal"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Dezactivați economisirea bateriei"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Conținutul este ascuns"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> va începe să captureze tot ceea ce se afișează pe ecran."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Nu se mai afișează"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 964f98d..9aa6531 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Текущие"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Уведомления"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Батарея почти разряжена"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"Осталось <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Уровень заряда батареи: <xliff:g id="NUMBER">%d%%</xliff:g>. Включен режим энергосбережения."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"Осталось: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Осталось: <xliff:g id="PERCENTAGE">%s</xliff:g>. Включен режим энергосбережения."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Зарядка через порт USB не поддерживается.\nИспользуйте только зарядное устройство из комплекта поставки."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Зарядка через USB не поддерживается."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Используйте только зарядное устройство, поставляемое в комплекте с устройством."</string>
@@ -226,8 +226,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Заставка"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Режим полета"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"100%%"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g>)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth выкл."</string>
@@ -326,7 +324,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Включен режим энергосбережения"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Откл. фоновой передачи данных"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Отключить режим энергосбережения"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Содержимое скрыто"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"Приложение <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> получит доступ к изображению на экране устройства."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Больше не показывать"</string>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index 0df07ce..b194e78 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"දැනට පවතින"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"දැනුම්දීම්"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"බැටරිය අඩුය"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> ක් ඉතිරියි"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> ක් ඉතිරියි. බැටරිය සුරකින්නා සක්‍රීයයි."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> ඉතිරිව තිබේ"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> ඉතිරිව තිබේ. බැටරිය සුරැකීම සක්‍රීයි."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB ආරෝපණය සහය නොදක්වයි.\nසපයන ලද ආරෝපකය පමණක් භාවිතා කරන්න."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"USB ආරෝපණය කිරීම සහාය නොදක්වයි."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"සපයන ලද අරෝපකය පමණක් භාවිතා කරන්න."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"දවල් හීනය"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"ඊතර නෙට්"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"අහස්යානා ආකාරය"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"ආරෝපණය වෙමින්, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"අරෝපිතයි"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"බ්ලූටූත්"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"බ්ලූටූත් (උපාංග <xliff:g id="NUMBER">%d</xliff:g>)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"බ්ලූටූත් අක්‍රියයි"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"බැටරිය සුරකින්නා සක්‍රීයයි"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"ක්‍රියාකාරිත්වය සහ පසුබිම් දත්ත අඩු කරන්න"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"බැටරි සුරැකීම අක්‍රිය කරන්න"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"සැඟවුණු සම්බන්ධතා"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"ඔබගේ තීරයේ දර්ශනය වන සෑම දෙයම <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ලබාගැනීම ආරම්භ කරන ලදි."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"නැවත නොපෙන්වන්න"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index f9191ff..1933b90 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Prebiehajúce"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Upozornenia"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Batéria je takmer vybitá"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"Zostáva: <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Zostáva: <xliff:g id="NUMBER">%d%%</xliff:g>. Šetrič batérie je zapnutý."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"Zostáva <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Zostáva <xliff:g id="PERCENTAGE">%s</xliff:g>. Úspora batérie je zapnutá."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Nabíjanie pomocou rozhrania USB nie je podporované.\nPoužívajte iba nabíjačku, ktorá bola dodaná spolu so zariadením."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Nabíjanie prostredníctvom USB nie je podporované."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Používajte iba originálnu nabíjačku."</string>
@@ -226,8 +226,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Šetrič obrazovky"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Režim v lietadle"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Nabíjanie, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Nabité"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Rozhranie Bluetooth (počet zariadení: <xliff:g id="NUMBER">%d</xliff:g>)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Rozhranie Bluetooth je vypnuté"</string>
@@ -326,7 +324,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Šetrič batérie je zapnutý"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Obmedzí výkonnosť a prenos údajov na pozadí"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Vypnúť šetrič batérie"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g> %%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Skrytý obsah"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"Aplikácia <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> začne zaznamenávať všetok obsah zobrazený na vašej obrazovke."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Nabudúce nezobrazovať"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index b441b9b..594b760 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Trenutno"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Obvestila"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Akumulator je skoraj izpraznjen"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> preostalo"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Še <xliff:g id="NUMBER">%d%%</xliff:g>. Varčevanje z energijo akumulatorja je vklopljeno."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"Še <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Še <xliff:g id="PERCENTAGE">%s</xliff:g>. Vklopljeno je varčevanje z energijo akumulatorja."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Polnjenje po povezavi USB ni podprto.\nUporabite priloženi polnilnik."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Polnjenje prek USB-ja ni podprto."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Uporabljajte samo priloženi polnilnik."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Sanjarjenje"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Način za letalo"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Polnjenje, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Napolnjeno"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (št. naprav: <xliff:g id="NUMBER">%d</xliff:g>)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth izklopljen"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Varčevanje z energijo akumulatorja je vklopljeno"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Omeji zmogljivost delovanja in prenos podatkov v ozadju"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Izklop varčevanja z energijo akumulatorja"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Vsebina je skrita"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"Aplikacija <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> bo začela zajemati vse, kar je prikazano na zaslonu."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Tega ne prikaži več"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 4c1d194..f7025fe 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Текуће"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Обавештења"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Ниво напуњености батерије је низак"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"преостало је <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Преостало је још <xliff:g id="NUMBER">%d%%</xliff:g>. Штедња батерије је укључена."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"Још <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Још <xliff:g id="PERCENTAGE">%s</xliff:g>. Укључена је штедња батерије."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Пуњење преко USB-а није подржано.\nКористите само приложени пуњач."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Пуњење преко USB-а није подржано."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Користите само пуњач који сте добили."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Сањарење"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Етернет"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Режим рада у авиону"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Пуњење, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Напуњено"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> уређаја)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth искључен"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Штедња батерије је укључена"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Смањује перформансе и позадинске податке"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Искључи штедњу батерије"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Садржај је сакривен"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ће почети да снима све што се приказује на екрану."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Не приказуј поново"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index c59f6a1..9718752 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Pågående"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Meddelanden"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Lågt batteri"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> återstår"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> kvar. Batterisparläget har aktiverats."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> kvar"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> kvar. Batterisparläget är aktiverat."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Det går inte att ladda via USB.\nAnvänd endast den laddare som levererades med telefonen."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Det finns inget stöd för laddning via USB."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Använd endast den medföljande laddaren."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Dagdröm"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Flygplansläge"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Laddar, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Laddat"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> enheter)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth av"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Batterisparläget har aktiverats"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Minskar prestanda och bakgrundsdata"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Inaktivera batterisparläget"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Innehåll har dolts"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tar en bild av allt som visas på skärmen."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Visa inte igen"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index fcb15eb..399204c 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Inaendelea"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Arifa"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Betri imeisha"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> zimebakia"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Imesalia <xliff:g id="NUMBER">%d%%</xliff:g>. Kiokoa betri kimewashwa."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> iliyosalia"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> iliyosalia. Kiokoa betri kimewashwa."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Chaji ya USB haihamiliwi.\n Tumia chaka iliyopeanwa."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Kuchaji kwa kutumia USB hakutumiki."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Tumia chaja iliyonunuliwa pamoja na kifaa pekee."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Hali Tulivu"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Hali ya ndege"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Inachaji, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Betri imejaa"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (Vifaa <xliff:g id="NUMBER">%d</xliff:g>)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth Imezimwa"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Kiokoa betri kimewashwa"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Hupunguza utendaji na data ya chini chini"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Zima kiokoa betri"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Maudhui yamefichwa"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> itaanza kupiga picha kila kitu kinachoonyeshwa kwenye skrini yako."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Usionyeshe tena"</string>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index 10410d3..7b629d7 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"செயலில் இருக்கும்"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"அறிவிப்புகள்"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"பேட்டரி குறைவு"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> மீதமுள்ளது"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> உள்ளது. பேட்டரி சேமிப்பான் இயக்கத்தில் உள்ளது."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> உள்ளது"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> உள்ளது. பேட்டரி சேமிப்பான் இயக்கத்தில் உள்ளது."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB மூலம் சார்ஜ் செய்வது ஆதரிக்கப்படவில்லை.\nவழங்கப்பட்ட சார்ஜரை மட்டும் பயன்படுத்தவும்."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"USB சார்ஜிங் ஆதரிக்கப்படவில்லை."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"வழங்கப்பட்ட சார்ஜரை மட்டும் பயன்படுத்துக."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"பகல்கனா"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"ஈதர்நெட்"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"விமானப் பயன்முறை"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"சார்ஜ் ஏற்றுகிறது, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"சார்ஜ் செய்யப்பட்டது"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"புளூடூத்"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"புளூடூத் (<xliff:g id="NUMBER">%d</xliff:g> சாதனங்கள்)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"புளூடூத் ஐ முடக்கு"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"பேட்டரி சேமிப்பான் இயக்கத்தில் உள்ளது"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"செயல்திறனையும் பின்புலத் தரவையும் குறைக்கிறது"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"பேட்டரி சேமிப்பானை முடக்கு"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"மறைந்துள்ள உள்ளடக்கம்"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"திரையில் காட்டப்படும் அனைத்தையும் <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> படமெடுக்கும்."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"மீண்டும் காட்டாதே"</string>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index 14f440f..8e3faed 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"కొనసాగుతున్నవి"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"నోటిఫికేషన్‌లు"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"బ్యాటరీ తక్కువగా ఉంది"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> మిగిలి ఉంది"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> మిగిలి ఉంది. బ్యాటరీ సేవర్ ఆన్‌లో ఉంది."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> మిగిలి ఉంది"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> మిగిలి ఉంది. బ్యాటరీ సేవర్ ఆన్‌లో ఉంది."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB ఛార్జింగ్‌కు మద్దతు లేదు.\nఅందించిన ఛార్జర్‌ను మాత్రమే ఉపయోగించండి."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"USB ఛార్జింగ్‌కి మద్దతు లేదు."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"అందించిన ఛార్జర్‌ను మాత్రమే ఉపయోగించండి."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"డేడ్రీమ్"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"ఈథర్‌నెట్"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"ఎయిర్‌ప్లేన్ మోడ్"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"ఛార్జ్ చేయబడుతోంది, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"ఛార్జ్ చేయబడింది"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"బ్లూటూత్"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"బ్లూటూత్ (<xliff:g id="NUMBER">%d</xliff:g> పరికరాలు)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"బ్లూటూత్ ఆఫ్‌లో ఉంది"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"బ్యాటర్ సేవర్ ఆన్ చేయబడింది"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"పనితీరుని మరియు నేపథ్య డేటాను తగ్గిస్తుంది"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"బ్యాటరీ సేవర్‌ను ఆఫ్ చేయి"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"కంటెంట్‌లు దాచబడ్డాయి"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> మీ స్క్రీన్‌పై కనిపించే ప్రతిదాన్ని క్యాప్చర్ చేయడం ప్రారంభిస్తుంది."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"మళ్లీ చూపవద్దు"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 80657c7..45c570f 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"ดำเนินอยู่"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"การแจ้งเตือน"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"แบตเตอรี่เหลือน้อย"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"เหลืออีก <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"แบตเตอรี่เหลือ <xliff:g id="NUMBER">%d%%</xliff:g> เปิดโหมดประหยัดแบตเตอรี่อยู่"</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"เหลืออีก <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"เหลืออีก <xliff:g id="PERCENTAGE">%s</xliff:g> เปิดประหยัดแบตเตอรี่"</string>
     <string name="invalid_charger" msgid="4549105996740522523">"ไม่สนับสนุนการชาร์จแบบ USB\nใช้เฉพาะที่ชาร์จที่ให้มาเท่านั้น"</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"ไม่รองรับการชาร์จผ่าน USB"</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"ใช้เฉพาะที่ชาร์จที่ให้มา"</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"เดย์ดรีม"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"อีเทอร์เน็ต"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"โหมดใช้บนเครื่องบิน"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"กำลังชาร์จ, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"ชาร์จแล้ว"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"บลูทูธ"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"บลูทูธ (<xliff:g id="NUMBER">%d</xliff:g> อุปกรณ์)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"ปิดบลูทูธ"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"เปิดโหมดประหยัดแบตเตอรี่อยู่"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"ลดการใช้แบตเตอรี่และข้อมูลแบ็กกราวด์"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"ปิดโหมดประหยัดแบตเตอรี่"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"เนื้อหาถูกซ่อนไว้"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> จะเริ่มจับภาพทุกอย่างที่แสดงบนหน้าจอ"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"ไม่ต้องแสดงข้อความนี้อีก"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index a1a7a46..fbf6132 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Nagpapatuloy"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Mga Notification"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Mahina na ang baterya"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> natitira"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> ang natitira. Naka-on ang tagatipid ng baterya."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> na lang ang natitira"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> na lang ang natitira. Naka-on ang battery saver."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Hindi sinusuportahan ang pag-charge sa USB.\nGamitin lang ang ibinigay na charger."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Hindi sinusuportahan ang pagtsa-charge gamit ang USB."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Gamitin lang ang ibinigay na charger."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Airplane mode"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Nagcha-charge, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Na-charge"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> (na) Device)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Naka-off ang Bluetooth"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Naka-on ang tagatipid ng baterya"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Binabawasan ang pagganap at data sa background"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"I-off ang pagtitipid ng baterya"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Nakatago ang mga content"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"Sisimulan ng i-capture ng <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ang lahat ng ipinapakita sa iyong screen."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Huwag ipakitang muli"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index e1b4465..e121613 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Sürüyor"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Bildirimler"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Pil gücü düşük"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> kaldı"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> kaldı. Pil tasarrufu açık."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> kaldı"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> kaldı. Pil tasarrufu açık."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB üzerinden şarj desteklenmiyor.\nYalnızca ürünle birlikte verilen şarj cihazını kullanın."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"USB şarjı desteklenmiyor."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Yalnızca ürünle birlikte verilen şarj cihazını kullanın."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Hafif uyku"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Uçak modu"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Şarj oluyor, <xliff:g id="PERCENT">%%</xliff:g><xliff:g id="NUMBER">%d</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Şarj oldu"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Cihaz)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth Kapalı"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Pil tasarrufu açık"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Performansı ve arka plan verilerini azaltır"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Pil tasarrufunu kapat"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"%%<xliff:g id="LEVEL">%d</xliff:g>"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"İçerik gizlendi"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>, ekranınızda görüntülenen her şeyi kaydetmeye başlayacak."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Bir daha gösterme"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 5871b03..0bdb5c5 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Поточні"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Сповіщення"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Низький рівень заряду акумулятора"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"Залишилося <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Залишилося <xliff:g id="NUMBER">%d%%</xliff:g>. Режим заощадження заряду акумулятора ввімкнено."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"Залишилося <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Залишилося <xliff:g id="PERCENTAGE">%s</xliff:g>. Режим заощадження заряду акумулятора ввімкнено."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Заряджання USB не підтримується.\nВикористовуйте лише наданий у комплекті зарядний пристрій."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Заряджання через USB не підтримується."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Використовуйте лише зарядний пристрій, який постачається в комплекті."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Заставка"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Режим польоту"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Заряджається, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Заряджено"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (пристроїв: <xliff:g id="NUMBER">%d</xliff:g>)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth вимкнено"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Режим заощадження заряду акумулятора ввімкнено"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Знижується продуктивність і обмежуються фонові дані"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Вимкнути режим заощадження заряду акумулятора"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Вміст сховано"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> отримає доступ до всіх даних, які відображаються на вашому екрані."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Більше не показувати"</string>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index d75796f..4251334 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"جاری"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"اطلاعات"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"بیٹری کم ہے"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> باقی ہے"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> باقی ہے۔ بیٹری سیور آن ہے۔"</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> باقی ہے"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> باقی ہے۔ بیٹری سیور آن ہے۔"</string>
     <string name="invalid_charger" msgid="4549105996740522523">"‏USB چارجنگ تعاون یافتہ نہیں ہے.\nصرف فراہم کردہ چارجر کا ہی استعمال کریں۔"</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"‏USB چارجنگ تعاون یافتہ نہیں ہے۔"</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"صرف فراہم کردہ چارجر استعمال کریں۔"</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"ایتھرنیٹ"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"ہوائی جہاز طرز"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"چارج ہو رہی ہے، <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"چارج ہوگئی"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"بلوٹوتھ"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"بلوٹوتھ (<xliff:g id="NUMBER">%d</xliff:g> آلات)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"بلوٹوتھ آف ہے"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"بیٹری سیور آن ہے"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"کارکردگی اور پس منظر کا ڈیٹا کم کر دیتا ہے"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"بیٹری کی بچت آف کریں"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"‎<xliff:g id="LEVEL">%d</xliff:g>%%‎"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"مواد مخفی ہیں"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> آپ کی اسکرین پر ڈسپلے ہونے والی ہر چیز کو کیپچر کرنا شروع کر دیگی۔"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"دوبارہ نہ دکھائیں"</string>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index f8d0519e..422a82f 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Joriy"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Eslatmalar"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Batareya quvvati kam"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> qolmoqda"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> qoldi. Quvvat tejash funksiyasi yoqilgan."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> qoldi"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> qoldi. Quvvat tejash funksiyasi yoqilgan."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB orqali zaryadlab bo‘lmaydi.\nFaqat taklif qilingan zaryadlagichdan foydalaning."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"USB orqali quvvat oldirish qo‘llab-quvvatlanmaydi."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Faqat qurilma bilan kelgan quvvatlash moslamasidan foydalaning."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Tush kurish"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Parvoz rejimi"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Zaryadlanmoqda: <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Zaryad to‘la"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g>ta qurilma)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth o‘chirilgan"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Quvvat tejash yoqilgan"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Unumdorlikni pasaytiradi va fonda int-dan foyd-ni cheklaydi"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Quvvat tejash funksiyasini o‘chiring"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Kontent yashirildi"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ilovasi qurilma ekranidagi har qanday tasvirni ko‘rishni boshlaydi."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Boshqa ko‘rsatilmasin"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index e4c8ee2..d070968 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Đang diễn ra"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Thông báo"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Pin yếu"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> còn lại"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Còn lại <xliff:g id="NUMBER">%d%%</xliff:g>. Trình tiết kiệm pin đang bật."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"Còn lại <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Còn lại <xliff:g id="PERCENTAGE">%s</xliff:g>. Trình tiết kiệm pin đang bật."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Không hỗ trợ sạc qua USB.\nChỉ sử dụng bộ sạc được cung cấp."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Sạc qua USB không được hỗ trợ."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Chỉ sử dụng bộ sạc được cung cấp."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Chế độ ngủ"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Chế độ trên máy bay"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Đang sạc, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Đã sạc"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> thiết bị)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Đã tắt Bluetooth"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Trình tiết kiệm pin đang bật"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Giảm hiệu suất và dữ liệu nền"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Tắt trình tiết kiệm pin"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Nội dung bị ẩn"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sẽ bắt đầu chụp mọi thứ hiển thị trên màn hình."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Không hiển thị lại"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index cf3f57c..db7e5e5 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"正在进行的"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"电池电量偏低"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"还剩<xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"电量还剩<xliff:g id="NUMBER">%d%%</xliff:g>。节电助手已开启。"</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"剩余<xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"剩余<xliff:g id="PERCENTAGE">%s</xliff:g>。节电助手已开启。"</string>
     <string name="invalid_charger" msgid="4549105996740522523">"不支持USB充电功能。\n只能使用随附的充电器充电。"</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"不支持USB充电。"</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"仅限使用设备随附的充电器。"</string>
@@ -226,8 +226,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"互动屏保"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"有线网络"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"飞行模式"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"正在充电:<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"充电完成"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"蓝牙"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"蓝牙(<xliff:g id="NUMBER">%d</xliff:g> 台设备)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"蓝牙:关闭"</string>
@@ -326,7 +324,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"节电助手已开启"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"降低性能并限制后台流量"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"关闭节电助手"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"内容已隐藏"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>将开始截取您的屏幕上显示的所有内容。"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"不再显示"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 5a76eec..5c5f07e 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"持續進行"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"電量低"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"剩餘 <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"電量尚餘 <xliff:g id="NUMBER">%d%%</xliff:g>,省電模式已開啟。"</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"剩餘 <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"剩餘 <xliff:g id="PERCENTAGE">%s</xliff:g>。開啟省電模式。"</string>
     <string name="invalid_charger" msgid="4549105996740522523">"不支援 USB 充電。\n僅能使用隨附的充電器。"</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"不支援 USB 充電功能。"</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"僅限使用裝置隨附的充電器。"</string>
@@ -226,8 +226,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"以太網"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"飛行模式"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"充電中 (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"充電完成"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"藍牙"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"藍牙 (<xliff:g id="NUMBER">%d</xliff:g> 部裝置)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"藍牙關閉"</string>
@@ -326,7 +324,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"省電模式已開啟"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"降低效能並限制背景數據傳輸"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"關閉省電模式"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"內容已隱藏"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 將開始擷取您的螢幕上顯示的內容。"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"不用再顯示"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 2f48a15..cbf73aa 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"進行中"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"電池電力不足"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"還剩 <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"電力剩下 <xliff:g id="NUMBER">%d%%</xliff:g>,節約耗電量模式已啟用。"</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"僅剩 <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"僅剩 <xliff:g id="PERCENTAGE">%s</xliff:g>。節約耗電量模式已開啟。"</string>
     <string name="invalid_charger" msgid="4549105996740522523">"不支援 USB 充電。\n僅能使用隨附的充電器。"</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"不支援 USB 充電功能。"</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"僅限使用裝置隨附的充電器。"</string>
@@ -226,8 +226,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"休眠模式"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"乙太網路"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"飛航模式"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"充電中 (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"充電完成"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"藍牙"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"藍牙 (<xliff:g id="NUMBER">%d</xliff:g> 個裝置)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"關閉藍牙"</string>
@@ -326,7 +324,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"節約耗電量模式已啟用"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"降低效能並限制背景數據傳輸"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"關閉節約耗電量模式"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"內容已隱藏"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 將開始擷取您的螢幕上顯示的內容。"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"不要再顯示"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index ad25dab..298f7b8 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -33,8 +33,8 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Okuqhubekayo"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Izaziso"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Ibhethri liphansi"</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> okusele"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> esele. Isilondolozi Sebhethri sivuliwe."</string>
+    <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> okusele"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> okusele. Isilondolozi sebhethri sivulekile."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Ukushaja i-USB akusekelwe.\nSebenzisa kuphela ishaja enikeziwe."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Ukushaja kwe-USB akusekelwe."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Sebenzisa kuphela ishaja enikeziwe."</string>
@@ -224,8 +224,6 @@
     <string name="start_dreams" msgid="7219575858348719790">"Ukuphupha emini"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"I-Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Isimo sendiza"</string>
-    <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Iyashaja <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Kushajiwe"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"I-Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"I-Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> amadivayisi)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"I-Bluetooth ivaliwe"</string>
@@ -324,7 +322,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Isilondolozi sebhethri sivuliwe"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Sehlisa ukusebenza nedatha yasemuva"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Vala isilondolozi sebhethri"</string>
-    <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Okuqukethwe kufihliwe"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> izoqala ukuthwebula yonke into eboniswa kusikrini sakho."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Ungabonisi futhi"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index cd82c45..aaa350c 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -238,8 +238,11 @@
     <!-- Volume: time to delay dismissing the volume panel after a click is performed -->
     <integer name="volume_panel_dismiss_delay">200</integer>
 
-    <!-- Tiles with feature timeouts: number of days to show after feature is used. -->
-    <integer name="days_to_show_timeout_tiles">30</integer>
+    <!-- Hotspot tile: number of days to show after feature is used. -->
+    <integer name="days_to_show_hotspot_tile">30</integer>
+
+    <!-- Color inversion tile: number of days to show after feature is used. -->
+    <integer name="days_to_show_color_inversion_tile">7</integer>
 
     <!-- Number of times to show the strong alarm warning text in the volume dialog -->
     <integer name="zen_mode_alarm_warning_threshold">5</integer>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 4f41cd5..c478071 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -358,6 +358,9 @@
     <!-- radius of the corners of the material rounded rect background -->
     <dimen name="notification_material_rounded_rect_radius">2dp</dimen>
 
+    <!-- radius of the corners of the material rounded rect background but negative-->
+    <dimen name="notification_material_rounded_rect_radius_negative">-2dp</dimen>
+
     <!-- end margin for multi user switch in expanded quick settings -->
     <dimen name="multi_user_switch_expanded_margin">8dp</dimen>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 71b9b61..89bbacf 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -62,12 +62,12 @@
     <string name="battery_low_title">Battery is low</string>
 
     <!-- A message that appears when the battery level is getting low in a dialog.  This is
-        appened to the subtitle of the low battery alert.  "number" is the percentage of battery
+        appened to the subtitle of the low battery alert.  "percentage" is the percentage of battery
         remaining [CHAR LIMIT=none]-->
-    <string name="battery_low_percent_format"><xliff:g id="number">%d%%</xliff:g> remaining</string>
+    <string name="battery_low_percent_format"><xliff:g id="percentage">%s</xliff:g> remaining</string>
 
     <!-- Same as battery_low_percent_format, with a notice about battery saver if on. [CHAR LIMIT=none]-->
-    <string name="battery_low_percent_format_saver_started"><xliff:g id="number">%d%%</xliff:g> remaining. Battery saver is on.</string>
+    <string name="battery_low_percent_format_saver_started"><xliff:g id="percentage">%s</xliff:g> remaining. Battery saver is on.</string>
 
     <!-- A message that appears when a USB charger is plugged in and the device does not
     support charging on it.  That is, a charger that fits into the USB port and goes into
@@ -115,11 +115,6 @@
     <!-- Label in system panel saying the device will show notifications [CHAR LIMIT=30] -->
     <string name="status_bar_settings_notifications">Notifications</string>
 
-    <!-- Text to display next to the graphical battery meter.  [CHAR LIMIT=3] -->
-    <string name="status_bar_settings_battery_meter_format" translatable="false">
-        <xliff:g id="number">%d</xliff:g><xliff:g id="percent">%%</xliff:g>
-    </string>
-
     <!-- Separator for PLMN and SPN in network name. -->
     <string name="status_bar_network_name_separator" translatable="false">|</string>
 
@@ -559,10 +554,6 @@
 
     <!-- QuickSettings: Airplane mode [CHAR LIMIT=NONE] -->
     <string name="quick_settings_airplane_mode_label">Airplane mode</string>
-    <!-- QuickSettings: Battery Charging [CHAR LIMIT=NONE] -->
-    <string name="quick_settings_battery_charging_label">Charging, <xliff:g id="number">%d</xliff:g><xliff:g id="percent">%%</xliff:g></string>
-    <!-- QuickSettings: Battery Charged [CHAR LIMIT=NONE] -->
-    <string name="quick_settings_battery_charged_label">Charged</string>
     <!-- QuickSettings: Bluetooth [CHAR LIMIT=NONE] -->
     <string name="quick_settings_bluetooth_label">Bluetooth</string>
     <!-- QuickSettings: Bluetooth (Multiple) [CHAR LIMIT=NONE] -->
@@ -813,9 +804,6 @@
     <!-- Battery saver notification action text. [CHAR LIMIT=60] -->
     <string name="battery_saver_notification_action_text">Turn off battery saver</string>
 
-    <!-- Battery level for expanded quick settings [CHAR LIMIT=2] -->
-    <string name="battery_level_template"><xliff:g id="level" example="45">%d</xliff:g>%%</string>
-
     <!-- Text shown in place of notification contents when the notification is hidden on a secure lockscreen -->
     <string name="notification_hidden_text">Contents hidden</string>
 
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index f184ad2..f5df1a9 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -43,6 +43,7 @@
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 
 import java.io.PrintWriter;
+import java.text.NumberFormat;
 
 public class PowerNotificationWarnings implements PowerUI.WarningsUI {
     private static final String TAG = PowerUI.TAG + ".Notification";
@@ -143,7 +144,7 @@
             showSaverNotification();
             mShowing = SHOWING_SAVER;
         } else {
-            mNoMan.cancel(TAG_NOTIFICATION, ID_NOTIFICATION);
+            mNoMan.cancelAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, UserHandle.ALL);
             mShowing = SHOWING_NOTHING;
         }
     }
@@ -157,7 +158,6 @@
                 .setContentTitle(mContext.getString(R.string.invalid_charger_title))
                 .setContentText(mContext.getString(R.string.invalid_charger_text))
                 .setPriority(Notification.PRIORITY_MAX)
-                .setCategory(Notification.CATEGORY_SYSTEM)
                 .setVisibility(Notification.VISIBILITY_PUBLIC)
                 .setColor(mContext.getResources().getColor(
                         com.android.internal.R.color.system_notification_accent_color));
@@ -165,22 +165,22 @@
         if (n.headsUpContentView != null) {
             n.headsUpContentView.setViewVisibility(com.android.internal.R.id.right_icon, View.GONE);
         }
-        mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, n, UserHandle.CURRENT);
+        mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, n, UserHandle.ALL);
     }
 
     private void showWarningNotification() {
         final int textRes = mSaver ? R.string.battery_low_percent_format_saver_started
                 : R.string.battery_low_percent_format;
+        final String percentage = NumberFormat.getPercentInstance().format((double) mBatteryLevel / 100.0);
         final Notification.Builder nb = new Notification.Builder(mContext)
                 .setSmallIcon(R.drawable.ic_power_low)
                 // Bump the notification when the bucket dropped.
                 .setWhen(mBucketDroppedNegativeTimeMs)
                 .setShowWhen(false)
                 .setContentTitle(mContext.getString(R.string.battery_low_title))
-                .setContentText(mContext.getString(textRes, mBatteryLevel))
+                .setContentText(mContext.getString(textRes, percentage))
                 .setOnlyAlertOnce(true)
                 .setPriority(Notification.PRIORITY_MAX)
-                .setCategory(Notification.CATEGORY_SYSTEM)
                 .setVisibility(Notification.VISIBILITY_PUBLIC)
                 .setColor(mContext.getResources().getColor(
                         com.android.internal.R.color.battery_saver_mode_color));
@@ -202,7 +202,7 @@
         if (n.headsUpContentView != null) {
             n.headsUpContentView.setViewVisibility(com.android.internal.R.id.right_icon, View.GONE);
         }
-        mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, n, UserHandle.CURRENT);
+        mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, n, UserHandle.ALL);
     }
 
     private void showSaverNotification() {
@@ -212,7 +212,6 @@
                 .setContentText(mContext.getString(R.string.battery_saver_notification_text))
                 .setOngoing(true)
                 .setShowWhen(false)
-                .setCategory(Notification.CATEGORY_SYSTEM)
                 .setVisibility(Notification.VISIBILITY_PUBLIC)
                 .setColor(mContext.getResources().getColor(
                         com.android.internal.R.color.battery_saver_mode_color));
@@ -220,7 +219,7 @@
         if (hasSaverSettings()) {
             nb.setContentIntent(pendingActivity(mOpenSaverSettings));
         }
-        mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, nb.build(), UserHandle.CURRENT);
+        mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, nb.build(), UserHandle.ALL);
     }
 
     private void addStopSaverAction(Notification.Builder nb) {
@@ -341,6 +340,11 @@
         updateNotification();
     }
 
+    @Override
+    public void userSwitched() {
+        updateNotification();
+    }
+
     private void showStartSaverConfirmation() {
         if (mSaverConfirmation != null) return;
         final SystemUIDialog d = new SystemUIDialog(mContext);
@@ -370,7 +374,7 @@
             filter.addAction(ACTION_SHOW_BATTERY_SETTINGS);
             filter.addAction(ACTION_START_SAVER);
             filter.addAction(ACTION_STOP_SAVER);
-            mContext.registerReceiver(this, filter, null, mHandler);
+            mContext.registerReceiverAsUser(this, UserHandle.ALL, filter, null, mHandler);
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index d3c7dee..9459740 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -137,6 +137,7 @@
             filter.addAction(Intent.ACTION_BATTERY_CHANGED);
             filter.addAction(Intent.ACTION_SCREEN_OFF);
             filter.addAction(Intent.ACTION_SCREEN_ON);
+            filter.addAction(Intent.ACTION_USER_SWITCHED);
             filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING);
             filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
             mContext.registerReceiver(this, filter, null, mHandler);
@@ -207,6 +208,8 @@
                 mScreenOffTime = SystemClock.elapsedRealtime();
             } else if (Intent.ACTION_SCREEN_ON.equals(action)) {
                 mScreenOffTime = -1;
+            } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+                mWarnings.userSwitched();
             } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) {
                 updateSaverMode();
             } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGING.equals(action)) {
@@ -256,6 +259,7 @@
         void updateLowBatteryWarning();
         boolean isInvalidChargerWarningShowing();
         void dump(PrintWriter pw);
+        void userSwitched();
     }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
index eb4560d..111484b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
@@ -55,7 +55,6 @@
         if (listener != null) {
             mAnimator.addListener(listener);
         }
-        mDetail.setLayerType(View.LAYER_TYPE_HARDWARE, null);
         if (in) {
             mBackground.startTransition((int)(mAnimator.getDuration() * 0.6));
             mAnimator.addListener(mVisibleOnStart);
@@ -82,7 +81,6 @@
         }
 
         public void onAnimationEnd(Animator animation) {
-            mDetail.setLayerType(View.LAYER_TYPE_NONE, null);
             mAnimator = null;
         }
     };
@@ -90,7 +88,6 @@
     private final AnimatorListenerAdapter mGoneOnEnd = new AnimatorListenerAdapter() {
         @Override
         public void onAnimationEnd(Animator animation) {
-            mDetail.setLayerType(View.LAYER_TYPE_NONE, null);
             mDetail.setVisibility(View.GONE);
             mBackground.resetTransition();
             mAnimator = null;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/UsageTracker.java b/packages/SystemUI/src/com/android/systemui/qs/UsageTracker.java
index ad79aba..a1092a3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/UsageTracker.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/UsageTracker.java
@@ -22,7 +22,6 @@
 import android.content.IntentFilter;
 import android.content.SharedPreferences;
 
-import com.android.systemui.R;
 import com.android.systemui.statusbar.policy.Listenable;
 
 public class UsageTracker implements Listenable {
@@ -35,11 +34,10 @@
 
     private boolean mRegistered;
 
-    public UsageTracker(Context context, Class<?> tile) {
+    public UsageTracker(Context context, Class<?> tile, int timeoutResource) {
         mContext = context;
         mPrefKey = tile.getSimpleName() + "LastUsed";
-        mTimeToShowTile = MILLIS_PER_DAY * mContext.getResources()
-                .getInteger(R.integer.days_to_show_timeout_tiles);
+        mTimeToShowTile = MILLIS_PER_DAY * mContext.getResources().getInteger(timeoutResource);
         mResetAction = "com.android.systemui.qs." + tile.getSimpleName() + ".usage_reset";
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index 01849c1..7ba1dc0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -44,7 +44,8 @@
                 }
             }
         };
-        mUsageTracker = new UsageTracker(host.getContext(), ColorInversionTile.class);
+        mUsageTracker = new UsageTracker(host.getContext(), ColorInversionTile.class,
+                R.integer.days_to_show_color_inversion_tile);
         if (mSetting.getValue() != 0 && !mUsageTracker.isRecentlyUsed()) {
             mUsageTracker.trackUsage();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index ce99cc3..b30a1d3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -34,7 +34,7 @@
     public HotspotTile(Host host) {
         super(host);
         mController = host.getHotspotController();
-        mUsageTracker = new UsageTracker(host.getContext(), HotspotTile.class);
+        mUsageTracker = newUsageTracker(host.getContext());
         mUsageTracker.setListening(true);
     }
 
@@ -84,6 +84,10 @@
         }
     }
 
+    private static UsageTracker newUsageTracker(Context context) {
+        return new UsageTracker(context, HotspotTile.class, R.integer.days_to_show_hotspot_tile);
+    }
+
     private final class Callback implements HotspotController.Callback {
         @Override
         public void onHotspotChanged(boolean enabled) {
@@ -101,7 +105,7 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             if (mUsageTracker == null) {
-                mUsageTracker = new UsageTracker(context, HotspotTile.class);
+                mUsageTracker = newUsageTracker(context);
             }
             mUsageTracker.trackUsage();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
index 1283dcd..1ca67bc 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
@@ -59,7 +59,6 @@
     final public static String EXTRA_FROM_HOME = "recents.triggeredOverHome";
     final public static String EXTRA_FROM_SEARCH_HOME = "recents.triggeredOverSearchHome";
     final public static String EXTRA_FROM_APP_THUMBNAIL = "recents.animatingWithThumbnail";
-    final public static String EXTRA_FROM_APP_FULL_SCREENSHOT = "recents.thumbnail";
     final public static String EXTRA_FROM_TASK_ID = "recents.activeTaskId";
     final public static String EXTRA_TRIGGERED_FROM_ALT_TAB = "recents.triggeredFromAltTab";
     final public static String EXTRA_TRIGGERED_FROM_HOME_KEY = "recents.triggeredFromHomeKey";
@@ -74,7 +73,6 @@
     final static String sRecentsPackage = "com.android.systemui";
     final static String sRecentsActivity = "com.android.systemui.recents.RecentsActivity";
 
-    static Bitmap sLastScreenshot;
     static RecentsComponent.Callbacks sRecentsComponentCallbacks;
 
     Context mContext;
@@ -256,7 +254,6 @@
     public void onConfigurationChanged(Configuration newConfig) {
         // Reload the header bar layout
         reloadHeaderBarLayout();
-        sLastScreenshot = null;
     }
 
     /** Prepares the header bar layout. */
@@ -394,20 +391,6 @@
      */
     ActivityOptions getThumbnailTransitionActivityOptions(ActivityManager.RunningTaskInfo topTask,
             boolean isTopTaskHome) {
-        if (Constants.DebugFlags.App.EnableScreenshotAppTransition) {
-            // Recycle the last screenshot
-            consumeLastScreenshot();
-
-            // Take the full screenshot
-            sLastScreenshot = mSystemServicesProxy.takeAppScreenshot();
-            if (sLastScreenshot != null) {
-                mStartAnimationTriggered = false;
-                return ActivityOptions.makeCustomAnimation(mContext,
-                        R.anim.recents_from_app_enter,
-                        R.anim.recents_from_app_exit, mHandler, this);
-            }
-        }
-
         // Update the destination rect
         Task toTask = new Task();
         TaskViewTransform toTransform = getThumbnailTransitionTransform(topTask.id, isTopTaskHome,
@@ -493,11 +476,7 @@
             // Try starting with a thumbnail transition
             ActivityOptions opts = getThumbnailTransitionActivityOptions(topTask, isTopTaskHome);
             if (opts != null) {
-                if (sLastScreenshot != null) {
-                    startAlternateRecentsActivity(topTask, opts, EXTRA_FROM_APP_FULL_SCREENSHOT);
-                } else {
-                    startAlternateRecentsActivity(topTask, opts, EXTRA_FROM_APP_THUMBNAIL);
-                }
+                startAlternateRecentsActivity(topTask, opts, EXTRA_FROM_APP_THUMBNAIL);
             } else {
                 // Fall through below to the non-thumbnail transition
                 useThumbnailTransition = false;
@@ -535,7 +514,7 @@
             } else {
                 // Otherwise we do the normal fade from an unknown source
                 ActivityOptions opts = getUnknownTransitionActivityOptions();
-                startAlternateRecentsActivity(topTask, opts, null);
+                startAlternateRecentsActivity(topTask, opts, EXTRA_FROM_HOME);
             }
         }
         mLastToggleTime = System.currentTimeMillis();
@@ -561,19 +540,6 @@
         }
     }
 
-    /** Returns the last screenshot taken, this will be called by the RecentsActivity. */
-    public static Bitmap getLastScreenshot() {
-        return sLastScreenshot;
-    }
-
-    /** Recycles the last screenshot taken, this will be called by the RecentsActivity. */
-    public static void consumeLastScreenshot() {
-        if (sLastScreenshot != null) {
-            sLastScreenshot.recycle();
-            sLastScreenshot = null;
-        }
-    }
-
     /** Sets the RecentsComponent callbacks. */
     public void setRecentsComponentCallback(RecentsComponent.Callbacks cb) {
         sRecentsComponentCallbacks = cb;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index 85cf077..9b84d2e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -25,8 +25,6 @@
         public static final boolean Verbose = false;
 
         public static class App {
-            // Enables the screenshot app->Recents transition
-            public static final boolean EnableScreenshotAppTransition = false;
             // Enables debug drawing for the transition thumbnail
             public static final boolean EnableTransitionThumbnailDebugMode = false;
             // Enables the filtering of tasks according to their grouping
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 01ba5a2..1c8f55b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -189,8 +189,6 @@
                 AlternateRecentsComponent.EXTRA_FROM_HOME, false);
         mConfig.launchedFromAppWithThumbnail = launchIntent.getBooleanExtra(
                 AlternateRecentsComponent.EXTRA_FROM_APP_THUMBNAIL, false);
-        mConfig.launchedFromAppWithScreenshot = launchIntent.getBooleanExtra(
-                AlternateRecentsComponent.EXTRA_FROM_APP_FULL_SCREENSHOT, false);
         mConfig.launchedToTaskId = launchIntent.getIntExtra(
                 AlternateRecentsComponent.EXTRA_FROM_TASK_ID, -1);
         mConfig.launchedWithAltTab = launchIntent.getBooleanExtra(
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 2aca576..bfea3f7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -307,7 +307,6 @@
         launchedWithAltTab = false;
         launchedWithNoRecentTasks = false;
         launchedFromAppWithThumbnail = false;
-        launchedFromAppWithScreenshot = false;
         launchedFromHome = false;
         launchedToTaskId = -1;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
index d2fdaff..421b905 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
@@ -17,12 +17,10 @@
 package com.android.systemui.recents.views;
 
 import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
 import android.graphics.Outline;
 import android.graphics.Rect;
 import android.view.View;
 import android.view.ViewOutlineProvider;
-
 import com.android.systemui.recents.RecentsConfiguration;
 
 /* An outline provider that has a clip and outline that can be animated. */
@@ -31,35 +29,27 @@
     RecentsConfiguration mConfig;
 
     TaskView mSourceView;
-    Rect mTmpRect = new Rect();
     Rect mClipRect = new Rect();
     Rect mClipBounds = new Rect();
-    Rect mOutlineClipRect = new Rect();
     int mCornerRadius;
     float mAlpha = 1f;
     final float mMinAlpha = 0.25f;
 
-    ObjectAnimator mClipTopAnimator;
-    ObjectAnimator mClipRightAnimator;
     ObjectAnimator mClipBottomAnimator;
 
     public AnimateableViewBounds(TaskView source, int cornerRadius) {
         mConfig = RecentsConfiguration.getInstance();
         mSourceView = source;
         mCornerRadius = cornerRadius;
-        setClipTop(getClipTop());
-        setClipRight(getClipRight());
         setClipBottom(getClipBottom());
-        setOutlineClipBottom(getOutlineClipBottom());
     }
 
     @Override
     public void getOutline(View view, Outline outline) {
         outline.setAlpha(mMinAlpha + mAlpha / (1f - mMinAlpha));
-        outline.setRoundRect(Math.max(mClipRect.left, mOutlineClipRect.left),
-                Math.max(mClipRect.top, mOutlineClipRect.top),
-                mSourceView.getWidth() - Math.max(mClipRect.right, mOutlineClipRect.right),
-                mSourceView.getHeight() - Math.max(mClipRect.bottom, mOutlineClipRect.bottom),
+        outline.setRoundRect(mClipRect.left, mClipRect.top,
+                mSourceView.getWidth() - mClipRect.right,
+                mSourceView.getHeight() - mClipRect.bottom,
                 mCornerRadius);
     }
 
@@ -71,73 +61,6 @@
         }
     }
 
-    /** Animates the top clip. */
-    void animateClipTop(int top, int duration, ValueAnimator.AnimatorUpdateListener updateListener) {
-        if (mClipTopAnimator != null) {
-            mClipTopAnimator.removeAllListeners();
-            mClipTopAnimator.cancel();
-        }
-        mClipTopAnimator = ObjectAnimator.ofInt(this, "clipTop", top);
-        mClipTopAnimator.setDuration(duration);
-        mClipTopAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator);
-        if (updateListener != null) {
-            mClipTopAnimator.addUpdateListener(updateListener);
-        }
-        mClipTopAnimator.start();
-    }
-
-    /** Sets the top clip. */
-    public void setClipTop(int top) {
-        if (top != mClipRect.top) {
-            mClipRect.top = top;
-            mSourceView.invalidateOutline();
-            updateClipBounds();
-        }
-    }
-
-    /** Returns the top clip. */
-    public int getClipTop() {
-        return mClipRect.top;
-    }
-
-    /** Animates the right clip. */
-    void animateClipRight(int right, int duration) {
-        if (mClipRightAnimator != null) {
-            mClipRightAnimator.removeAllListeners();
-            mClipRightAnimator.cancel();
-        }
-        mClipRightAnimator = ObjectAnimator.ofInt(this, "clipRight", right);
-        mClipRightAnimator.setDuration(duration);
-        mClipRightAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator);
-        mClipRightAnimator.start();
-    }
-
-    /** Sets the right clip. */
-    public void setClipRight(int right) {
-        if (right != mClipRect.right) {
-            mClipRect.right = right;
-            mSourceView.invalidateOutline();
-            updateClipBounds();
-        }
-    }
-
-    /** Returns the right clip. */
-    public int getClipRight() {
-        return mClipRect.right;
-    }
-
-    /** Animates the bottom clip. */
-    void animateClipBottom(int bottom, int duration) {
-        if (mClipBottomAnimator != null) {
-            mClipBottomAnimator.removeAllListeners();
-            mClipBottomAnimator.cancel();
-        }
-        mClipBottomAnimator = ObjectAnimator.ofInt(this, "clipBottom", bottom);
-        mClipBottomAnimator.setDuration(duration);
-        mClipBottomAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator);
-        mClipBottomAnimator.start();
-    }
-
     /** Sets the bottom clip. */
     public void setClipBottom(int bottom) {
         if (bottom != mClipRect.bottom) {
@@ -156,19 +79,6 @@
         return mClipRect.bottom;
     }
 
-    /** Sets the outline bottom clip. */
-    public void setOutlineClipBottom(int bottom) {
-        if (bottom != mOutlineClipRect.bottom) {
-            mOutlineClipRect.bottom = bottom;
-            mSourceView.invalidateOutline();
-        }
-    }
-
-    /** Gets the outline bottom clip. */
-    public int getOutlineClipBottom() {
-        return mOutlineClipRect.bottom;
-    }
-
     private void updateClipBounds() {
         mClipBounds.set(mClipRect.left, mClipRect.top,
                 mSourceView.getWidth() - mClipRect.right,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 6c22a3b..9dfebfe 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -18,7 +18,6 @@
 
 import android.app.ActivityOptions;
 import android.app.TaskStackBuilder;
-import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -35,7 +34,6 @@
 import android.widget.FrameLayout;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
-import com.android.systemui.recents.misc.Console;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.RecentsPackageMonitor;
@@ -339,7 +337,7 @@
             View child = getChildAt(i);
             if (child != mSearchBar) {
                 TaskStackView stackView = (TaskStackView) child;
-                stackView.focusNextTask(forward);
+                stackView.focusNextTask(forward, true);
                 break;
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 40134da..e479952 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -24,7 +24,6 @@
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewTreeObserver;
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.FrameLayout;
 import com.android.systemui.R;
@@ -415,7 +414,7 @@
     }
 
     /** Focuses the task at the specified index in the stack */
-    void focusTask(int taskIndex, boolean scrollToNewPosition) {
+    void focusTask(int taskIndex, boolean scrollToNewPosition, final boolean animateFocusedState) {
         // Return early if the task is already focused
         if (taskIndex == mFocusedTaskIndex) return;
 
@@ -427,7 +426,7 @@
             TaskView tv = getChildViewForTask(t);
             Runnable postScrollRunnable = null;
             if (tv != null) {
-                tv.setFocusedTask();
+                tv.setFocusedTask(animateFocusedState);
             } else {
                 postScrollRunnable = new Runnable() {
                     @Override
@@ -435,7 +434,7 @@
                         Task t = mStack.getTasks().get(mFocusedTaskIndex);
                         TaskView tv = getChildViewForTask(t);
                         if (tv != null) {
-                            tv.setFocusedTask();
+                            tv.setFocusedTask(animateFocusedState);
                         }
                     }
                 };
@@ -455,18 +454,50 @@
         }
     }
 
-    /** Focuses the next task in the stack */
-    void focusNextTask(boolean forward) {
+    /**
+     * Ensures that there is a task focused, if nothign is focused, then we will use the task
+     * at the center of the visible stack.
+     */
+    public boolean ensureFocusedTask() {
+        if (mFocusedTaskIndex < 0) {
+            // If there is no task focused, then find the task that is closes to the center
+            // of the screen and use that as the currently focused task
+            int x = mLayoutAlgorithm.mStackVisibleRect.centerX();
+            int y = mLayoutAlgorithm.mStackVisibleRect.centerY();
+            int childCount = getChildCount();
+            for (int i = childCount - 1; i >= 0; i--) {
+                TaskView tv = (TaskView) getChildAt(i);
+                tv.getHitRect(mTmpRect);
+                if (mTmpRect.contains(x, y)) {
+                    mFocusedTaskIndex = mStack.indexOfTask(tv.getTask());
+                    break;
+                }
+            }
+            // If we can't find the center task, then use the front most index
+            if (mFocusedTaskIndex < 0 && childCount > 0) {
+                mFocusedTaskIndex = childCount - 1;
+            }
+        }
+        return mFocusedTaskIndex >= 0;
+    }
+
+    /**
+     * Focuses the next task in the stack.
+     * @param animateFocusedState determines whether to actually draw the highlight along with
+     *                            the change in focus, as well as whether to scroll to fit the
+     *                            task into view.
+     */
+    public void focusNextTask(boolean forward, boolean animateFocusedState) {
         // Find the next index to focus
         int numTasks = mStack.getTaskCount();
         if (numTasks == 0) return;
 
-        int nextFocusIndex = numTasks - 1;
-        if (0 <= mFocusedTaskIndex && mFocusedTaskIndex < numTasks) {
-            nextFocusIndex = Math.max(0, Math.min(numTasks - 1,
-                    mFocusedTaskIndex + (forward ? -1 : 1)));
+        int direction = (forward ? -1 : 1);
+        int newIndex = mFocusedTaskIndex + direction;
+        if (newIndex >= 0 && newIndex <= (numTasks - 1)) {
+            newIndex = Math.max(0, Math.min(numTasks - 1, newIndex));
+            focusTask(newIndex, true, animateFocusedState);
         }
-        focusTask(nextFocusIndex, true);
     }
 
     /** Dismisses the focused task. */
@@ -506,6 +537,11 @@
     }
 
     @Override
+    public boolean onGenericMotionEvent(MotionEvent ev) {
+        return mTouchHandler.onGenericMotionEvent(ev);
+    }
+
+    @Override
     public void computeScroll() {
         mStackScroller.computeScroll();
         // Synchronize the views
@@ -562,22 +598,18 @@
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             TaskView tv = (TaskView) getChildAt(i);
-            if (tv.isFullScreenView()) {
-                tv.measure(widthMeasureSpec, heightMeasureSpec);
+            if (tv.getBackground() != null) {
+                tv.getBackground().getPadding(mTmpRect);
             } else {
-                if (tv.getBackground() != null) {
-                    tv.getBackground().getPadding(mTmpRect);
-                } else {
-                    mTmpRect.setEmpty();
-                }
-                tv.measure(
-                    MeasureSpec.makeMeasureSpec(
-                            mLayoutAlgorithm.mTaskRect.width() + mTmpRect.left + mTmpRect.right,
-                            MeasureSpec.EXACTLY),
-                    MeasureSpec.makeMeasureSpec(
-                            mLayoutAlgorithm.mTaskRect.height() + mTmpRect.top + mTmpRect.bottom +
-                            tv.getMaxFooterHeight(), MeasureSpec.EXACTLY));
+                mTmpRect.setEmpty();
             }
+            tv.measure(
+                MeasureSpec.makeMeasureSpec(
+                        mLayoutAlgorithm.mTaskRect.width() + mTmpRect.left + mTmpRect.right,
+                        MeasureSpec.EXACTLY),
+                MeasureSpec.makeMeasureSpec(
+                        mLayoutAlgorithm.mTaskRect.height() + mTmpRect.top + mTmpRect.bottom,
+                        MeasureSpec.EXACTLY));
         }
 
         setMeasuredDimension(width, height);
@@ -594,20 +626,15 @@
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             TaskView tv = (TaskView) getChildAt(i);
-            if (tv.isFullScreenView()) {
-                tv.layout(left, top, left + tv.getMeasuredWidth(), top + tv.getMeasuredHeight());
+            if (tv.getBackground() != null) {
+                tv.getBackground().getPadding(mTmpRect);
             } else {
-                if (tv.getBackground() != null) {
-                    tv.getBackground().getPadding(mTmpRect);
-                } else {
-                    mTmpRect.setEmpty();
-                }
-                tv.layout(mLayoutAlgorithm.mTaskRect.left - mTmpRect.left,
-                        mLayoutAlgorithm.mTaskRect.top - mTmpRect.top,
-                        mLayoutAlgorithm.mTaskRect.right + mTmpRect.right,
-                        mLayoutAlgorithm.mTaskRect.bottom + mTmpRect.bottom +
-                                tv.getMaxFooterHeight());
+                mTmpRect.setEmpty();
             }
+            tv.layout(mLayoutAlgorithm.mTaskRect.left - mTmpRect.left,
+                    mLayoutAlgorithm.mTaskRect.top - mTmpRect.top,
+                    mLayoutAlgorithm.mTaskRect.right + mTmpRect.right,
+                    mLayoutAlgorithm.mTaskRect.bottom + mTmpRect.bottom);
         }
 
         if (mAwaitingFirstLayout) {
@@ -653,9 +680,9 @@
         // When Alt-Tabbing, we scroll to and focus the previous task
         if (mConfig.launchedWithAltTab) {
             if (mConfig.launchedFromHome) {
-                focusTask(Math.max(0, mStack.getTaskCount() - 1), false);
+                focusTask(Math.max(0, mStack.getTaskCount() - 1), false, true);
             } else {
-                focusTask(Math.max(0, mStack.getTaskCount() - 2), false);
+                focusTask(Math.max(0, mStack.getTaskCount() - 2), false, true);
             }
         }
     }
@@ -811,6 +838,7 @@
             TaskView frontTv = getChildViewForTask(newFrontMostTask);
             if (frontTv != null) {
                 frontTv.onTaskBound(newFrontMostTask);
+                frontTv.fadeInActionButton(false);
             }
         }
 
@@ -923,13 +951,6 @@
         // Rebind the task and request that this task's data be filled into the TaskView
         tv.onTaskBound(task);
 
-        // Mark the launch task as fullscreen
-        if (Constants.DebugFlags.App.EnableScreenshotAppTransition && mAwaitingFirstLayout) {
-            if (task.isLaunchTarget) {
-                tv.setIsFullScreen(true);
-            }
-        }
-
         // Load the task data
         RecentsTaskLoader.getInstance().loadTaskData(task);
 
@@ -1018,14 +1039,18 @@
                 tv.getTask().activityLabel));
         // Remove the task from the view
         mStack.removeTask(task);
-        // If the dismissed task was focused, then we should focus the next task in front
+        // If the dismissed task was focused, then we should focus the new task in the same index
         if (taskWasFocused) {
             ArrayList<Task> tasks = mStack.getTasks();
-            int nextTaskIndex = Math.min(tasks.size() - 1, taskIndex);
+            int nextTaskIndex = Math.min(tasks.size() - 1, taskIndex - 1);
             if (nextTaskIndex >= 0) {
                 Task nextTask = tasks.get(nextTaskIndex);
                 TaskView nextTv = getChildViewForTask(nextTask);
-                nextTv.setFocusedTask();
+                if (nextTv != null) {
+                    // Focus the next task, and only animate the visible state if we are launched
+                    // from Alt-Tab
+                    nextTv.setFocusedTask(mConfig.launchedWithAltTab);
+                }
             }
         }
     }
@@ -1038,11 +1063,6 @@
     }
 
     @Override
-    public void onTaskViewFullScreenTransitionCompleted() {
-        requestSynchronizeStackViewsWithModel();
-    }
-
-    @Override
     public void onTaskViewFocusChanged(TaskView tv, boolean focused) {
         if (focused) {
             mFocusedTaskIndex = mStack.indexOfTask(tv.getTask());
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
index 31fc701..c549d2b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
@@ -199,18 +199,14 @@
         return transformOut;
     }
 
-    /**
-     * Returns the untransformed task view size.
-     */
+    /** Returns the untransformed task view size. */
     public Rect getUntransformedTaskViewSize() {
         Rect tvSize = new Rect(mTaskRect);
         tvSize.offsetTo(0, 0);
         return tvSize;
     }
 
-    /**
-     * Returns the scroll to such task top = 1f;
-     */
+    /** Returns the scroll to such task top = 1f; */
     float getStackScrollForTask(Task t) {
         return mTaskProgressMap.get(t.key);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
index 5852b88..c9113fe 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
@@ -38,6 +38,7 @@
 
     OverScroller mScroller;
     ObjectAnimator mScrollAnimator;
+    float mFinalAnimatedScroll;
 
     public TaskStackViewScroller(Context context, RecentsConfiguration config, TaskStackViewLayoutAlgorithm layoutAlgorithm) {
         mConfig = config;
@@ -128,10 +129,15 @@
 
     /** Animates the stack scroll */
     void animateScroll(float curScroll, float newScroll, final Runnable postRunnable) {
-        // Abort any current animations
+        // Finish any current scrolling animations
+        if (mScrollAnimator != null && mScrollAnimator.isRunning()) {
+            setStackScroll(mFinalAnimatedScroll);
+            mScroller.startScroll(0, progressToScrollRange(mFinalAnimatedScroll), 0, 0, 0);
+        }
         stopScroller();
         stopBoundScrollAnimation();
 
+        mFinalAnimatedScroll = newScroll;
         mScrollAnimator = ObjectAnimator.ofFloat(this, "stackScroll", curScroll, newScroll);
         mScrollAnimator.setDuration(mConfig.taskStackScrollDuration);
         mScrollAnimator.setInterpolator(mConfig.linearOutSlowInInterpolator);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index 8f9b4c2..2b173a9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -17,6 +17,7 @@
 package com.android.systemui.recents.views;
 
 import android.content.Context;
+import android.view.InputDevice;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
@@ -189,7 +190,6 @@
 
     /** Handles touch events once we have intercepted them */
     public boolean onTouchEvent(MotionEvent ev) {
-
         // Short circuit if we have no children
         boolean hasChildren = (mSv.getChildCount() > 0);
         if (!hasChildren) {
@@ -336,6 +336,30 @@
         return true;
     }
 
+    /** Handles generic motion events */
+    public boolean onGenericMotionEvent(MotionEvent ev) {
+        if ((ev.getSource() & InputDevice.SOURCE_CLASS_POINTER) ==
+                InputDevice.SOURCE_CLASS_POINTER) {
+            int action = ev.getAction();
+            switch (action & MotionEvent.ACTION_MASK) {
+                case MotionEvent.ACTION_SCROLL:
+                    // Find the front most task and scroll the next task to the front
+                    float vScroll = ev.getAxisValue(MotionEvent.AXIS_VSCROLL);
+                    if (vScroll > 0) {
+                        if (mSv.ensureFocusedTask()) {
+                            mSv.focusNextTask(true, false);
+                        }
+                    } else {
+                        if (mSv.ensureFocusedTask()) {
+                            mSv.focusNextTask(false, false);
+                        }
+                    }
+                    return true;
+            }
+        }
+        return false;
+    }
+
     /**** SwipeHelper Implementation ****/
 
     @Override
@@ -355,8 +379,6 @@
         tv.setClipViewInStack(false);
         // Disallow touch events from this task view
         tv.setTouchEnabled(false);
-        // Hide the footer
-        tv.animateFooterVisibility(false, mSv.mConfig.taskViewLockToAppShortAnimDuration);
         // Disallow parents from intercepting touch events
         final ViewParent parent = mSv.getParent();
         if (parent != null) {
@@ -387,8 +409,6 @@
         tv.setClipViewInStack(true);
         // Re-enable touch events from this task view
         tv.setTouchEnabled(true);
-        // Restore the footer
-        tv.animateFooterVisibility(true, mSv.mConfig.taskViewLockToAppShortAnimDuration);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 2658176..dfb30f3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -21,11 +21,10 @@
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.graphics.*;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewOutlineProvider;
+import android.view.ViewPropertyAnimator;
 import android.view.animation.AccelerateInterpolator;
 import android.widget.FrameLayout;
 import com.android.systemui.R;
@@ -34,10 +33,11 @@
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.model.RecentsTaskLoader;
 import com.android.systemui.recents.model.Task;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
 
 /* A task view */
 public class TaskView extends FrameLayout implements Task.TaskCallbacks,
-        TaskViewFooter.TaskFooterViewCallbacks, View.OnClickListener, View.OnLongClickListener {
+        View.OnClickListener, View.OnLongClickListener {
 
     /** The TaskView callbacks */
     interface TaskViewCallbacks {
@@ -46,7 +46,6 @@
         public void onTaskViewClicked(TaskView tv, Task task, boolean lockToTask);
         public void onTaskViewDismissed(TaskView tv);
         public void onTaskViewClipStateChanged(TaskView tv);
-        public void onTaskViewFullScreenTransitionCompleted();
         public void onTaskViewFocusChanged(TaskView tv, boolean focused);
     }
 
@@ -64,7 +63,6 @@
     boolean mTaskDataLoaded;
     boolean mIsFocused;
     boolean mFocusAnimationsEnabled;
-    boolean mIsFullScreenView;
     boolean mClipViewInStack;
     AnimateableViewBounds mViewBounds;
     Paint mLayerPaint = new Paint();
@@ -72,7 +70,6 @@
     View mContent;
     TaskViewThumbnail mThumbnailView;
     TaskViewHeader mHeaderView;
-    TaskViewFooter mFooterView;
     View mActionButtonView;
     TaskViewCallbacks mCb;
 
@@ -142,9 +139,6 @@
                 outline.setOval(0, 0, mActionButtonView.getWidth(), mActionButtonView.getHeight());
             }
         });
-        if (mFooterView != null) {
-            mFooterView.setCallbacks(this);
-        }
     }
 
     @Override
@@ -159,29 +153,16 @@
         mContent.measure(MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY));
 
-        // Measure the bar view, thumbnail, and footer
+        // Measure the bar view, and action button
         mHeaderView.measure(MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(mConfig.taskBarHeight, MeasureSpec.EXACTLY));
-        if (mFooterView != null) {
-            mFooterView.measure(
-                    MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY),
-                    MeasureSpec.makeMeasureSpec(mConfig.taskViewLockToAppButtonHeight,
-                            MeasureSpec.EXACTLY));
-        }
         mActionButtonView.measure(
                 MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.AT_MOST),
                 MeasureSpec.makeMeasureSpec(heightWithoutPadding, MeasureSpec.AT_MOST));
-        if (mIsFullScreenView) {
-            // Measure the thumbnail height to be the full dimensions
-            mThumbnailView.measure(
-                    MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY),
-                    MeasureSpec.makeMeasureSpec(heightWithoutPadding, MeasureSpec.EXACTLY));
-        } else {
-            // Measure the thumbnail to be square
-            mThumbnailView.measure(
-                    MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY),
-                    MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY));
-        }
+        // Measure the thumbnail to be square
+        mThumbnailView.measure(
+                MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY),
+                MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY));
         setMeasuredDimension(width, height);
         invalidateOutline();
     }
@@ -193,16 +174,6 @@
 
     void updateViewPropertiesToTaskTransform(TaskViewTransform toTransform, int duration,
                                              ValueAnimator.AnimatorUpdateListener updateCallback) {
-        // If we are a full screen view, then only update the Z to keep it in order
-        // XXX: Also update/animate the dim as well
-        if (mIsFullScreenView) {
-            if (!mConfig.fakeShadows &&
-                    toTransform.hasTranslationZChangedFrom(getTranslationZ())) {
-                setTranslationZ(toTransform.translationZ);
-            }
-            return;
-        }
-
         // Apply the transform
         toTransform.applyToTaskView(this, duration, mConfig.fastOutSlowInInterpolator, false,
                 !mConfig.fakeShadows, updateCallback);
@@ -253,22 +224,12 @@
     void prepareEnterRecentsAnimation(boolean isTaskViewLaunchTargetTask,
                                              boolean occludesLaunchTarget, int offscreenY) {
         int initialDim = getDim();
-        if (mConfig.launchedFromAppWithScreenshot) {
+        if (mConfig.launchedFromAppWithThumbnail) {
             if (isTaskViewLaunchTargetTask) {
-                // Hide the footer during the transition in, and animate it out afterwards?
-                if (mFooterView != null) {
-                    mFooterView.animateFooterVisibility(false, 0);
-                }
-            } else {
-                // Don't do anything for the side views when animating in
-            }
-
-        } else if (mConfig.launchedFromAppWithThumbnail) {
-            if (isTaskViewLaunchTargetTask) {
-                // Hide the action button if it exists
-                mActionButtonView.setAlpha(0f);
                 // Set the dim to 0 so we can animate it in
                 initialDim = 0;
+                // Hide the action button
+                mActionButtonView.setAlpha(0f);
             } else if (occludesLaunchTarget) {
                 // Move the task view off screen (below) so we can animate it in
                 setTranslationY(offscreenY);
@@ -292,74 +253,7 @@
         final TaskViewTransform transform = ctx.currentTaskTransform;
         int startDelay = 0;
 
-        if (mConfig.launchedFromAppWithScreenshot) {
-            if (mTask.isLaunchTarget) {
-                Rect taskRect = ctx.currentTaskRect;
-                int duration = mConfig.taskViewEnterFromHomeDuration * 10;
-                int windowInsetTop = mConfig.systemInsets.top; // XXX: Should be for the window
-                float taskScale = ((float) taskRect.width() / getMeasuredWidth()) * transform.scale;
-                float scaledYOffset = ((1f - taskScale) * getMeasuredHeight()) / 2;
-                float scaledWindowInsetTop = (int) (taskScale * windowInsetTop);
-                float scaledTranslationY = taskRect.top + transform.translationY -
-                        (scaledWindowInsetTop + scaledYOffset);
-                startDelay = mConfig.taskViewEnterFromHomeStaggerDelay;
-
-                // Animate the top clip
-                mViewBounds.animateClipTop(windowInsetTop, duration,
-                        new ValueAnimator.AnimatorUpdateListener() {
-                    @Override
-                    public void onAnimationUpdate(ValueAnimator animation) {
-                        int y = (Integer) animation.getAnimatedValue();
-                        mHeaderView.setTranslationY(y);
-                    }
-                });
-                // Animate the bottom or right clip
-                int size = Math.round((taskRect.width() / taskScale));
-                if (mConfig.hasHorizontalLayout()) {
-                    mViewBounds.animateClipRight(getMeasuredWidth() - size, duration);
-                } else {
-                    mViewBounds.animateClipBottom(getMeasuredHeight() - (windowInsetTop + size), duration);
-                }
-                // Animate the task bar of the first task view
-                animate()
-                        .scaleX(taskScale)
-                        .scaleY(taskScale)
-                        .translationY(scaledTranslationY)
-                        .setDuration(duration)
-                        .withEndAction(new Runnable() {
-                            @Override
-                            public void run() {
-                                setIsFullScreen(false);
-                                requestLayout();
-
-                                // Reset the clip
-                                mViewBounds.setClipTop(0);
-                                mViewBounds.setClipBottom(0);
-                                mViewBounds.setClipRight(0);
-                                // Reset the bar translation
-                                mHeaderView.setTranslationY(0);
-                                // Animate the footer into view (if it is the front most task)
-                                animateFooterVisibility(true, mConfig.taskBarEnterAnimDuration);
-
-                                // Unbind the thumbnail from the screenshot
-                                RecentsTaskLoader.getInstance().loadTaskData(mTask);
-                                // Recycle the full screen screenshot
-                                AlternateRecentsComponent.consumeLastScreenshot();
-
-                                mCb.onTaskViewFullScreenTransitionCompleted();
-
-                                // Decrement the post animation trigger
-                                ctx.postAnimationTrigger.decrement();
-                            }
-                        })
-                        .start();
-            } else {
-                // Animate the footer into view
-                animateFooterVisibility(true, 0);
-            }
-            ctx.postAnimationTrigger.increment();
-
-        } else if (mConfig.launchedFromAppWithThumbnail) {
+        if (mConfig.launchedFromAppWithThumbnail) {
             if (mTask.isLaunchTarget) {
                 // Animate the dim/overlay
                 if (Constants.DebugFlags.App.EnableThumbnailAlphaOnFrontmost) {
@@ -381,16 +275,8 @@
                 }
                 ctx.postAnimationTrigger.increment();
 
-                // Animate the footer into view
-                animateFooterVisibility(true, mConfig.taskBarEnterAnimDuration);
-
                 // Animate the action button in
-                mActionButtonView.animate().alpha(1f)
-                        .setStartDelay(mConfig.taskBarEnterAnimDelay)
-                        .setDuration(mConfig.taskBarEnterAnimDuration)
-                        .setInterpolator(mConfig.fastOutLinearInInterpolator)
-                        .withLayer()
-                        .start();
+                fadeInActionButton(true);
             } else {
                 // Animate the task up if it was occluding the launch target
                 if (ctx.currentTaskOccludesLaunchTarget) {
@@ -442,14 +328,7 @@
                     })
                     .start();
             ctx.postAnimationTrigger.increment();
-
-            // Animate the footer into view
-            animateFooterVisibility(true, mConfig.taskViewEnterFromHomeDuration);
             startDelay = delay;
-
-        } else {
-            // Animate the footer into view
-            animateFooterVisibility(true, 0);
         }
 
         // Enable the focus animations from this point onwards so that they aren't affected by the
@@ -462,6 +341,21 @@
         }, (startDelay / 2));
     }
 
+    public void fadeInActionButton(boolean withDelay) {
+        // Hide the action button
+        mActionButtonView.setAlpha(0f);
+
+        // Animate the action button in
+        ViewPropertyAnimator animator = mActionButtonView.animate().alpha(1f)
+                .setDuration(mConfig.taskBarEnterAnimDuration)
+                .setInterpolator(PhoneStatusBar.ALPHA_IN)
+                .withLayer();
+        if (withDelay) {
+            animator.setStartDelay(mConfig.taskBarEnterAnimDelay);
+        }
+        animator.start();
+    }
+
     /** Animates this task view as it leaves recents by pressing home. */
     void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) {
         animate()
@@ -569,23 +463,6 @@
                 mCb.onTaskViewDismissed(tv);
             }
         });
-        // Hide the footer
-        animateFooterVisibility(false, mConfig.taskViewRemoveAnimDuration);
-    }
-
-    /** Sets whether this task view is full screen or not. */
-    void setIsFullScreen(boolean isFullscreen) {
-        mIsFullScreenView = isFullscreen;
-        mHeaderView.setIsFullscreen(isFullscreen);
-        if (isFullscreen) {
-            // If we are full screen, then disable the bottom outline clip for the footer
-            mViewBounds.setOutlineClipBottom(0);
-        }
-    }
-
-    /** Returns whether this task view should currently be drawn as a full screen view. */
-    boolean isFullScreenView() {
-        return mIsFullScreenView;
     }
 
     /**
@@ -593,7 +470,7 @@
      * view.
      */
     boolean shouldClipViewInStack() {
-        return mClipViewInStack && !mIsFullScreenView && (getVisibility() == View.VISIBLE);
+        return mClipViewInStack && (getVisibility() == View.VISIBLE);
     }
 
     /** Sets whether this view should be clipped, or clipped against. */
@@ -604,27 +481,6 @@
         }
     }
 
-    /** Gets the max footer height. */
-    public int getMaxFooterHeight() {
-        if (mFooterView != null) {
-            return mFooterView.mMaxFooterHeight;
-        } else {
-            return 0;
-        }
-    }
-
-    /** Animates the footer into and out of view. */
-    void animateFooterVisibility(boolean visible, int duration) {
-        // Hide the footer if we are a full screen view
-        if (mIsFullScreenView) return;
-        // Hide the footer if the current task can not be locked to
-        if (!mTask.lockToTaskEnabled || !mTask.lockToThisTask) return;
-        // Otherwise, animate the visibility
-        if (mFooterView != null) {
-            mFooterView.animateFooterVisibility(visible, duration);
-        }
-    }
-
     /** Sets the current task progress. */
     public void setTaskProgress(float p) {
         mTaskProgress = p;
@@ -706,11 +562,11 @@
      * if the view is not currently visible, or we are in touch state (where we still want to keep
      * track of focus).
      */
-    public void setFocusedTask() {
+    public void setFocusedTask(boolean animateFocusedState) {
         mIsFocused = true;
         if (mFocusAnimationsEnabled) {
             // Focus the header bar
-            mHeaderView.onTaskViewFocusChanged(true);
+            mHeaderView.onTaskViewFocusChanged(true, animateFocusedState);
         }
         // Update the thumbnail alpha with the focus
         mThumbnailView.onFocusChanged(true);
@@ -732,7 +588,7 @@
         mIsFocused = false;
         if (mFocusAnimationsEnabled) {
             // Un-focus the header bar
-            mHeaderView.onTaskViewFocusChanged(false);
+            mHeaderView.onTaskViewFocusChanged(false, true);
         }
 
         // Update the thumbnail alpha with the focus
@@ -766,7 +622,7 @@
         mFocusAnimationsEnabled = true;
         if (mIsFocused && !wasFocusAnimationsEnabled) {
             // Re-notify the header if we were focused and animations were not previously enabled
-            mHeaderView.onTaskViewFocusChanged(true);
+            mHeaderView.onTaskViewFocusChanged(true, true);
         }
     }
 
@@ -776,15 +632,12 @@
     public void onTaskBound(Task t) {
         mTask = t;
         mTask.setCallbacks(this);
-        if (getMeasuredWidth() == 0) {
-            // If we haven't yet measured, we should just set the footer height with any animation
-            animateFooterVisibility(t.lockToThisTask, 0);
-        } else {
-            animateFooterVisibility(t.lockToThisTask, mConfig.taskViewLockToAppLongAnimDuration);
-        }
-        // Hide the action button if lock to app is disabled
-        if (!t.lockToTaskEnabled && mActionButtonView.getVisibility() != View.GONE) {
-            mActionButtonView.setVisibility(View.GONE);
+
+        // Hide the action button if lock to app is disabled for this view
+        int lockButtonVisibility = (!t.lockToTaskEnabled || !t.lockToThisTask) ? GONE : VISIBLE;
+        if (mActionButtonView.getVisibility() != lockButtonVisibility) {
+            mActionButtonView.setVisibility(lockButtonVisibility);
+            requestLayout();
         }
     }
 
@@ -792,18 +645,11 @@
     public void onTaskDataLoaded() {
         if (mThumbnailView != null && mHeaderView != null) {
             // Bind each of the views to the new task data
-            if (mIsFullScreenView) {
-                mThumbnailView.bindToScreenshot(AlternateRecentsComponent.getLastScreenshot());
-            } else {
-                mThumbnailView.rebindToTask(mTask);
-            }
+            mThumbnailView.rebindToTask(mTask);
             mHeaderView.rebindToTask(mTask);
             // Rebind any listeners
             mHeaderView.mApplicationIcon.setOnClickListener(this);
             mHeaderView.mDismissButton.setOnClickListener(this);
-            if (mFooterView != null) {
-                mFooterView.setOnClickListener(this);
-            }
             mActionButtonView.setOnClickListener(this);
             if (Constants.DebugFlags.App.EnableDevAppInfoOnLongPress) {
                 if (mConfig.developerOptionsEnabled) {
@@ -824,9 +670,6 @@
             // Unbind any listeners
             mHeaderView.mApplicationIcon.setOnClickListener(null);
             mHeaderView.mDismissButton.setOnClickListener(null);
-            if (mFooterView != null) {
-                mFooterView.setOnClickListener(null);
-            }
             mActionButtonView.setOnClickListener(null);
             if (Constants.DebugFlags.App.EnableDevAppInfoOnLongPress) {
                 mHeaderView.mApplicationIcon.setOnLongClickListener(null);
@@ -840,19 +683,6 @@
         setOnClickListener(enabled ? this : null);
     }
 
-    /**** TaskViewFooter.TaskFooterViewCallbacks ****/
-
-    @Override
-    public void onTaskFooterHeightChanged(int height, int maxHeight) {
-        if (mIsFullScreenView) {
-            // Disable the bottom outline clip when fullscreen
-            mViewBounds.setOutlineClipBottom(0);
-        } else {
-            // Update the bottom clip in our outline provider
-            mViewBounds.setOutlineClipBottom(maxHeight - height);
-        }
-    }
-
     /**** View.OnClickListener Implementation ****/
 
     @Override
@@ -876,8 +706,7 @@
                 // Reset the translation of the action button before we animate it out
                 mActionButtonView.setTranslationZ(0f);
             }
-            mCb.onTaskViewClicked(tv, tv.getTask(),
-                    (v == mFooterView || v == mActionButtonView));
+            mCb.onTaskViewClicked(tv, tv.getTask(), (v == mActionButtonView));
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewFooter.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewFooter.java
deleted file mode 100644
index 324169e..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewFooter.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents.views;
-
-import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.util.AttributeSet;
-import android.widget.FrameLayout;
-import com.android.systemui.recents.RecentsConfiguration;
-
-
-/** The task footer view */
-public class TaskViewFooter extends FrameLayout {
-
-    interface TaskFooterViewCallbacks {
-        public void onTaskFooterHeightChanged(int height, int maxHeight);
-    }
-
-    RecentsConfiguration mConfig;
-
-    TaskFooterViewCallbacks mCb;
-    int mFooterHeight;
-    int mMaxFooterHeight;
-    ObjectAnimator mFooterAnimator;
-
-    public TaskViewFooter(Context context) {
-        this(context, null);
-    }
-
-    public TaskViewFooter(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public TaskViewFooter(Context context, AttributeSet attrs, int defStyleAttr) {
-        this(context, attrs, defStyleAttr, 0);
-    }
-
-    public TaskViewFooter(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-        mConfig = RecentsConfiguration.getInstance();
-        mMaxFooterHeight = mConfig.taskViewLockToAppButtonHeight;
-        setFooterHeight(getFooterHeight());
-    }
-
-    /** Sets the callbacks for when the footer height changes. */
-    void setCallbacks(TaskFooterViewCallbacks cb) {
-        mCb = cb;
-        mCb.onTaskFooterHeightChanged(mFooterHeight, mMaxFooterHeight);
-    }
-
-    /** Sets the footer height. */
-    public void setFooterHeight(int footerHeight) {
-        if (footerHeight != mFooterHeight) {
-            mFooterHeight = footerHeight;
-            mCb.onTaskFooterHeightChanged(footerHeight, mMaxFooterHeight);
-        }
-    }
-
-    /** Gets the footer height. */
-    public int getFooterHeight() {
-        return mFooterHeight;
-    }
-
-    /** Animates the footer into and out of view. */
-    void animateFooterVisibility(final boolean visible, int duration) {
-        // Return early if there is no footer
-        if (mMaxFooterHeight <= 0) return;
-
-        // Cancel the previous animation
-        if (mFooterAnimator != null) {
-            mFooterAnimator.removeAllListeners();
-            mFooterAnimator.cancel();
-        }
-        int finalHeight = visible ? mMaxFooterHeight : 0;
-        if (duration > 0) {
-            mFooterAnimator = ObjectAnimator.ofInt(this, "footerHeight", finalHeight);
-            mFooterAnimator.setDuration(duration);
-            mFooterAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator);
-            mFooterAnimator.start();
-        } else {
-            setFooterHeight(finalHeight);
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index 396d441..6554f82 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -66,10 +66,8 @@
     Drawable mLightDismissDrawable;
     Drawable mDarkDismissDrawable;
     AnimatorSet mFocusAnimator;
-    ValueAnimator backgroundColorAnimator;
     PorterDuffColorFilter mDimFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_ATOP);
 
-    boolean mIsFullscreen;
     boolean mCurrentPrimaryColorIsDark;
     int mCurrentPrimaryColor;
 
@@ -159,21 +157,14 @@
 
     @Override
     protected void onDraw(Canvas canvas) {
-        if (!mIsFullscreen) {
-            // Draw the highlight at the top edge (but put the bottom edge just out of view)
-            float offset = (float) Math.ceil(mConfig.taskViewHighlightPx / 2f);
-            float radius = mConfig.taskViewRoundedCornerRadiusPx;
-            int count = canvas.save(Canvas.CLIP_SAVE_FLAG);
-            canvas.clipRect(0, 0, getMeasuredWidth(), getMeasuredHeight());
-            canvas.drawRoundRect(-offset, 0f, (float) getMeasuredWidth() + offset,
-                    getMeasuredHeight() + radius, radius, radius, sHighlightPaint);
-            canvas.restoreToCount(count);
-        }
-    }
-
-    /** Sets whether the current task is full screen or not. */
-    void setIsFullscreen(boolean isFullscreen) {
-        mIsFullscreen = isFullscreen;
+        // Draw the highlight at the top edge (but put the bottom edge just out of view)
+        float offset = (float) Math.ceil(mConfig.taskViewHighlightPx / 2f);
+        float radius = mConfig.taskViewRoundedCornerRadiusPx;
+        int count = canvas.save(Canvas.CLIP_SAVE_FLAG);
+        canvas.clipRect(0, 0, getMeasuredWidth(), getMeasuredHeight());
+        canvas.drawRoundRect(-offset, 0f, (float) getMeasuredWidth() + offset,
+                getMeasuredHeight() + radius, radius, radius, sHighlightPaint);
+        canvas.restoreToCount(count);
     }
 
     @Override
@@ -268,13 +259,17 @@
     }
 
     /** Notifies the associated TaskView has been focused. */
-    void onTaskViewFocusChanged(boolean focused) {
+    void onTaskViewFocusChanged(boolean focused, boolean animateFocusedState) {
+        // If we are not animating the visible state, just return
+        if (!animateFocusedState) return;
+
         boolean isRunning = false;
         if (mFocusAnimator != null) {
             isRunning = mFocusAnimator.isRunning();
             mFocusAnimator.removeAllListeners();
             mFocusAnimator.cancel();
         }
+
         if (focused) {
             int secondaryColor = getSecondaryColor(mCurrentPrimaryColor, mCurrentPrimaryColorIsDark);
             int[][] states = new int[][] {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 650a14f..40c9134 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -36,6 +36,8 @@
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
 import com.android.systemui.statusbar.policy.UserInfoController;
 
+import java.text.NumberFormat;
+
 /**
  * The header group on Keyguard.
  */
@@ -150,7 +152,8 @@
 
     @Override
     public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
-        mBatteryLevel.setText(getResources().getString(R.string.battery_level_template, level));
+        String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0);
+        mBatteryLevel.setText(percentage);
         boolean changed = mBatteryCharging != charging;
         mBatteryCharging = charging;
         if (changed) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 9e3f0f6..e5c9bdd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -40,6 +40,7 @@
 import android.app.PendingIntent;
 import android.app.StatusBarManager;
 import android.content.BroadcastReceiver;
+import android.content.ComponentCallbacks2;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -95,6 +96,7 @@
 import android.view.ViewStub;
 import android.view.ViewTreeObserver;
 import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.animation.AccelerateDecelerateInterpolator;
@@ -173,6 +175,7 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 
 public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
         DragDownHelper.DragDownCallback, ActivityStarter {
@@ -2413,6 +2416,12 @@
         setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
         showBouncer();
         disable(mDisabledUnmodified, true /* animate */);
+
+        // Trimming will happen later if Keyguard is showing - doing it here might cause a jank in
+        // the bouncer appear animation.
+        if (!mStatusBarKeyguardViewManager.isShowing()) {
+            WindowManagerGlobal.getInstance().trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
+        }
     }
 
     public boolean interceptTouchEvent(MotionEvent event) {
@@ -2955,6 +2964,11 @@
         if (mSecurityController != null) {
             mSecurityController.dump(fd, pw, args);
         }
+        pw.println("SharedPreferences:");
+        for (Map.Entry<String, ?> entry : mContext.getSharedPreferences(mContext.getPackageName(),
+                Context.MODE_PRIVATE).getAll().entrySet()) {
+            pw.print("  "); pw.print(entry.getKey()); pw.print("="); pw.println(entry.getValue());
+        }
     }
 
     private String hunStateToString(Entry entry) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
index b0f3ea1..ca853a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -48,6 +48,8 @@
 import com.android.systemui.statusbar.policy.NextAlarmController;
 import com.android.systemui.statusbar.policy.UserInfoController;
 
+import java.text.NumberFormat;
+
 /**
  * The view to manage the header area in the expanded status bar.
  */
@@ -395,7 +397,8 @@
 
     @Override
     public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
-        mBatteryLevel.setText(getResources().getString(R.string.battery_level_template, level));
+        String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0);
+        mBatteryLevel.setText(percentage);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 55c861a..65d231e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.content.ComponentCallbacks2;
 import android.content.Context;
 import android.os.Bundle;
 import android.os.RemoteException;
@@ -24,6 +25,7 @@
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.WindowManagerGlobal;
 
 import com.android.internal.policy.IKeyguardShowCallback;
 import com.android.internal.widget.LockPatternUtils;
@@ -268,6 +270,8 @@
                     public void run() {
                         mStatusBarWindowManager.setKeyguardFadingAway(false);
                         mPhoneStatusBar.finishKeyguardFadingAway();
+                        WindowManagerGlobal.getInstance().trimMemory(
+                                ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
                     }
                 });
             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java
index dcda2c7..b89aa8f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java
@@ -133,6 +133,7 @@
         if (!mAnimating) {
             mAnimating = true;
             updateState(true);
+            invalidateSelf();
         }
     }
 
@@ -146,18 +147,21 @@
             mState = STATE_UNSET;
             mCurAlpha = 0;
             mCurInnerRadius = mInnerRadiusEnter;
+            invalidateSelf();
         }
     }
 
     public void setTrustManaged(boolean trustManaged) {
         if (trustManaged == mTrustManaged && mState != STATE_UNSET) return;
         mTrustManaged = trustManaged;
-        if (mAnimating) {
-            updateState(true);
-        }
+        updateState(true);
     }
 
-    private void updateState(boolean animate) {
+    private void updateState(boolean allowTransientState) {
+        if (!mAnimating) {
+            return;
+        }
+
         int nextState = mState;
         if (mState == STATE_UNSET) {
             nextState = mTrustManaged ? STATE_ENTERING : STATE_GONE;
@@ -170,7 +174,7 @@
         } else if (mState == STATE_EXITING) {
             if (mTrustManaged) nextState = STATE_ENTERING;
         }
-        if (!animate) {
+        if (!allowTransientState) {
             if (nextState == STATE_ENTERING) nextState = STATE_VISIBLE;
             if (nextState == STATE_EXITING) nextState = STATE_GONE;
         }
@@ -200,9 +204,8 @@
             mState = nextState;
             if (mCurAnimator != null) {
                 mCurAnimator.start();
-            } else {
-                invalidateSelf();
             }
+            invalidateSelf();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java
deleted file mode 100644
index f339401..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.policy;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-
-public class Prefs {
-    private static final String SHARED_PREFS_NAME = "status_bar";
-
-    public static SharedPreferences read(Context context) {
-        return context.getSharedPreferences(Prefs.SHARED_PREFS_NAME, Context.MODE_PRIVATE);
-    }
-
-    public static SharedPreferences.Editor edit(Context context) {
-        return context.getSharedPreferences(Prefs.SHARED_PREFS_NAME, Context.MODE_PRIVATE).edit();
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index ea431ae..69be377 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -430,7 +430,8 @@
         }
         tag.condition = condition;
         tag.rb.setEnabled(enabled);
-        if (sameConditionId(mSessionExitCondition, tag.condition)) {
+        if (mSessionExitCondition != null
+                && sameConditionId(mSessionExitCondition, tag.condition)) {
             tag.rb.setChecked(true);
         }
         tag.rb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@@ -690,7 +691,7 @@
         }
 
         private SharedPreferences prefs() {
-            return mContext.getSharedPreferences(ZenModePanel.class.getSimpleName(), 0);
+            return mContext.getSharedPreferences(mContext.getPackageName(), 0);
         }
 
         private void updateMinuteIndex() {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 9c81f0a..1ed61fd 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -3342,9 +3342,9 @@
         final boolean noActionBar = !hasFeature(FEATURE_ACTION_BAR) || hasFeature(FEATURE_NO_TITLE);
 
         if (targetPreHoneycomb || (targetPreIcs && targetHcNeedsOptions && noActionBar)) {
-            addFlags(WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY);
+            setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE);
         } else {
-            clearFlags(WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY);
+            setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_FALSE);
         }
 
         // Non-floating windows on high end devices must put up decor beneath the system bars and
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 1882d56..e184577 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -1484,7 +1484,6 @@
             case TYPE_PHONE:
             case TYPE_POINTER:
             case TYPE_PRIORITY_PHONE:
-            case TYPE_RECENTS_OVERLAY:
             case TYPE_SEARCH_BAR:
             case TYPE_STATUS_BAR:
             case TYPE_STATUS_BAR_PANEL:
@@ -1603,7 +1602,6 @@
         case TYPE_VOICE_INTERACTION:
             // voice interaction layer is almost immediately above apps.
             return 5;
-        case TYPE_RECENTS_OVERLAY:
         case TYPE_SYSTEM_DIALOG:
             return 6;
         case TYPE_TOAST:
@@ -2231,15 +2229,6 @@
                     return -1;
                 }
 
-                // If an incoming call is ringing, HOME is totally disabled.
-                // (The user is already on the InCallUI at this point,
-                // and his ONLY options are to answer or reject the call.)
-                TelecomManager telecomManager = getTelecommService();
-                if (telecomManager != null && telecomManager.isRinging()) {
-                    Log.i(TAG, "Ignoring HOME; there's a ringing incoming call.");
-                    return -1;
-                }
-
                 // Delay handling home if a double-tap is possible.
                 if (mDoubleTapOnHomeBehavior != DOUBLE_TAP_HOME_NOTHING) {
                     mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable); // just in case
@@ -3215,10 +3204,15 @@
             // whether it is taking care of insetting its content.  If not,
             // we need to use the parent's content frame so that the entire
             // window is positioned within that content.  Otherwise we can use
-            // the display frame and let the attached window take care of
+            // the overscan frame and let the attached window take care of
             // positioning its content appropriately.
             if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
-                cf.set(attached.getOverscanFrameLw());
+                // Set the content frame of the attached window to the parent's decor frame
+                // (same as content frame when IME isn't present) if specifically requested by
+                // setting {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR} flag.
+                // Otherwise, use the overscan frame.
+                cf.set((fl & FLAG_LAYOUT_ATTACHED_IN_DECOR) != 0
+                        ? attached.getContentFrameLw() : attached.getOverscanFrameLw());
             } else {
                 // If the window is resizing, then we want to base the content
                 // frame on our attached content frame to resize...  however,
diff --git a/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java b/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java
deleted file mode 100644
index bc55ed1..0000000
--- a/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import android.app.ActivityManager;
-import android.app.Dialog;
-import android.app.StatusBarManager;
-import android.content.ActivityNotFoundException;
-import android.content.BroadcastReceiver;
-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.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.os.Handler;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.SoundEffectConstants;
-import android.view.View;
-import android.view.Window;
-import android.view.WindowManager;
-import android.view.View.OnClickListener;
-import android.widget.TextView;
-
-import java.util.List;
-
-public class RecentApplicationsDialog extends Dialog implements OnClickListener {
-    // Elements for debugging support
-//  private static final String LOG_TAG = "RecentApplicationsDialog";
-    private static final boolean DBG_FORCE_EMPTY_LIST = false;
-
-    static private StatusBarManager sStatusBar;
-
-    private static final int NUM_BUTTONS = 8;
-    private static final int MAX_RECENT_TASKS = NUM_BUTTONS * 2;    // allow for some discards
-
-    final TextView[] mIcons = new TextView[NUM_BUTTONS];
-    View mNoAppsText;
-    IntentFilter mBroadcastIntentFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
-
-    class RecentTag {
-        ActivityManager.RecentTaskInfo info;
-        Intent intent;
-    }
-
-    Handler mHandler = new Handler();
-    Runnable mCleanup = new Runnable() {
-        public void run() {
-            // dump extra memory we're hanging on to
-            for (TextView icon: mIcons) {
-                icon.setCompoundDrawables(null, null, null, null);
-                icon.setTag(null);
-            }
-        }
-    };
-
-    public RecentApplicationsDialog(Context context) {
-        super(context, com.android.internal.R.style.Theme_Dialog_RecentApplications);
-
-    }
-
-    /**
-     * We create the recent applications dialog just once, and it stays around (hidden)
-     * until activated by the user.
-     *
-     * @see PhoneWindowManager#showRecentAppsDialog
-     */
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        Context context = getContext();
-
-        if (sStatusBar == null) {
-            sStatusBar = (StatusBarManager)context.getSystemService(Context.STATUS_BAR_SERVICE);
-        }
-
-        Window window = getWindow();
-        window.requestFeature(Window.FEATURE_NO_TITLE);
-        window.setType(WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY);
-        window.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
-                WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
-        window.setTitle("Recents");
-
-        setContentView(com.android.internal.R.layout.recent_apps_dialog);
-
-        final WindowManager.LayoutParams params = window.getAttributes();
-        params.width = WindowManager.LayoutParams.MATCH_PARENT;
-        params.height = WindowManager.LayoutParams.MATCH_PARENT;
-        window.setAttributes(params);
-        window.setFlags(0, WindowManager.LayoutParams.FLAG_DIM_BEHIND);
-
-        mIcons[0] = (TextView)findViewById(com.android.internal.R.id.button0);
-        mIcons[1] = (TextView)findViewById(com.android.internal.R.id.button1);
-        mIcons[2] = (TextView)findViewById(com.android.internal.R.id.button2);
-        mIcons[3] = (TextView)findViewById(com.android.internal.R.id.button3);
-        mIcons[4] = (TextView)findViewById(com.android.internal.R.id.button4);
-        mIcons[5] = (TextView)findViewById(com.android.internal.R.id.button5);
-        mIcons[6] = (TextView)findViewById(com.android.internal.R.id.button6);
-        mIcons[7] = (TextView)findViewById(com.android.internal.R.id.button7);
-        mNoAppsText = findViewById(com.android.internal.R.id.no_applications_message);
-
-        for (TextView b: mIcons) {
-            b.setOnClickListener(this);
-        }
-    }
-
-    @Override
-      public boolean onKeyDown(int keyCode, KeyEvent event) {
-        if (keyCode == KeyEvent.KEYCODE_TAB) {
-            // Ignore all meta keys other than SHIFT.  The app switch key could be a
-            // fallback action chorded with ALT, META or even CTRL depending on the key map.
-            // DPad navigation is handled by the ViewRoot elsewhere.
-            final boolean backward = event.isShiftPressed();
-            final int numIcons = mIcons.length;
-            int numButtons = 0;
-            while (numButtons < numIcons && mIcons[numButtons].getVisibility() == View.VISIBLE) {
-                numButtons += 1;
-            }
-            if (numButtons != 0) {
-                int nextFocus = backward ? numButtons - 1 : 0;
-                for (int i = 0; i < numButtons; i++) {
-                    if (mIcons[i].hasFocus()) {
-                        if (backward) {
-                            nextFocus = (i + numButtons - 1) % numButtons;
-                        } else {
-                            nextFocus = (i + 1) % numButtons;
-                        }
-                        break;
-                    }
-                }
-                final int direction = backward ? View.FOCUS_BACKWARD : View.FOCUS_FORWARD;
-                if (mIcons[nextFocus].requestFocus(direction)) {
-                    mIcons[nextFocus].playSoundEffect(
-                            SoundEffectConstants.getContantForFocusDirection(direction));
-                }
-            }
-
-            // The dialog always handles the key to prevent the ViewRoot from
-            // performing the default navigation itself.
-            return true;
-        }
-
-        return super.onKeyDown(keyCode, event);
-    }
-
-    /**
-     * Dismiss the dialog and switch to the selected application.
-     */
-    public void dismissAndSwitch() {
-        final int numIcons = mIcons.length;
-        RecentTag tag = null;
-        for (int i = 0; i < numIcons; i++) {
-            if (mIcons[i].getVisibility() != View.VISIBLE) {
-                break;
-            }
-            if (i == 0 || mIcons[i].hasFocus()) {
-                tag = (RecentTag) mIcons[i].getTag();
-                if (mIcons[i].hasFocus()) {
-                    break;
-                }
-            }
-        }
-        if (tag != null) {
-            switchTo(tag);
-        }
-        dismiss();
-    }
-
-    /**
-     * Handler for user clicks.  If a button was clicked, launch the corresponding activity.
-     */
-    public void onClick(View v) {
-        for (TextView b: mIcons) {
-            if (b == v) {
-                RecentTag tag = (RecentTag)b.getTag();
-                switchTo(tag);
-                break;
-            }
-        }
-        dismiss();
-    }
-
-    private void switchTo(RecentTag tag) {
-        if (tag.info.id >= 0) {
-            // This is an active task; it should just go to the foreground.
-            final ActivityManager am = (ActivityManager)
-                    getContext().getSystemService(Context.ACTIVITY_SERVICE);
-            am.moveTaskToFront(tag.info.id, ActivityManager.MOVE_TASK_WITH_HOME);
-        } else if (tag.intent != null) {
-            tag.intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
-                    | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
-            try {
-                getContext().startActivity(tag.intent);
-            } catch (ActivityNotFoundException e) {
-                Log.w("Recent", "Unable to launch recent task", e);
-            }
-        }
-    }
-
-    /**
-     * Set up and show the recent activities dialog.
-     */
-    @Override
-    public void onStart() {
-        super.onStart();
-        reloadButtons();
-        if (sStatusBar != null) {
-            sStatusBar.disable(StatusBarManager.DISABLE_EXPAND);
-        }
-
-        // receive broadcasts
-        getContext().registerReceiver(mBroadcastReceiver, mBroadcastIntentFilter);
-
-        mHandler.removeCallbacks(mCleanup);
-    }
-
-    /**
-     * Dismiss the recent activities dialog.
-     */
-    @Override
-    public void onStop() {
-        super.onStop();
-
-        if (sStatusBar != null) {
-            sStatusBar.disable(StatusBarManager.DISABLE_NONE);
-        }
-
-        // stop receiving broadcasts
-        getContext().unregisterReceiver(mBroadcastReceiver);
-
-        mHandler.postDelayed(mCleanup, 100);
-     }
-
-    /**
-     * Reload the 6 buttons with recent activities
-     */
-    private void reloadButtons() {
-
-        final Context context = getContext();
-        final PackageManager pm = context.getPackageManager();
-        final ActivityManager am = (ActivityManager)
-                context.getSystemService(Context.ACTIVITY_SERVICE);
-        final List<ActivityManager.RecentTaskInfo> recentTasks =
-                am.getRecentTasks(MAX_RECENT_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
-
-        ActivityInfo homeInfo = 
-            new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
-                    .resolveActivityInfo(pm, 0);
-
-        IconUtilities iconUtilities = new IconUtilities(getContext());
-
-        // Performance note:  Our android performance guide says to prefer Iterator when
-        // using a List class, but because we know that getRecentTasks() always returns
-        // an ArrayList<>, we'll use a simple index instead.
-        int index = 0;
-        int numTasks = recentTasks.size();
-        for (int i = 0; i < numTasks && (index < NUM_BUTTONS); ++i) {
-            final ActivityManager.RecentTaskInfo info = recentTasks.get(i);
-
-            // for debug purposes only, disallow first result to create empty lists
-            if (DBG_FORCE_EMPTY_LIST && (i == 0)) continue;
-
-            Intent intent = new Intent(info.baseIntent);
-            if (info.origActivity != null) {
-                intent.setComponent(info.origActivity);
-            }
-
-            // Skip the current home activity.
-            if (homeInfo != null) {
-                if (homeInfo.packageName.equals(
-                        intent.getComponent().getPackageName())
-                        && homeInfo.name.equals(
-                                intent.getComponent().getClassName())) {
-                    continue;
-                }
-            }
-
-            intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
-                    | Intent.FLAG_ACTIVITY_NEW_TASK);
-            final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
-            if (resolveInfo != null) {
-                final ActivityInfo activityInfo = resolveInfo.activityInfo;
-                final String title = activityInfo.loadLabel(pm).toString();
-                Drawable icon = activityInfo.loadIcon(pm);
-
-                if (title != null && title.length() > 0 && icon != null) {
-                    final TextView tv = mIcons[index];
-                    tv.setText(title);
-                    icon = iconUtilities.createIconDrawable(icon);
-                    tv.setCompoundDrawables(null, icon, null, null);
-                    RecentTag tag = new RecentTag();
-                    tag.info = info;
-                    tag.intent = intent;
-                    tv.setTag(tag);
-                    tv.setVisibility(View.VISIBLE);
-                    tv.setPressed(false);
-                    tv.clearFocus();
-                    ++index;
-                }
-            }
-        }
-
-        // handle the case of "no icons to show"
-        mNoAppsText.setVisibility((index == 0) ? View.VISIBLE : View.GONE);
-
-        // hide the rest
-        for (; index < NUM_BUTTONS; ++index) {
-            mIcons[index].setVisibility(View.GONE);
-        }
-    }
-
-    /**
-     * This is the listener for the ACTION_CLOSE_SYSTEM_DIALOGS intent.  It's an indication that
-     * we should close ourselves immediately, in order to allow a higher-priority UI to take over
-     * (e.g. phone call received).
-     */
-    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
-                String reason = intent.getStringExtra(PhoneWindowManager.SYSTEM_DIALOG_REASON_KEY);
-                if (! PhoneWindowManager.SYSTEM_DIALOG_REASON_RECENT_APPS.equals(reason)) {
-                    dismiss();
-                }
-            }
-        }
-    };
-}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index bfbf0ac..e1a74d1 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -3156,7 +3156,6 @@
                 case WindowManager.LayoutParams.TYPE_STATUS_BAR:
                 case WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL:
                 case WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL:
-                case WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY:
                 case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY:
                 case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
                 case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index b3337bb..7b58608 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -212,11 +212,12 @@
                     //defaultSubId comes before new defaultSubId update) we need to recall all
                     //possible missed notify callback
                     synchronized (mRecords) {
-                      for (Record r : mRecords) {
-                          if(r.subId == SubscriptionManager.DEFAULT_SUB_ID) {
-                              checkPossibleMissNotify(r, newDefaultPhoneId);
-                          }
-                      }
+                        for (Record r : mRecords) {
+                            if(r.subId == SubscriptionManager.DEFAULT_SUB_ID) {
+                                checkPossibleMissNotify(r, newDefaultPhoneId);
+                            }
+                        }
+                        handleRemoveListLocked();
                     }
                     mDefaultSubId = newDefaultSubId;
                     mDefaultPhoneId = newDefaultPhoneId;
@@ -345,10 +346,10 @@
                 + " notifyNow=" + notifyNow + " subId=" + subId + " myUid=" + myUid
                 + " callerUid=" + callerUid);
         }
-        if (events != 0) {
+
+        if (events != PhoneStateListener.LISTEN_NONE) {
             /* Checks permission and throws Security exception */
             checkListenerPermission(events);
-
             synchronized (mRecords) {
                 // register
                 Record r = null;
@@ -363,26 +364,26 @@
                     }
                     r = new Record();
                     r.binder = b;
-                    r.callback = callback;
-                    r.pkgForDebug = pkgForDebug;
-                    r.callerUid = callerUid;
-                    // Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID,
-                    // force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID
-                    if (!SubscriptionManager.isValidSubId(subId)) {
-                        r.subId = SubscriptionManager.DEFAULT_SUB_ID;
-                     } else {//APP specify subID
-                        r.subId = subId;
-                    }
-                    r.phoneId = SubscriptionManager.getPhoneId(r.subId);
-
                     mRecords.add(r);
                     if (DBG) log("listen: add new record");
                 }
 
+                r.callback = callback;
+                r.pkgForDebug = pkgForDebug;
+                r.callerUid = callerUid;
+                // Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID,
+                // force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID
+                if (!SubscriptionManager.isValidSubId(subId)) {
+                    r.subId = SubscriptionManager.DEFAULT_SUB_ID;
+                 } else {//APP specify subID
+                    r.subId = subId;
+                }
+                r.phoneId = SubscriptionManager.getPhoneId(r.subId);
+
                 int phoneId = r.phoneId;
                 r.events = events;
                 if (DBG) {
-                    log("listen: r=" + r + " r.subId=" + r.subId + " phoneId=" + phoneId);
+                    log("listen:  Register r=" + r + " r.subId=" + r.subId + " phoneId=" + phoneId);
                 }
                 if (VDBG) toStringLogSSC("listen");
                 if (notifyNow && validatePhoneId(phoneId)) {
@@ -502,6 +503,7 @@
                 }
             }
         } else {
+            if(DBG) log("listen: Unregister");
             remove(callback.asBinder());
         }
     }
@@ -1445,7 +1447,7 @@
                 r.callback.onServiceStateChanged(
                         new ServiceState(mServiceState[phoneId]));
             } catch (RemoteException ex) {
-                remove(r.binder);
+                mRemoveList.add(r.binder);
             }
         }
 
@@ -1472,7 +1474,7 @@
                 r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
                         : gsmSignalStrength));
             } catch (RemoteException ex) {
-                remove(r.binder);
+                mRemoveList.add(r.binder);
             }
         }
 
@@ -1484,7 +1486,7 @@
                 }
                 r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
             } catch (RemoteException ex) {
-                remove(r.binder);
+                mRemoveList.add(r.binder);
             }
         }
 
@@ -1497,7 +1499,7 @@
                 r.callback.onMessageWaitingIndicatorChanged(
                         mMessageWaiting[phoneId]);
             } catch (RemoteException ex) {
-                remove(r.binder);
+                mRemoveList.add(r.binder);
             }
         }
 
@@ -1510,7 +1512,7 @@
                 r.callback.onCallForwardingIndicatorChanged(
                         mCallForwarding[phoneId]);
             } catch (RemoteException ex) {
-                remove(r.binder);
+                mRemoveList.add(r.binder);
             }
         }
 
@@ -1535,7 +1537,7 @@
                 r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId],
                         mDataConnectionNetworkType[phoneId]);
             } catch (RemoteException ex) {
-                remove(r.binder);
+                mRemoveList.add(r.binder);
             }
         }
     }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8dfb321..970d275 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1734,8 +1734,13 @@
                         logBuilder.append("  MemInfo: ");
                         logBuilder.append(infos[Debug.MEMINFO_SLAB]).append(" kB slab, ");
                         logBuilder.append(infos[Debug.MEMINFO_SHMEM]).append(" kB shmem, ");
+                        logBuilder.append(infos[Debug.MEMINFO_VM_ALLOC_USED]).append(" kB vm alloc, ");
+                        logBuilder.append(infos[Debug.MEMINFO_PAGE_TABLES]).append(" kB page tables ");
+                        logBuilder.append(infos[Debug.MEMINFO_KERNEL_STACK]).append(" kB kernel stack\n");
+                        logBuilder.append("           ");
                         logBuilder.append(infos[Debug.MEMINFO_BUFFERS]).append(" kB buffers, ");
                         logBuilder.append(infos[Debug.MEMINFO_CACHED]).append(" kB cached, ");
+                        logBuilder.append(infos[Debug.MEMINFO_MAPPED]).append(" kB mapped, ");
                         logBuilder.append(infos[Debug.MEMINFO_FREE]).append(" kB free\n");
                         if (infos[Debug.MEMINFO_ZRAM_TOTAL] != 0) {
                             logBuilder.append("  ZRAM: ");
@@ -1952,9 +1957,7 @@
                                 + (SystemClock.uptimeMillis()-start) + "ms");
                         mProcessStats.addSysMemUsageLocked(memInfo.getCachedSizeKb(),
                                 memInfo.getFreeSizeKb(), memInfo.getZramTotalSizeKb(),
-                                memInfo.getBuffersSizeKb()+memInfo.getShmemSizeKb()
-                                        +memInfo.getSlabSizeKb(),
-                                nativeTotalPss);
+                                memInfo.getKernelUsedSizeKb(), nativeTotalPss);
                     }
                 }
 
@@ -14240,8 +14243,7 @@
                 synchronized (this) {
                     mProcessStats.addSysMemUsageLocked(memInfo.getCachedSizeKb(),
                             memInfo.getFreeSizeKb(), memInfo.getZramTotalSizeKb(),
-                            memInfo.getBuffersSizeKb()+memInfo.getShmemSizeKb()+memInfo.getSlabSizeKb(),
-                            nativeProcTotalPss);
+                            memInfo.getKernelUsedSizeKb(), nativeProcTotalPss);
                 }
             }
             if (!brief) {
@@ -14280,16 +14282,12 @@
             }
             if (!isCompact) {
                 pw.print(" Used RAM: "); pw.print(totalPss - cachedPss
-                        + memInfo.getBuffersSizeKb() + memInfo.getShmemSizeKb()
-                        + memInfo.getSlabSizeKb()); pw.print(" kB (");
+                        + memInfo.getKernelUsedSizeKb()); pw.print(" kB (");
                         pw.print(totalPss - cachedPss); pw.print(" used pss + ");
-                        pw.print(memInfo.getBuffersSizeKb()); pw.print(" buffers + ");
-                        pw.print(memInfo.getShmemSizeKb()); pw.print(" shmem + ");
-                        pw.print(memInfo.getSlabSizeKb()); pw.println(" slab)");
+                        pw.print(memInfo.getKernelUsedSizeKb()); pw.print(" kernel)\n");
                 pw.print(" Lost RAM: "); pw.print(memInfo.getTotalSizeKb()
                         - totalPss - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
-                        - memInfo.getBuffersSizeKb() - memInfo.getShmemSizeKb()
-                        - memInfo.getSlabSizeKb()); pw.println(" kB");
+                        - memInfo.getKernelUsedSizeKb()); pw.println(" kB");
             }
             if (!brief) {
                 if (memInfo.getZramTotalSizeKb() != 0) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 03dd3c0..c1bf955 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -120,7 +120,7 @@
     static final boolean DEBUG_RELEASE = DEBUG || false;
     static final boolean DEBUG_SAVED_STATE = DEBUG || false;
     static final boolean DEBUG_SCREENSHOTS = DEBUG || false;
-    static final boolean DEBUG_STATES = DEBUG || false;
+    static final boolean DEBUG_STATES = DEBUG || true;
     static final boolean DEBUG_VISIBLE_BEHIND = DEBUG || false;
 
     public static final int HOME_STACK_ID = 0;
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index afc781f..b331c84 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -166,7 +166,7 @@
                         break;
                     }
                 }
-                if (queueNdx < 0) {
+                if (queueNdx < 0 && task.isPersistable) {
                     mWriteQueue.add(new TaskWriteQueueItem(task));
                 }
             } else {
@@ -473,13 +473,15 @@
                         if (DEBUG) Slog.d(TAG, "mRecents=" + tasks);
                         for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
                             final TaskRecord task = tasks.get(taskNdx);
-                            if (DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task + " persistable=" +
-                                    task.isPersistable);
-                            if (task.isPersistable && !task.stack.isHomeStack()) {
+                            if (DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task +
+                                    " persistable=" + task.isPersistable);
+                            if ((task.isPersistable || task.inRecents)
+                                    && !task.stack.isHomeStack()) {
                                 if (DEBUG) Slog.d(TAG, "adding to persistentTaskIds task=" + task);
                                 persistentTaskIds.add(task.taskId);
                             } else {
-                                if (DEBUG) Slog.d(TAG, "omitting from persistentTaskIds task=" + task);
+                                if (DEBUG) Slog.d(TAG,
+                                        "omitting from persistentTaskIds task=" + task);
                             }
                         }
                     }
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 4dfd23b..ee93233 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -144,7 +144,7 @@
     boolean mReuseTask = false;
 
     private Bitmap mLastThumbnail; // Last thumbnail captured for this item.
-    private final File mLastThumbnailFile; // File containing last thubmnail.
+    private final File mLastThumbnailFile; // File containing last thumbnail.
     private final String mFilename;
     CharSequence lastDescription; // Last description captured for this item.
 
diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index 3b23b6a..f514531 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -248,6 +248,7 @@
                 mInfo.width = mWidth;
                 mInfo.height = mHeight;
                 mInfo.refreshRate = mRefreshRate;
+                mInfo.supportedRefreshRates = new float[] { mRefreshRate };
                 mInfo.densityDpi = mDensityDpi;
                 mInfo.xDpi = mDensityDpi;
                 mInfo.yDpi = mDensityDpi;
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index c2b4478..0232bad 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -257,6 +257,7 @@
                 mInfo.width = mWidth;
                 mInfo.height = mHeight;
                 mInfo.refreshRate = 60;
+                mInfo.supportedRefreshRates = new float[] { 60.0f };
                 mInfo.densityDpi = mDensityDpi;
                 mInfo.xDpi = mDensityDpi;
                 mInfo.yDpi = mDensityDpi;
diff --git a/services/core/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
index a17d731..6b010d9 100644
--- a/services/core/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
@@ -625,6 +625,7 @@
                 mInfo.width = mWidth;
                 mInfo.height = mHeight;
                 mInfo.refreshRate = mRefreshRate;
+                mInfo.supportedRefreshRates = new float[] { mRefreshRate };
                 mInfo.presentationDeadlineNanos = 1000000000L / (int) mRefreshRate; // 1 frame
                 mInfo.flags = mFlags;
                 mInfo.type = Display.TYPE_WIFI;
diff --git a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
index cb92112..9593a9c 100644
--- a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
+++ b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
@@ -57,8 +57,9 @@
      * Handles the incoming active source command.
      *
      * @param newActive new active source information
+     * @param deviceType device type of the new active source
      */
-    void process(ActiveSource newActive) {
+    void process(ActiveSource newActive, int deviceType) {
         // Seq #17
         HdmiCecLocalDeviceTv tv = mSource;
         ActiveSource activeSource = tv.getActiveSource();
@@ -68,7 +69,7 @@
         }
         HdmiDeviceInfo device = mService.getDeviceInfo(newActive.logicalAddress);
         if (device == null) {
-            tv.startNewDeviceAction(newActive);
+            tv.startNewDeviceAction(newActive, deviceType);
         }
 
         if (!tv.isProhibitMode()) {
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index b0a3a66..bb12eae 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -205,13 +205,6 @@
 
     static final int UNKNOWN_VOLUME = -1;
 
-    // IRT(Initiator Repetition Time) in millisecond as recommended in the standard.
-    // Outgoing UCP commands, when in 'Press and Hold' mode, should be this much apart
-    // from the adjacent one so as not to place unnecessarily heavy load on the CEC line.
-    // TODO: This value might need tweaking per product basis. Consider putting it
-    //       in config.xml to allow customization.
-    static final int IRT_MS = 300;
-
     static final String PROPERTY_PREFERRED_ADDRESS_PLAYBACK = "persist.sys.hdmi.addr.playback";
     static final String PROPERTY_PREFERRED_ADDRESS_TV = "persist.sys.hdmi.addr.tv";
 
diff --git a/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java b/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java
index d965caa..3dd1522 100644
--- a/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java
+++ b/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java
@@ -70,7 +70,8 @@
 
     @Override
     boolean processCommand(HdmiCecMessage cmd) {
-        if (mState != STATE_WAITING_FOR_REPORT_POWER_STATUS) {
+        if (mState != STATE_WAITING_FOR_REPORT_POWER_STATUS
+               || mTargetAddress != cmd.getSource()) {
             return false;
         }
         if (cmd.getOpcode() == Constants.MESSAGE_REPORT_POWER_STATUS) {
diff --git a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
index d155e84..5a1d896 100644
--- a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
+++ b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
@@ -95,7 +95,7 @@
         sendCommand(mGivePowerStatus, new SendMessageCallback() {
             @Override
             public void onSendCompleted(int error) {
-                if (error == Constants.SEND_RESULT_NAK) {
+                if (error != Constants.SEND_RESULT_SUCCESS) {
                     invokeCallback(HdmiControlManager.RESULT_COMMUNICATION_FAILED);
                     finish();
                     return;
@@ -168,6 +168,10 @@
     }
 
     private void sendSetStreamPath() {
+        // Turn the active source invalidated, which remains so till <Active Source> comes from
+        // the selected device.
+        tv().getActiveSource().invalidate();
+        tv().setActivePath(mTarget.getPhysicalAddress());
         sendCommand(HdmiCecMessageBuilder.buildSetStreamPath(
                 getSourceAddress(), mTarget.getPhysicalAddress()));
         invokeCallback(HdmiControlManager.RESULT_SUCCESS);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java b/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
index fc53c50..d26be57 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
@@ -85,8 +85,7 @@
      * Process the command. Called whenever a new command arrives.
      *
      * @param cmd command to process
-     * @return true if the command was consumed in the process; Otherwise false, which
-     *          indicates that the command shall be handled by other actions.
+     * @return true if the command was consumed in the process; Otherwise false.
      */
     abstract boolean processCommand(HdmiCecMessage cmd);
 
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java b/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
index 61c9424..2eca42b 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
@@ -18,6 +18,10 @@
 
 import android.view.KeyEvent;
 
+import libcore.util.EmptyArray;
+
+import java.util.Arrays;
+
 /**
  * Helper class to translate android keycode to hdmi cec keycode and vice versa.
  */
@@ -156,46 +160,60 @@
 
     /**
      * A mapping between Android and CEC keycode.
+     * <p>
+     * Normal implementation of this looks like
      *
-     * <p>Normal implementation of this looks like
      * <pre>
-     *    new KeycodeEntry(KeyEvent.KEYCODE_DPAD_CENTER, CEC_KEYCODE_SELECT);
+     * new KeycodeEntry(KeyEvent.KEYCODE_DPAD_CENTER, CEC_KEYCODE_SELECT);
      * </pre>
-     * <p>However, some keys in CEC requires additional parameter.
-     * In order to use parameterized cec key, add unique android keycode (existing or custom)
-     * corresponding to a pair of cec keycode and and its param.
+     * <p>
+     * However, some keys in CEC requires additional parameter. In order to use parameterized cec
+     * key, add unique android keycode (existing or custom) corresponding to a pair of cec keycode
+     * and and its param.
+     *
      * <pre>
-     *    new KeycodeEntry(CUSTOME_ANDORID_KEY_1, CEC_KEYCODE_SELECT_BROADCAST_TYPE,
-     *        UI_BROADCAST_TOGGLE_ALL);
-     *    new KeycodeEntry(CUSTOME_ANDORID_KEY_2, CEC_KEYCODE_SELECT_BROADCAST_TYPE,
-     *        UI_BROADCAST_ANALOGUE);
+     * new KeycodeEntry(CUSTOME_ANDORID_KEY_1, CEC_KEYCODE_SELECT_BROADCAST_TYPE,
+     *         UI_BROADCAST_TOGGLE_ALL);
+     * new KeycodeEntry(CUSTOME_ANDORID_KEY_2, CEC_KEYCODE_SELECT_BROADCAST_TYPE,
+     *         UI_BROADCAST_ANALOGUE);
      * </pre>
      */
     private static class KeycodeEntry {
         private final int mAndroidKeycode;
-        private final int mCecKeycode;
         private final boolean mIsRepeatable;
+        private final byte[] mCecKeycodeAndParams;
+
+        private KeycodeEntry(int androidKeycode, int cecKeycode, boolean isRepeatable,
+                byte[] cecParams) {
+            mAndroidKeycode = androidKeycode;
+            mIsRepeatable = isRepeatable;
+            mCecKeycodeAndParams = new byte[cecParams.length + 1];
+            System.arraycopy(cecParams, 0, mCecKeycodeAndParams, 1, cecParams.length);
+            mCecKeycodeAndParams[0] = (byte) (cecKeycode & 0xFF);
+        }
 
         private KeycodeEntry(int androidKeycode, int cecKeycode, boolean isRepeatable) {
-            mAndroidKeycode = androidKeycode;
-            mCecKeycode = cecKeycode;
-            mIsRepeatable = isRepeatable;
+            this(androidKeycode, cecKeycode, isRepeatable, EmptyArray.BYTE);
+        }
+
+        private KeycodeEntry(int androidKeycode, int cecKeycode, byte[] cecParams) {
+            this(androidKeycode, cecKeycode, true, cecParams);
         }
 
         private KeycodeEntry(int androidKeycode, int cecKeycode) {
-            this(androidKeycode, cecKeycode, true);
+            this(androidKeycode, cecKeycode, true, EmptyArray.BYTE);
         }
 
-        private int toCecKeycodeIfMatched(int androidKeycode) {
+        private byte[] toCecKeycodeAndParamIfMatched(int androidKeycode) {
             if (mAndroidKeycode == androidKeycode) {
-                return mCecKeycode;
+                return mCecKeycodeAndParams;
             } else {
-                return UNSUPPORTED_KEYCODE;
+                return null;
             }
         }
 
-        private int toAndroidKeycodeIfMatched(int cecKeycode) {
-            if (cecKeycode == mCecKeycode) {
+        private int toAndroidKeycodeIfMatched(byte[] cecKeycodeAndParams) {
+            if (Arrays.equals(mCecKeycodeAndParams, cecKeycodeAndParams)) {
                 return mAndroidKeycode;
             } else {
                 return UNSUPPORTED_KEYCODE;
@@ -211,6 +229,11 @@
         }
     }
 
+    private static byte[] intToSingleByteArray(int value) {
+        return new byte[] {
+                (byte) (value & 0xFF) };
+    }
+
     // Keycode entry container for all mappings.
     // Note that order of entry is the same as above cec keycode definition.
     private static final KeycodeEntry[] KEYCODE_ENTRIES = new KeycodeEntry[] {
@@ -227,19 +250,25 @@
             new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_LEFT_UP),
             // No Android keycode defined for CEC_KEYCODE_LEFT_DOWN
             new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_LEFT_DOWN),
-            new KeycodeEntry(KeyEvent.KEYCODE_HOME, CEC_KEYCODE_ROOT_MENU, false),
-            new KeycodeEntry(KeyEvent.KEYCODE_SETTINGS, CEC_KEYCODE_SETUP_MENU, false),
-            new KeycodeEntry(KeyEvent.KEYCODE_MENU, CEC_KEYCODE_CONTENTS_MENU, false),
+            new KeycodeEntry(KeyEvent.KEYCODE_HOME, CEC_KEYCODE_ROOT_MENU),
+            new KeycodeEntry(KeyEvent.KEYCODE_SETTINGS, CEC_KEYCODE_SETUP_MENU),
+            new KeycodeEntry(KeyEvent.KEYCODE_TV_CONTENTS_MENU, CEC_KEYCODE_CONTENTS_MENU, false),
             // No Android keycode defined for CEC_KEYCODE_FAVORITE_MENU
             new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_FAVORITE_MENU),
+            // Note that both BACK and ESCAPE are mapped to EXIT of CEC keycode.
+            // This would be problematic when translates CEC keycode to Android keycode.
+            // In current implementation, we pick BACK as mapping of EXIT key.
+            // If you'd like to map CEC EXIT to Android EXIT key, change order of
+            // the following two definition.
             new KeycodeEntry(KeyEvent.KEYCODE_BACK, CEC_KEYCODE_EXIT),
+            new KeycodeEntry(KeyEvent.KEYCODE_ESCAPE, CEC_KEYCODE_EXIT),
             // RESERVED
             new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_TOP_MENU, CEC_KEYCODE_MEDIA_TOP_MENU),
-            // No Android keycode defined for CEC_KEYCODE_MEDIA_CONTEXT_SENSITIVE_MENU
-            new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_MEDIA_CONTEXT_SENSITIVE_MENU),
+            new KeycodeEntry(KeyEvent.KEYCODE_TV_MEDIA_CONTEXT_MENU,
+                    CEC_KEYCODE_MEDIA_CONTEXT_SENSITIVE_MENU),
             // RESERVED
             // No Android keycode defined for CEC_KEYCODE_NUMBER_ENTRY_MODE
-            new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_NUMBER_ENTRY_MODE),
+            new KeycodeEntry(KeyEvent.KEYCODE_TV_NUMBER_ENTRY, CEC_KEYCODE_NUMBER_ENTRY_MODE),
             new KeycodeEntry(KeyEvent.KEYCODE_11, CEC_KEYCODE_NUMBER_11),
             new KeycodeEntry(KeyEvent.KEYCODE_12, CEC_KEYCODE_NUMBER_12),
             new KeycodeEntry(KeyEvent.KEYCODE_0, CEC_KEYCODE_NUMBER_0_OR_NUMBER_10),
@@ -276,7 +305,12 @@
             new KeycodeEntry(KeyEvent.KEYCODE_VOLUME_MUTE, CEC_KEYCODE_MUTE, false),
             new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_PLAY, CEC_KEYCODE_PLAY),
             new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_STOP, CEC_KEYCODE_STOP),
+            // Note that we map both MEDIA_PAUSE and MEDIA_PLAY_PAUSE to CEC PAUSE key.
+            // When it translates CEC PAUSE key, it picks Android MEDIA_PAUSE key as a mapping of
+            // it. If you'd like to choose MEDIA_PLAY_PAUSE, please change order of the following
+            // two lines.
             new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_PAUSE, CEC_KEYCODE_PAUSE),
+            new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, CEC_KEYCODE_PAUSE),
             new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_RECORD, CEC_KEYCODE_RECORD),
             new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_REWIND, CEC_KEYCODE_REWIND),
             new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD, CEC_KEYCODE_FAST_FORWARD),
@@ -291,48 +325,61 @@
             new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_RESERVED),
             // No Android keycode defined for CEC_KEYCODE_ANGLE
             new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_ANGLE),
-            // No Android keycode defined for CEC_KEYCODE_SUB_PICTURE
-            new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_SUB_PICTURE),
+            new KeycodeEntry(KeyEvent.KEYCODE_CAPTIONS, CEC_KEYCODE_SUB_PICTURE),
             // No Android keycode defined for CEC_KEYCODE_VIDEO_ON_DEMAND
             new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_VIDEO_ON_DEMAND),
             new KeycodeEntry(KeyEvent.KEYCODE_GUIDE, CEC_KEYCODE_ELECTRONIC_PROGRAM_GUIDE),
-            // No Android keycode defined for CEC_KEYCODE_TIMER_PROGRAMMING
-            new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_TIMER_PROGRAMMING),
+            new KeycodeEntry(KeyEvent.KEYCODE_TV_TIMER_PROGRAMMING, CEC_KEYCODE_TIMER_PROGRAMMING),
             // No Android keycode defined for CEC_KEYCODE_INITIAL_CONFIGURATION
             new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_INITIAL_CONFIGURATION),
             // No Android keycode defined for CEC_KEYCODE_SELECT_BROADCAST_TYPE
             new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_SELECT_BROADCAST_TYPE),
+            new KeycodeEntry(KeyEvent.KEYCODE_TV_TERRESTRIAL_ANALOG,
+                    CEC_KEYCODE_SELECT_BROADCAST_TYPE, true,
+                    intToSingleByteArray(UI_BROADCAST_ANALOGUE)),
+            new KeycodeEntry(KeyEvent.KEYCODE_TV_TERRESTRIAL_DIGITAL,
+                    CEC_KEYCODE_SELECT_BROADCAST_TYPE, true,
+                    intToSingleByteArray(UI_BROADCAST_DIGITAL_TERRESTRIAL)),
+            new KeycodeEntry(KeyEvent.KEYCODE_TV_SATELLITE_BS,
+                    CEC_KEYCODE_SELECT_BROADCAST_TYPE, true,
+                    intToSingleByteArray(UI_BROADCAST_DIGITAL_SATELLITE)),
+            new KeycodeEntry(KeyEvent.KEYCODE_TV_SATELLITE_CS,
+                    CEC_KEYCODE_SELECT_BROADCAST_TYPE, true,
+                    intToSingleByteArray(UI_BROADCAST_DIGITAL_COMMNICATIONS_SATELLITE)),
+            new KeycodeEntry(KeyEvent.KEYCODE_TV_NETWORK,
+                    CEC_KEYCODE_SELECT_BROADCAST_TYPE, true,
+                    intToSingleByteArray(UI_BROADCAST_TOGGLE_ANALOGUE_DIGITAL)),
             // No Android keycode defined for CEC_KEYCODE_SELECT_SOUND_PRESENTATION
             new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_SELECT_SOUND_PRESENTATION),
             // RESERVED
             // The following deterministic key definitions do not need key mapping
             // since they are supposed to be generated programmatically only.
             // No Android keycode defined for CEC_KEYCODE_PLAY_FUNCTION
-            new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_PLAY_FUNCTION),
+            new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_PLAY_FUNCTION, false),
             // No Android keycode defined for CEC_KEYCODE_PAUSE_PLAY_FUNCTION
-            new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_PAUSE_PLAY_FUNCTION),
+            new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_PAUSE_PLAY_FUNCTION, false),
             // No Android keycode defined for CEC_KEYCODE_RECORD_FUNCTION
-            new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_RECORD_FUNCTION),
+            new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_RECORD_FUNCTION, false),
             // No Android keycode defined for CEC_KEYCODE_PAUSE_RECORD_FUNCTION
-            new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_PAUSE_RECORD_FUNCTION),
+            new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_PAUSE_RECORD_FUNCTION, false),
             // No Android keycode defined for CEC_KEYCODE_STOP_FUNCTION
-            new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_STOP_FUNCTION),
+            new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_STOP_FUNCTION, false),
             // No Android keycode defined for CEC_KEYCODE_MUTE_FUNCTION
             new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_MUTE_FUNCTION, false),
             // No Android keycode defined for CEC_KEYCODE_RESTORE_VOLUME_FUNCTION
             new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_RESTORE_VOLUME_FUNCTION, false),
             // No Android keycode defined for CEC_KEYCODE_TUNE_FUNCTION
-            new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_TUNE_FUNCTION),
+            new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_TUNE_FUNCTION, false),
             // No Android keycode defined for CEC_KEYCODE_SELECT_MEDIA_FUNCTION
-            new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_SELECT_MEDIA_FUNCTION),
+            new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_SELECT_MEDIA_FUNCTION, false),
             // No Android keycode defined for CEC_KEYCODE_SELECT_AV_INPUT_FUNCTION
-            new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_SELECT_AV_INPUT_FUNCTION),
+            new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_SELECT_AV_INPUT_FUNCTION, false),
             // No Android keycode defined for CEC_KEYCODE_SELECT_AUDIO_INPUT_FUNCTION
-            new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_SELECT_AUDIO_INPUT_FUNCTION),
+            new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_SELECT_AUDIO_INPUT_FUNCTION, false),
             // No Android keycode defined for CEC_KEYCODE_POWER_TOGGLE_FUNCTION
-            new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_POWER_TOGGLE_FUNCTION),
+            new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_POWER_TOGGLE_FUNCTION, false),
             // No Android keycode defined for CEC_KEYCODE_POWER_OFF_FUNCTION
-            new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_POWER_OFF_FUNCTION),
+            new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_POWER_OFF_FUNCTION, false),
             // No Android keycode defined for CEC_KEYCODE_POWER_ON_FUNCTION
             new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_POWER_ON_FUNCTION, false),
             // RESERVED
@@ -347,31 +394,31 @@
     };
 
     /**
-     * Translate Android keycode to Hdmi Cec keycode.
+     * Translate Android keycode to Hdmi Cec keycode and params.
      *
      * @param keycode Android keycode. For details, refer {@link KeyEvent}
-     * @return single byte CEC keycode if matched.
+     * @return byte array of CEC keycode and params if matched. Otherwise, return null.
      */
-    static int androidKeyToCecKey(int keycode) {
+    static byte[] androidKeyToCecKey(int keycode) {
         for (int i = 0; i < KEYCODE_ENTRIES.length; ++i) {
-            int cecKeycode = KEYCODE_ENTRIES[i].toCecKeycodeIfMatched(keycode);
-            if (cecKeycode != UNSUPPORTED_KEYCODE) {
-                return cecKeycode;
+            byte[] cecKeycodeAndParams = KEYCODE_ENTRIES[i].toCecKeycodeAndParamIfMatched(keycode);
+            if (cecKeycodeAndParams != null) {
+                return cecKeycodeAndParams;
             }
         }
-        return UNSUPPORTED_KEYCODE;
+        return null;
     }
 
     /**
-     * Translate Hdmi CEC keycode to Android keycode.
+     * Translate Hdmi CEC keycode with params to Android keycode.
      *
-     * @param keycode CEC keycode
-     * @return cec keycode corresponding to the given android keycode.
-     *         If finds no matched keycode, return {@link #UNSUPPORTED_KEYCODE}
+     * @param cecKeycodeAndParams CEC keycode and params
+     * @return cec keycode corresponding to the given android keycode. If finds no matched keycode,
+     *         return {@link #UNSUPPORTED_KEYCODE}
      */
-    static int cecKeyToAndroidKey(int keycode) {
+    static int cecKeycodeAndParamsToAndroidKey(byte[] cecKeycodeAndParams) {
         for (int i = 0; i < KEYCODE_ENTRIES.length; ++i) {
-            int androidKey = KEYCODE_ENTRIES[i].toAndroidKeycodeIfMatched(keycode);
+            int androidKey = KEYCODE_ENTRIES[i].toAndroidKeycodeIfMatched(cecKeycodeAndParams);
             if (androidKey != UNSUPPORTED_KEYCODE) {
                 return androidKey;
             }
@@ -399,7 +446,6 @@
      * Returns {@code true} if given Android keycode is supported, otherwise {@code false}.
      */
     static boolean isSupportedKeycode(int androidKeycode) {
-        return HdmiCecKeycode.androidKeyToCecKey(androidKeycode)
-                != HdmiCecKeycode.UNSUPPORTED_KEYCODE;
-  }
+        return HdmiCecKeycode.androidKeyToCecKey(androidKeycode) != null;
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 8f9af61..4f8b9fb 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -34,7 +34,6 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
-import java.util.LinkedList;
 import java.util.List;
 
 /**
@@ -125,7 +124,7 @@
 
     // A collection of FeatureAction.
     // Note that access to this collection should happen in service thread.
-    private final LinkedList<HdmiCecFeatureAction> mActions = new LinkedList<>();
+    private final ArrayList<HdmiCecFeatureAction> mActions = new ArrayList<>();
 
     private final Handler mHandler = new Handler () {
         @Override
@@ -290,12 +289,14 @@
     @ServiceThreadOnly
     private boolean dispatchMessageToAction(HdmiCecMessage message) {
         assertRunOnServiceThread();
-        for (HdmiCecFeatureAction action : mActions) {
-            if (action.processCommand(message)) {
-                return true;
-            }
+        boolean processed = false;
+        // Use copied action list in that processCommand may remove itself.
+        for (HdmiCecFeatureAction action : new ArrayList<>(mActions)) {
+            // Iterates all actions to check whether incoming message is consumed.
+            boolean result = action.processCommand(message);
+            processed = processed || result;
         }
-        return false;
+        return processed;
     }
 
     @ServiceThreadOnly
@@ -425,9 +426,7 @@
 
         final long downTime = SystemClock.uptimeMillis();
         final byte[] params = message.getParams();
-        // Note that we don't support parameterized keycode now.
-        // TODO: translate parameterized keycode as well.
-        final int keycode = HdmiCecKeycode.cecKeyToAndroidKey(params[0]);
+        final int keycode = HdmiCecKeycode.cecKeycodeAndParamsToAndroidKey(params);
         int keyRepeatCount = 0;
         if (mLastKeycode != HdmiCecKeycode.UNSUPPORTED_KEYCODE) {
             if (keycode == mLastKeycode) {
@@ -517,8 +516,8 @@
     }
 
     protected boolean handleVendorCommand(HdmiCecMessage message) {
-        if (!mService.invokeVendorCommandListeners(mDeviceType, message.getSource(),
-                message.getParams(), false)) {
+        if (!mService.invokeVendorCommandListenersOnReceived(mDeviceType, message.getSource(),
+                message.getDestination(), message.getParams(), false)) {
             // Vendor command listener may not have been registered yet. Respond with
             // <Feature Abort> [NOT_IN_CORRECT_MODE] so that the sender can try again later.
             mService.maySendFeatureAbortCommand(message, Constants.ABORT_NOT_IN_CORRECT_MODE);
@@ -530,8 +529,8 @@
         byte[] params = message.getParams();
         int vendorId = HdmiUtils.threeBytesToInt(params);
         if (vendorId == mService.getVendorId()) {
-            if (!mService.invokeVendorCommandListeners(mDeviceType, message.getSource(), params,
-                    true)) {
+            if (!mService.invokeVendorCommandListenersOnReceived(mDeviceType, message.getSource(),
+                    message.getDestination(), params, true)) {
                 mService.maySendFeatureAbortCommand(message, Constants.ABORT_NOT_IN_CORRECT_MODE);
             }
         } else if (message.getDestination() != Constants.ADDR_BROADCAST &&
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 780d54b..da508e8 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -50,6 +50,8 @@
         assertRunOnServiceThread();
         mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
                 mAddress, mService.getPhysicalAddress(), mDeviceType));
+        mService.sendCecCommand(HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
+                mAddress, mService.getVendorId()));
         startQueuedActions();
     }
 
@@ -230,4 +232,4 @@
         super.dump(pw);
         pw.println("mIsActiveSource: " + mIsActiveSource);
     }
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 0fb4b48..6bae761 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -110,6 +110,9 @@
     // If true, TV wakes itself up when receiving <Text/Image View On>.
     private boolean mAutoWakeup;
 
+    // List of the logical address of local CEC devices. Unmodifiable, thread-safe.
+    private List<Integer> mLocalDeviceAddresses;
+
     private final HdmiCecStandbyModeHandler mStandbyHandler;
 
     // If true, do not do routing control/send active source for internal source.
@@ -141,10 +144,22 @@
         mSkipRoutingControl = (reason == HdmiControlService.INITIATED_BY_WAKE_UP_MESSAGE);
         launchRoutingControl(reason != HdmiControlService.INITIATED_BY_ENABLE_CEC &&
                 reason != HdmiControlService.INITIATED_BY_BOOT_UP);
+        mLocalDeviceAddresses = initLocalDeviceAddresses();
         launchDeviceDiscovery();
         startQueuedActions();
     }
 
+
+    @ServiceThreadOnly
+    private List<Integer> initLocalDeviceAddresses() {
+        assertRunOnServiceThread();
+        List<Integer> addresses = new ArrayList<>();
+        for (HdmiCecLocalDevice device : mService.getAllLocalDevices()) {
+            addresses.add(device.getDeviceInfo().getLogicalAddress());
+        }
+        return Collections.unmodifiableList(addresses);
+    }
+
     @Override
     @ServiceThreadOnly
     protected int getPreferredAddress() {
@@ -351,15 +366,28 @@
         if (!action.isEmpty()) {
             action.get(0).processKeyEvent(keyCode, isPressed);
         } else {
-            if (isPressed && getActiveSource().isValid()) {
-                int logicalAddress = getActiveSource().logicalAddress;
-                addAndStartAction(new SendKeyAction(this, logicalAddress, keyCode));
-            } else {
-                Slog.w(TAG, "Discard key event: " + keyCode + " pressed:" + isPressed);
+            if (isPressed) {
+                int logicalAddress = findKeyReceiverAddress();
+                if (logicalAddress != Constants.ADDR_INVALID) {
+                    addAndStartAction(new SendKeyAction(this, logicalAddress, keyCode));
+                    return;
+                }
             }
+            Slog.w(TAG, "Discard key event: " + keyCode + " pressed:" + isPressed);
         }
     }
 
+    private int findKeyReceiverAddress() {
+        if (getActiveSource().isValid()) {
+            return getActiveSource().logicalAddress;
+        }
+        HdmiDeviceInfo info = getDeviceInfoByPath(getActivePath());
+        if (info != null) {
+            return info.getLogicalAddress();
+        }
+        return Constants.ADDR_INVALID;
+    }
+
     private static void invokeCallback(IHdmiControlCallback callback, int result) {
         if (callback == null) {
             return;
@@ -377,11 +405,12 @@
         assertRunOnServiceThread();
         int logicalAddress = message.getSource();
         int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
-        if (getCecDeviceInfo(logicalAddress) == null) {
+        HdmiDeviceInfo info = getCecDeviceInfo(logicalAddress);
+        if (info == null) {
             handleNewDeviceAtTheTailOfActivePath(physicalAddress);
         } else {
             ActiveSource activeSource = ActiveSource.of(logicalAddress, physicalAddress);
-            ActiveSourceHandler.create(this, null).process(activeSource);
+            ActiveSourceHandler.create(this, null).process(activeSource, info.getDeviceType());
         }
         return true;
     }
@@ -471,7 +500,7 @@
         if (!isInDeviceList(address, path)) {
             handleNewDeviceAtTheTailOfActivePath(path);
         }
-        startNewDeviceAction(ActiveSource.of(address, path));
+        startNewDeviceAction(ActiveSource.of(address, path), type);
         return true;
     }
 
@@ -507,7 +536,7 @@
         return false;
     }
 
-    void startNewDeviceAction(ActiveSource activeSource) {
+    void startNewDeviceAction(ActiveSource activeSource, int deviceType) {
         for (NewDeviceAction action : getActions(NewDeviceAction.class)) {
             // If there is new device action which has the same logical address and path
             // ignore new request.
@@ -523,7 +552,7 @@
         }
 
         addAndStartAction(new NewDeviceAction(this, activeSource.logicalAddress,
-                activeSource.physicalAddress));
+                activeSource.physicalAddress, deviceType));
     }
 
     private void handleNewDeviceAtTheTailOfActivePath(int path) {
@@ -1182,15 +1211,8 @@
         }
     }
 
-    @ServiceThreadOnly
     private boolean isLocalDeviceAddress(int address) {
-        assertRunOnServiceThread();
-        for (HdmiCecLocalDevice device : mService.getAllLocalDevices()) {
-            if (device.isAddressOf(address)) {
-                return true;
-            }
-        }
-        return false;
+        return mLocalDeviceAddresses.contains(address);
     }
 
     @ServiceThreadOnly
@@ -1240,6 +1262,17 @@
         }
     }
 
+    List<HdmiDeviceInfo> getSafeCecDevicesLocked() {
+        ArrayList<HdmiDeviceInfo> infoList = new ArrayList<>();
+        for (HdmiDeviceInfo info : mSafeAllDeviceInfos) {
+            if (isLocalDeviceAddress(info.getLogicalAddress())) {
+                continue;
+            }
+            infoList.add(info);
+        }
+        return infoList;
+    }
+
     /**
      * Called when a device is newly added or a new device is detected or
      * existing device is updated.
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 60d1520..953bef2 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -303,6 +303,7 @@
             }
         } else {
             Slog.i(TAG, "Device does not support HDMI-CEC.");
+            return;
         }
 
         mMhlController = HdmiMhlControllerStub.create(this);
@@ -315,20 +316,23 @@
         mMessageValidator = new HdmiCecMessageValidator(this);
         publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService());
 
-        // Register broadcast receiver for power state change.
         if (mCecController != null) {
+            // Register broadcast receiver for power state change.
             IntentFilter filter = new IntentFilter();
             filter.addAction(Intent.ACTION_SCREEN_OFF);
             filter.addAction(Intent.ACTION_SCREEN_ON);
             filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
             getContext().registerReceiver(mHdmiControlBroadcastReceiver, filter);
+
+            // Register ContentObserver to monitor the settings change.
+            registerContentObserver();
         }
     }
 
     /**
      * Called when the initialization of local devices is complete.
      */
-    private void onInitializeCecComplete() {
+    private void onInitializeCecComplete(int initiatedBy) {
         if (mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON) {
             mPowerStatus = HdmiControlManager.POWER_STATUS_ON;
         }
@@ -336,7 +340,22 @@
 
         if (isTvDevice()) {
             mCecController.setOption(OPTION_CEC_AUTO_WAKEUP, toInt(tv().getAutoWakeup()));
-            registerContentObserver();
+        }
+        int reason = -1;
+        switch (initiatedBy) {
+            case INITIATED_BY_BOOT_UP:
+                reason = HdmiControlManager.CONTROL_STATE_CHANGED_REASON_START;
+                break;
+            case INITIATED_BY_ENABLE_CEC:
+                reason = HdmiControlManager.CONTROL_STATE_CHANGED_REASON_SETTING;
+                break;
+            case INITIATED_BY_SCREEN_ON:
+            case INITIATED_BY_WAKE_UP_MESSAGE:
+                reason = HdmiControlManager.CONTROL_STATE_CHANGED_REASON_WAKEUP;
+                break;
+        }
+        if (reason != -1) {
+            invokeVendorCommandListenersOnControlStateChanged(true, reason);
         }
     }
 
@@ -401,10 +420,6 @@
         Global.putInt(cr, key, toInt(value));
     }
 
-    private void unregisterSettingsObserver() {
-        getContext().getContentResolver().unregisterContentObserver(mSettingsObserver);
-    }
-
     private void initializeCec(int initiatedBy) {
         mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, ENABLED);
         initializeLocalDevices(initiatedBy);
@@ -459,7 +474,7 @@
                         if (initiatedBy != INITIATED_BY_HOTPLUG) {
                             // In case of the hotplug we don't call onInitializeCecComplete()
                             // since we reallocate the logical address only.
-                            onInitializeCecComplete();
+                            onInitializeCecComplete(initiatedBy);
                         }
                         notifyAddressAllocated(allocatedDevices, initiatedBy);
                     }
@@ -729,20 +744,18 @@
     void onHotplug(int portId, boolean connected) {
         assertRunOnServiceThread();
 
-        ArrayList<HdmiCecLocalDevice> localDevices = new ArrayList<>();
-        for (int type : mLocalDevices) {
-            if (type == HdmiDeviceInfo.DEVICE_TV) {
-                // Skip the reallocation of the logical address on TV.
-                continue;
+        if (connected && !isTvDevice()) {
+            ArrayList<HdmiCecLocalDevice> localDevices = new ArrayList<>();
+            for (int type : mLocalDevices) {
+                HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(type);
+                if (localDevice == null) {
+                    localDevice = HdmiCecLocalDevice.create(this, type);
+                    localDevice.init();
+                }
+                localDevices.add(localDevice);
             }
-            HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(type);
-            if (localDevice == null) {
-                localDevice = HdmiCecLocalDevice.create(this, type);
-                localDevice.init();
-            }
-            localDevices.add(localDevice);
+            allocateLogicalAddress(localDevices, INITIATED_BY_HOTPLUG);
         }
-        allocateLogicalAddress(localDevices, INITIATED_BY_HOTPLUG);
 
         for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) {
             device.onHotplug(portId, connected);
@@ -827,6 +840,7 @@
     @ServiceThreadOnly
     void handleMhlHotplugEvent(int portId, boolean connected) {
         assertRunOnServiceThread();
+        // Hotplug event is used to add/remove MHL devices as TV input.
         if (connected) {
             HdmiMhlLocalDeviceStub newDevice = new HdmiMhlLocalDeviceStub(this, portId);
             HdmiMhlLocalDeviceStub oldDevice = mMhlController.addLocalDevice(newDevice);
@@ -834,17 +848,14 @@
                 oldDevice.onDeviceRemoved();
                 Slog.i(TAG, "Old device of port " + portId + " is removed");
             }
+            invokeDeviceEventListeners(newDevice.getInfo(), DEVICE_EVENT_ADD_DEVICE);
+            updateSafeMhlInput();
         } else {
             HdmiMhlLocalDeviceStub device = mMhlController.removeLocalDevice(portId);
             if (device != null) {
                 device.onDeviceRemoved();
-                // There is no explicit event for device removal.
-                // Hence we remove the device on hotplug event.
-                HdmiDeviceInfo deviceInfo = device.getInfo();
-                if (deviceInfo != null) {
-                    invokeDeviceEventListeners(deviceInfo, DEVICE_EVENT_REMOVE_DEVICE);
-                    updateSafeMhlInput();
-                }
+                invokeDeviceEventListeners(device.getInfo(), DEVICE_EVENT_REMOVE_DEVICE);
+                updateSafeMhlInput();
             } else {
                 Slog.w(TAG, "No device to remove:[portId=" + portId);
             }
@@ -880,11 +891,8 @@
         assertRunOnServiceThread();
         HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId);
 
-        // Hotplug event should already have been called before device status change event.
         if (device != null) {
             device.setDeviceStatusChange(adopterId, deviceId);
-            invokeDeviceEventListeners(device.getInfo(), DEVICE_EVENT_ADD_DEVICE);
-            updateSafeMhlInput();
         } else {
             Slog.w(TAG, "No mhl device exists for device status event[portId:"
                     + portId + ", adopterId:" + adopterId + ", deviceId:" + deviceId + "]");
@@ -1025,6 +1033,7 @@
 
         @Override
         public HdmiDeviceInfo getActiveSource() {
+            enforceAccessPermission();
             HdmiCecLocalDeviceTv tv = tv();
             if (tv == null) {
                 Slog.w(TAG, "Local tv device not available");
@@ -1238,6 +1247,19 @@
             }
         }
 
+        // Returns all the CEC devices on the bus including system audio, switch,
+        // even those of reserved type.
+        @Override
+        public List<HdmiDeviceInfo> getDeviceList() {
+            enforceAccessPermission();
+            HdmiCecLocalDeviceTv tv = tv();
+            synchronized (mLock) {
+                return (tv == null)
+                        ? Collections.<HdmiDeviceInfo>emptyList()
+                        : tv.getSafeCecDevicesLocked();
+            }
+        }
+
         @Override
         public void setSystemAudioVolume(final int oldIndex, final int newIndex,
                 final int maxIndex) {
@@ -1344,11 +1366,13 @@
 
         @Override
         public void setHdmiRecordListener(IHdmiRecordListener listener) {
+            enforceAccessPermission();
             HdmiControlService.this.setHdmiRecordListener(listener);
         }
 
         @Override
         public void startOneTouchRecord(final int recorderAddress, final byte[] recordSource) {
+            enforceAccessPermission();
             runOnServiceThread(new Runnable() {
                 @Override
                 public void run() {
@@ -1363,6 +1387,7 @@
 
         @Override
         public void stopOneTouchRecord(final int recorderAddress) {
+            enforceAccessPermission();
             runOnServiceThread(new Runnable() {
                 @Override
                 public void run() {
@@ -1378,6 +1403,7 @@
         @Override
         public void startTimerRecording(final int recorderAddress, final int sourceType,
                 final byte[] recordSource) {
+            enforceAccessPermission();
             runOnServiceThread(new Runnable() {
                 @Override
                 public void run() {
@@ -1393,6 +1419,7 @@
         @Override
         public void clearTimerRecording(final int recorderAddress, final int sourceType,
                 final byte[] recordSource) {
+            enforceAccessPermission();
             runOnServiceThread(new Runnable() {
                 @Override
                 public void run() {
@@ -1696,7 +1723,7 @@
     }
 
     boolean isTvDevice() {
-        return tv() != null;
+        return mLocalDevices.contains(HdmiDeviceInfo.DEVICE_TV);
     }
 
     private HdmiCecLocalDevicePlayback playback() {
@@ -1782,6 +1809,8 @@
     private void onStandby() {
         assertRunOnServiceThread();
         mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY;
+        invokeVendorCommandListenersOnControlStateChanged(false,
+                HdmiControlManager.CONTROL_STATE_CHANGED_REASON_STANDBY);
 
         final List<HdmiCecLocalDevice> devices = getAllLocalDevices();
         disableDevices(new PendingActionClearedCallback() {
@@ -1820,9 +1849,6 @@
             for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) {
                 device.disableDevice(mStandbyMessageReceived, callback);
             }
-            if (isTvDevice()) {
-                unregisterSettingsObserver();
-            }
         }
 
         mMhlController.clearAllLocalDevices();
@@ -1867,8 +1893,8 @@
         }
     }
 
-    boolean invokeVendorCommandListeners(int deviceType, int srcAddress, byte[] params,
-            boolean hasVendorId) {
+    boolean invokeVendorCommandListenersOnReceived(int deviceType, int srcAddress, int destAddress,
+            byte[] params, boolean hasVendorId) {
         synchronized (mLock) {
             if (mVendorCommandListenerRecords.isEmpty()) {
                 return false;
@@ -1878,7 +1904,7 @@
                     continue;
                 }
                 try {
-                    record.mListener.onReceived(srcAddress, params, hasVendorId);
+                    record.mListener.onReceived(srcAddress, destAddress, params, hasVendorId);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Failed to notify vendor command reception", e);
                 }
@@ -1887,6 +1913,22 @@
         }
     }
 
+    boolean invokeVendorCommandListenersOnControlStateChanged(boolean enabled, int reason) {
+        synchronized (mLock) {
+            if (mVendorCommandListenerRecords.isEmpty()) {
+                return false;
+            }
+            for (VendorCommandListenerRecord record : mVendorCommandListenerRecords) {
+                try {
+                    record.mListener.onControlStateChanged(enabled, reason);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Failed to notify control-state-changed to vendor handler", e);
+                }
+            }
+            return true;
+        }
+    }
+
     private void addHdmiMhlVendorCommandListener(IHdmiMhlVendorCommandListener listener) {
         HdmiMhlVendorCommandListenerRecord record =
                 new HdmiMhlVendorCommandListenerRecord(listener);
@@ -1936,6 +1978,11 @@
     void setControlEnabled(boolean enabled) {
         assertRunOnServiceThread();
 
+        if (!enabled) {
+            // Call the vendor handler before the service is disabled.
+            invokeVendorCommandListenersOnControlStateChanged(false,
+                    HdmiControlManager.CONTROL_STATE_CHANGED_REASON_SETTING);
+        }
         int value = toInt(enabled);
         mCecController.setOption(OPTION_CEC_ENABLE, value);
         mMhlController.setOption(OPTION_MHL_ENABLE, value);
@@ -2008,9 +2055,7 @@
         // may not be the MHL-enabled one. In this case the device info to be passed to
         // input change listener should be the one describing the corresponding HDMI port.
         HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId);
-        HdmiDeviceInfo info = (device != null && device.getInfo() != null)
-                ? device.getInfo()
-                : mPortDeviceMap.get(portId);
+        HdmiDeviceInfo info = (device != null) ? device.getInfo() : mPortDeviceMap.get(portId);
         invokeInputChangeListener(info);
     }
 
diff --git a/services/core/java/com/android/server/hdmi/NewDeviceAction.java b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
index 2074085..998889b 100644
--- a/services/core/java/com/android/server/hdmi/NewDeviceAction.java
+++ b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
@@ -47,6 +47,7 @@
 
     private final int mDeviceLogicalAddress;
     private final int mDevicePhysicalAddress;
+    private final int mDeviceType;
 
     private int mVendorId;
     private String mDisplayName;
@@ -57,12 +58,14 @@
      * @param source {@link HdmiCecLocalDevice} instance
      * @param deviceLogicalAddress logical address of the device in interest
      * @param devicePhysicalAddress physical address of the device in interest
+     * @param deviceType type of the device
      */
     NewDeviceAction(HdmiCecLocalDevice source, int deviceLogicalAddress,
-            int devicePhysicalAddress) {
+            int devicePhysicalAddress, int deviceType) {
         super(source);
         mDeviceLogicalAddress = deviceLogicalAddress;
         mDevicePhysicalAddress = devicePhysicalAddress;
+        mDeviceType = deviceType;
         mVendorId = Constants.UNKNOWN_VENDOR_ID;
     }
 
@@ -155,8 +158,7 @@
         HdmiDeviceInfo deviceInfo = new HdmiDeviceInfo(
                 mDeviceLogicalAddress, mDevicePhysicalAddress,
                 tv().getPortId(mDevicePhysicalAddress),
-                HdmiUtils.getTypeFromAddress(mDeviceLogicalAddress),
-                mVendorId, mDisplayName);
+                mDeviceType, mVendorId, mDisplayName);
         tv().addCecDevice(deviceInfo);
 
         if (HdmiUtils.getTypeFromAddress(mDeviceLogicalAddress)
diff --git a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
index 7db991a..e764a1c 100644
--- a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
+++ b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
@@ -92,7 +92,8 @@
 
     @Override
     boolean processCommand(HdmiCecMessage cmd) {
-        if (mState != STATE_WAITING_FOR_REPORT_POWER_STATUS) {
+        if (mState != STATE_WAITING_FOR_REPORT_POWER_STATUS
+                || mTargetAddress != cmd.getSource()) {
             return false;
         }
         if (cmd.getOpcode() == Constants.MESSAGE_REPORT_POWER_STATUS) {
diff --git a/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java b/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java
index 39c0d7f..906944b 100644
--- a/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java
+++ b/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java
@@ -68,23 +68,21 @@
                             finish();
                             return;
                         }
-
-                        mState = STATE_WAITING_FOR_RECORD_STATUS;
-                        addTimer(mState, RECORD_STATUS_TIMEOUT_MS);
                     }
                 });
+        mState = STATE_WAITING_FOR_RECORD_STATUS;
+        addTimer(mState, RECORD_STATUS_TIMEOUT_MS);
     }
 
     @Override
     boolean processCommand(HdmiCecMessage cmd) {
-        if (mState != STATE_WAITING_FOR_RECORD_STATUS) {
+        if (mState != STATE_WAITING_FOR_RECORD_STATUS || mRecorderAddress != cmd.getSource()) {
             return false;
         }
 
         switch (cmd.getOpcode()) {
             case Constants.MESSAGE_RECORD_STATUS:
                 return handleRecordStatus(cmd);
-
         }
         return false;
     }
diff --git a/services/core/java/com/android/server/hdmi/SendKeyAction.java b/services/core/java/com/android/server/hdmi/SendKeyAction.java
index ed978e0..eef5010 100644
--- a/services/core/java/com/android/server/hdmi/SendKeyAction.java
+++ b/services/core/java/com/android/server/hdmi/SendKeyAction.java
@@ -15,7 +15,7 @@
  */
 package com.android.server.hdmi;
 
-import static com.android.server.hdmi.Constants.IRT_MS;
+import static com.android.server.hdmi.HdmiConfig.IRT_MS;
 
 import android.util.Slog;
 import android.view.KeyEvent;
@@ -35,6 +35,11 @@
 final class SendKeyAction extends HdmiCecFeatureAction {
     private static final String TAG = "SendKeyAction";
 
+    // Amount of time this action waits for a new release key input event. When timed out,
+    // the action sends out UCR and finishes its lifecycle. Used to deal with missing key release
+    // event, which can lead the device on the receiving end to generating unintended key repeats.
+    private static final int AWAIT_RELEASE_KEY_MS = 1000;
+
     // State in which the action is at work. The state is set in {@link #start()} and
     // persists throughout the process till it is set back to {@code STATE_NONE} at the end.
     private static final int STATE_PROCESSING_KEYCODE = 1;
@@ -45,6 +50,10 @@
     // The key code of the last key press event the action is passed via processKeyEvent.
     private int mLastKeycode;
 
+    // The time stamp when the last CEC key command was sent. Used to determine the press-and-hold
+    // operation.
+    private long mLastSendKeyTime;
+
     /**
      * Constructor.
      *
@@ -61,6 +70,7 @@
     @Override
     public boolean start() {
         sendKeyDown(mLastKeycode);
+        mLastSendKeyTime = getCurrentTime();
         // finish action for non-repeatable key.
         if (!HdmiCecKeycode.isRepeatableKey(mLastKeycode)) {
             sendKeyUp();
@@ -68,10 +78,14 @@
             return true;
         }
         mState = STATE_PROCESSING_KEYCODE;
-        addTimer(mState, IRT_MS);
+        addTimer(mState, AWAIT_RELEASE_KEY_MS);
         return true;
     }
 
+    private long getCurrentTime() {
+        return System.currentTimeMillis();
+    }
+
     /**
      * Called when a key event should be handled for the action.
      *
@@ -83,24 +97,32 @@
             Slog.w(TAG, "Not in a valid state");
             return;
         }
-        // A new key press event that comes in with a key code different from the last
-        // one sets becomes a new key code to be used for press-and-hold operation.
-        // Removes any pending timer and starts a new timer for itself.
-        // Key release event indicates that the action shall be finished. Send UCR
-        // command and terminate the action. Other release events are ignored.
         if (isPressed) {
+            // A new key press event that comes in with a key code different from the last
+            // one becomes a new key code to be used for press-and-hold operation.
             if (keycode != mLastKeycode) {
                 sendKeyDown(keycode);
+                mLastSendKeyTime = getCurrentTime();
                 if (!HdmiCecKeycode.isRepeatableKey(keycode)) {
                     sendKeyUp();
                     finish();
                     return;
                 }
-                mActionTimer.clearTimerMessage();
-                addTimer(mState, IRT_MS);
-                mLastKeycode = keycode;
+            } else {
+                // Press-and-hold key transmission takes place if Android key inputs are
+                // repeatedly coming in and more than IRT_MS has passed since the last
+                // press-and-hold key transmission.
+                if (getCurrentTime() - mLastSendKeyTime >= IRT_MS) {
+                    sendKeyDown(keycode);
+                    mLastSendKeyTime = getCurrentTime();
+                }
             }
+            mActionTimer.clearTimerMessage();
+            addTimer(mState, AWAIT_RELEASE_KEY_MS);
+            mLastKeycode = keycode;
         } else {
+            // Key release event indicates that the action shall be finished. Send UCR
+            // command and terminate the action. Other release events are ignored.
             if (keycode == mLastKeycode) {
                 sendKeyUp();
                 finish();
@@ -109,12 +131,12 @@
     }
 
     private void sendKeyDown(int keycode) {
-        int cecKeycode = HdmiCecKeycode.androidKeyToCecKey(keycode);
-        if (cecKeycode == HdmiCecKeycode.UNSUPPORTED_KEYCODE) {
+        byte[] cecKeycodeAndParams = HdmiCecKeycode.androidKeyToCecKey(keycode);
+        if (cecKeycodeAndParams == null) {
             return;
         }
         sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(getSourceAddress(),
-                mTargetAddress, new byte[] { (byte) (cecKeycode & 0xFF) }));
+                mTargetAddress, cecKeycodeAndParams));
     }
 
     private void sendKeyUp() {
@@ -130,15 +152,12 @@
 
     @Override
     public void handleTimerEvent(int state) {
-        // Timer event occurs every IRT_MS milliseconds to perform key-repeat (or press-and-hold)
-        // operation. If the last received key code is as same as the one with which the action
-        // is started, plus there was no key release event in last IRT_MS timeframe, send a UCP
-        // command and start another timer to schedule the next press-and-hold command.
+        // Timeout on waiting for the release key event. Send UCR and quit the action.
         if (mState != STATE_PROCESSING_KEYCODE) {
             Slog.w(TAG, "Not in a valid state");
             return;
         }
-        sendKeyDown(mLastKeycode);
-        addTimer(mState, IRT_MS);
+        sendKeyUp();
+        finish();
     }
 }
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAction.java
index 0871194..6023354 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioAction.java
@@ -125,6 +125,9 @@
 
     @Override
     final boolean processCommand(HdmiCecMessage cmd) {
+        if (cmd.getSource() != mAvrLogicalAddress) {
+            return false;
+        }
         switch (mState) {
             case STATE_WAIT_FOR_SET_SYSTEM_AUDIO_MODE:
                 if (cmd.getOpcode() == Constants.MESSAGE_FEATURE_ABORT
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
index 3653aac..50f8475 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
@@ -58,17 +58,16 @@
 
     @Override
     boolean processCommand(HdmiCecMessage cmd) {
-        if (mState != STATE_WAITING_FOR_SYSTEM_AUDIO_MODE_STATUS) {
+        if (mState != STATE_WAITING_FOR_SYSTEM_AUDIO_MODE_STATUS
+                || mAvrAddress != cmd.getSource()) {
             return false;
         }
 
-        switch (cmd.getOpcode()) {
-            case Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS:
-                handleSystemAudioModeStatusMessage();
-                return true;
-            default:
-                return false;
+        if (cmd.getOpcode() == Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS) {
+            handleSystemAudioModeStatusMessage();
+            return true;
         }
+        return false;
     }
 
     private void handleSystemAudioModeStatusMessage() {
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
index bfcda50..dba3591 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
@@ -79,7 +79,7 @@
 
     @Override
     boolean processCommand(HdmiCecMessage cmd) {
-        if (mState != STATE_WAIT_FOR_REPORT_AUDIO_STATUS) {
+        if (mState != STATE_WAIT_FOR_REPORT_AUDIO_STATUS || mAvrAddress != cmd.getSource()) {
             return false;
         }
 
diff --git a/services/core/java/com/android/server/hdmi/TimerRecordingAction.java b/services/core/java/com/android/server/hdmi/TimerRecordingAction.java
index 8fc0182..5fcbc91 100644
--- a/services/core/java/com/android/server/hdmi/TimerRecordingAction.java
+++ b/services/core/java/com/android/server/hdmi/TimerRecordingAction.java
@@ -96,11 +96,8 @@
 
     @Override
     boolean processCommand(HdmiCecMessage cmd) {
-        if (mState != STATE_WAITING_FOR_TIMER_STATUS) {
-            return false;
-        }
-
-        if (cmd.getSource() != mRecorderAddress) {
+        if (mState != STATE_WAITING_FOR_TIMER_STATUS
+                || cmd.getSource() != mRecorderAddress) {
             return false;
         }
 
diff --git a/services/core/java/com/android/server/hdmi/VolumeControlAction.java b/services/core/java/com/android/server/hdmi/VolumeControlAction.java
index 4338fc7..cd38b1f 100644
--- a/services/core/java/com/android/server/hdmi/VolumeControlAction.java
+++ b/services/core/java/com/android/server/hdmi/VolumeControlAction.java
@@ -16,10 +16,10 @@
 
 package com.android.server.hdmi;
 
-import static com.android.server.hdmi.Constants.IRT_MS;
 import static com.android.server.hdmi.Constants.MESSAGE_FEATURE_ABORT;
 import static com.android.server.hdmi.Constants.MESSAGE_REPORT_AUDIO_STATUS;
 import static com.android.server.hdmi.Constants.MESSAGE_USER_CONTROL_PRESSED;
+import static com.android.server.hdmi.HdmiConfig.IRT_MS;
 
 import android.media.AudioManager;
 
@@ -45,6 +45,7 @@
     private boolean mIsVolumeUp;
     private long mLastKeyUpdateTime;
     private int mLastAvrVolume;
+    private boolean mLastAvrMute;
     private boolean mSentKeyPressed;
 
     /**
@@ -74,6 +75,7 @@
         mAvrAddress = avrAddress;
         mIsVolumeUp = isVolumeUp;
         mLastAvrVolume = UNKNOWN_AVR_VOLUME;
+        mLastAvrMute = false;
         mSentKeyPressed = false;
 
         updateLastKeyUpdateTime();
@@ -108,6 +110,8 @@
             HdmiLogger.debug("Volume Key Status Changed[old:%b new:%b]", mIsVolumeUp, isVolumeUp);
             sendVolumeKeyReleased();
             mIsVolumeUp = isVolumeUp;
+            sendVolumeKeyPressed();
+            resetTimer();
         }
         updateLastKeyUpdateTime();
     }
@@ -129,9 +133,8 @@
                 return handleReportAudioStatus(cmd);
             case MESSAGE_FEATURE_ABORT:
                 return handleFeatureAbort(cmd);
-            default:
-                return false;
         }
+        return false;
     }
 
     private boolean handleReportAudioStatus(HdmiCecMessage cmd) {
@@ -139,9 +142,12 @@
         boolean mute = (params[0] & 0x80) == 0x80;
         int volume = params[0] & 0x7F;
         mLastAvrVolume = volume;
+        mLastAvrMute = mute;
         if (shouldUpdateAudioVolume(mute)) {
             HdmiLogger.debug("Force volume change[mute:%b, volume=%d]", mute, volume);
             tv().setAudioStatus(mute, volume);
+            mLastAvrVolume = UNKNOWN_AVR_VOLUME;
+            mLastAvrMute = false;
         }
         return true;
     }
@@ -182,8 +188,9 @@
             sendVolumeKeyReleased();
         }
         if (mLastAvrVolume != UNKNOWN_AVR_VOLUME) {
-            tv().setAudioStatus(false, mLastAvrVolume);
+            tv().setAudioStatus(mLastAvrMute, mLastAvrVolume);
             mLastAvrVolume = UNKNOWN_AVR_VOLUME;
+            mLastAvrMute = false;
         }
     }
 
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index c6d2db2..83d6986 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -137,11 +137,15 @@
         public void onReceive(Context context, Intent intent) {
             Slog.d(TAG, "Receieved: " + intent.getAction());
             if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
-                int uidRemoved = intent.getIntExtra(Intent.EXTRA_UID, -1);
-                if (DEBUG) {
-                    Slog.d(TAG, "Removing jobs for uid: " + uidRemoved);
+                // If this is an outright uninstall rather than the first half of an
+                // app update sequence, cancel the jobs associated with the app.
+                if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+                    int uidRemoved = intent.getIntExtra(Intent.EXTRA_UID, -1);
+                    if (DEBUG) {
+                        Slog.d(TAG, "Removing jobs for uid: " + uidRemoved);
+                    }
+                    cancelJobsForUid(uidRemoved);
                 }
-                cancelJobsForUid(uidRemoved);
             } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
                 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
                 if (DEBUG) {
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index cdfb656..00eaaa4 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -325,7 +325,7 @@
 
             final long token = Binder.clearCallingIdentity();
             try {
-                dump(pw);
+                MediaProjectionManagerService.this.dump(pw);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index f85e2d9..f19bfc2 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -26,6 +26,7 @@
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.util.Slog;
+import android.view.WindowManager;
 
 import com.android.internal.statusbar.IStatusBar;
 import com.android.internal.statusbar.IStatusBarService;
@@ -295,9 +296,10 @@
         }
     }
 
-    /** 
+    /**
      * Hide or show the on-screen Menu key. Only call this from the window manager, typically in
-     * response to a window with FLAG_NEEDS_MENU_KEY set.
+     * response to a window with {@link android.view.WindowManager.LayoutParams#needsMenuKey} set
+     * to {@link android.view.WindowManager.LayoutParams#NEEDS_MENU_SET_TRUE}.
      */
     @Override
     public void topAppWindowChanged(final boolean menuVisible) {
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 77ab33b..44e4ad1 100644
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -122,6 +122,8 @@
                 } catch (RemoteException e) {
                     Slog.w(TAG, "Error registering listeners to HdmiControlService:", e);
                 }
+            } else {
+                Slog.w(TAG, "HdmiControlService is not available");
             }
         }
     }
@@ -743,7 +745,7 @@
                             && sinkConfig.channelMask() != mDesiredChannelMask)
                     || (mDesiredFormat != AudioFormat.ENCODING_DEFAULT
                             && sinkConfig.format() != mDesiredFormat)) {
-                sinkConfig = mAudioSource.buildConfig(mDesiredSamplingRate, mDesiredChannelMask,
+                sinkConfig = mAudioSink.buildConfig(mDesiredSamplingRate, mDesiredChannelMask,
                         mDesiredFormat, null);
                 shouldRecreateAudioPatch = true;
             }
@@ -914,11 +916,18 @@
                     break;
                 }
                 case HDMI_DEVICE_UPDATED: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    String inputId = (String) args.arg1;
-                    HdmiDeviceInfo info = (HdmiDeviceInfo) args.arg2;
-                    args.recycle();
-                    mListener.onHdmiDeviceUpdated(inputId, info);
+                    HdmiDeviceInfo info = (HdmiDeviceInfo) msg.obj;
+                    String inputId = null;
+                    synchronized (mLock) {
+                        inputId = mHdmiInputIdMap.get(info.getId());
+                    }
+                    if (inputId != null) {
+                        mListener.onHdmiDeviceUpdated(inputId, info);
+                    } else {
+                        Slog.w(TAG, "Could not resolve input ID matching the device info; "
+                                + "ignoring.");
+                    }
+                    break;
                 }
                 default: {
                     Slog.w(TAG, "Unhandled message: " + msg);
@@ -986,11 +995,7 @@
                         }
                         mHdmiDeviceList.add(deviceInfo);
                         messageType = ListenerHandler.HDMI_DEVICE_UPDATED;
-                        String inputId = mHdmiInputIdMap.get(deviceInfo.getId());
-                        SomeArgs args = SomeArgs.obtain();
-                        args.arg1 = inputId;
-                        args.arg2 = deviceInfo;
-                        obj = args;
+                        obj = deviceInfo;
                         break;
                     }
                 }
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index fa1c0ff..fde703d 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -346,8 +346,7 @@
                         case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG:
                         case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
                         case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY:
-                        case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL:
-                        case WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY: {
+                        case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: {
                             Rect magnifiedRegionBounds = mTempRect2;
                             mMagnifedViewport.getMagnifiedFrameInContentCoordsLocked(
                                     magnifiedRegionBounds);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 30589b1..b0feca8 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -376,10 +376,9 @@
             stack.dump(prefix + "  ", pw);
         }
         pw.println();
-        pw.println("  Application tokens in bottom up Z order:");
+        pw.println("  Application tokens in top down Z order:");
         int ndx = 0;
-        final int numStacks = mStacks.size();
-        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
             ArrayList<Task> tasks = mStacks.get(stackNdx).getTasks();
             for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
                 AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2354369..57d793f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2515,9 +2515,8 @@
             }
             mInputMonitor.updateInputWindowsLw(false /*force*/);
 
-            if (localLOGV) Slog.v(
-                TAG, "New client " + client.asBinder()
-                + ": window=" + win);
+            if (true || localLOGV) Slog.v(TAG, "addWindow: New client " + client.asBinder()
+                    + ": window=" + win + " Callers=" + Debug.getCallers(5));
 
             if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false)) {
                 reportNewConfig = true;
@@ -2681,7 +2680,8 @@
         mPolicy.removeWindowLw(win);
         win.removeLocked();
 
-        if (DEBUG_ADD_REMOVE) Slog.v(TAG, "removeWindowInnerLocked: " + win);
+        if (true || DEBUG_ADD_REMOVE) Slog.v(TAG, "removeWindowInnerLocked: " + win +
+                " Callers=" + Debug.getCallers(5));
         mWindowMap.remove(win.mClient.asBinder());
         if (win.mAppOp != AppOpsManager.OP_NONE) {
             mAppOps.finishOp(win.mAppOp, win.getOwningUid(), win.getOwningPackage());
@@ -9378,7 +9378,6 @@
             final int type = attrs.type;
             if (canBeSeen
                     && (type == TYPE_SYSTEM_DIALOG
-                     || type == TYPE_RECENTS_OVERLAY
                      || type == TYPE_SYSTEM_ERROR
                      || (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0)) {
                 mInnerFields.mSyswin = true;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index b4a7f04..806f7c5 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -704,9 +704,8 @@
         WindowState ws = this;
         WindowList windows = getWindowList();
         while (true) {
-            if ((ws.mAttrs.privateFlags
-                    & WindowManager.LayoutParams.PRIVATE_FLAG_SET_NEEDS_MENU_KEY) != 0) {
-                return (ws.mAttrs.flags & WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY) != 0;
+            if (ws.mAttrs.needsMenuKey != WindowManager.LayoutParams.NEEDS_MENU_UNSET) {
+                return ws.mAttrs.needsMenuKey == WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE;
             }
             // If we reached the bottom of the range of windows we are considering,
             // assume no menu is needed.
diff --git a/services/print/java/com/android/server/print/RemotePrintSpooler.java b/services/print/java/com/android/server/print/RemotePrintSpooler.java
index 9496cae..7ab3840 100644
--- a/services/print/java/com/android/server/print/RemotePrintSpooler.java
+++ b/services/print/java/com/android/server/print/RemotePrintSpooler.java
@@ -21,6 +21,7 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.os.Binder;
+import android.os.Build;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
@@ -55,7 +56,8 @@
 
     private static final boolean DEBUG = false;
 
-    private static final long BIND_SPOOLER_SERVICE_TIMEOUT = 10000;
+    private static final long BIND_SPOOLER_SERVICE_TIMEOUT =
+            ("eng".equals(Build.TYPE)) ? 120000 : 10000;
 
     private final Object mLock = new Object();
 
diff --git a/telecomm/java/android/telecom/AudioState.java b/telecomm/java/android/telecom/AudioState.java
index fc2fff4..d0e2860 100644
--- a/telecomm/java/android/telecom/AudioState.java
+++ b/telecomm/java/android/telecom/AudioState.java
@@ -16,7 +16,6 @@
 
 package android.telecom;
 
-import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -24,9 +23,7 @@
 
 /**
  *  Encapsulates all audio states during a call.
- *  @hide
  */
-@SystemApi
 public final class AudioState implements Parcelable {
     /** Direct the audio stream through the device's earpiece. */
     public static final int ROUTE_EARPIECE      = 0x00000001;
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index b7b98bf..15cb786 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -16,8 +16,6 @@
 
 package android.telecom;
 
-import android.annotation.SystemApi;
-
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -27,9 +25,7 @@
 
 /**
  * Represents a conference call which can contain any number of {@link Connection} objects.
- * @hide
  */
-@SystemApi
 public abstract class Conference {
 
     /** @hide */
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 4c1f75f..2932721 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -19,7 +19,6 @@
 import com.android.internal.telecom.IVideoCallback;
 import com.android.internal.telecom.IVideoProvider;
 
-import android.annotation.SystemApi;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.IBinder;
@@ -44,9 +43,7 @@
  * Implementations are then responsible for updating the state of the {@code Connection}, and
  * must call {@link #destroy()} to signal to the framework that the {@code Connection} is no
  * longer used and associated resources may be recovered.
- * @hide
  */
-@SystemApi
 public abstract class Connection {
 
     public static final int STATE_INITIALIZING = 0;
@@ -876,7 +873,7 @@
         return mUnmodifiableConferenceableConnections;
     }
 
-    /**
+    /*
      * @hide
      */
     public final void setConnectionService(ConnectionService connectionService) {
@@ -921,6 +918,7 @@
             mConference = conference;
             if (mConnectionService != null && mConnectionService.containsConference(conference)) {
                 fireConferenceChanged();
+                onConferenceChanged();
             }
             return true;
         }
@@ -936,6 +934,7 @@
             Log.d(this, "Conference reset");
             mConference = null;
             fireConferenceChanged();
+            onConferenceChanged();
         }
     }
 
@@ -1020,14 +1019,9 @@
     public void onPostDialContinue(boolean proceed) {}
 
     /**
-     * Merge this connection and the specified connection into a conference call.  Once the
-     * connections are merged, the calls should be added to the an existing or new
-     * {@code Conference} instance. For new {@code Conference} instances, use
-     * {@code ConnectionService#addConference}.
-     *
-     * @param otherConnection The connection with which this connection should be conferenced.
+     * Notifies this Connection that the conference which is set on it has changed.
      */
-    public void onConferenceWith(Connection otherConnection) {}
+    public void onConferenceChanged() {}
 
     static String toLogSafePhoneNumber(String number) {
         // For unknown number, log empty string.
diff --git a/telecomm/java/android/telecom/ConnectionRequest.java b/telecomm/java/android/telecom/ConnectionRequest.java
index f691c17..71b481b 100644
--- a/telecomm/java/android/telecom/ConnectionRequest.java
+++ b/telecomm/java/android/telecom/ConnectionRequest.java
@@ -16,7 +16,6 @@
 
 package android.telecom;
 
-import android.annotation.SystemApi;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -25,9 +24,7 @@
 /**
  * Simple data container encapsulating a request to some entity to
  * create a new {@link Connection}.
- * @hide
  */
-@SystemApi
 public final class ConnectionRequest implements Parcelable {
 
     // TODO: Token to limit recursive invocations
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 6eee99d..649533e 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -16,7 +16,6 @@
 
 package android.telecom;
 
-import android.annotation.SystemApi;
 import android.annotation.SdkConstant;
 import android.app.Service;
 import android.content.ComponentName;
@@ -43,9 +42,7 @@
 /**
  * A {@link android.app.Service} that provides telephone connections to processes running on an
  * Android device.
- * @hide
  */
-@SystemApi
 public abstract class ConnectionService extends Service {
     /**
      * The {@link Intent} that must be declared as handled by the service.
diff --git a/telecomm/java/android/telecom/DisconnectCause.java b/telecomm/java/android/telecom/DisconnectCause.java
index 52c1284..9be0138 100644
--- a/telecomm/java/android/telecom/DisconnectCause.java
+++ b/telecomm/java/android/telecom/DisconnectCause.java
@@ -16,7 +16,6 @@
 
 package android.telecom;
 
-import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.media.ToneGenerator;
@@ -29,9 +28,7 @@
  * cause of the disconnect. Optionally, it may include a localized label and/or localized description
  * to display to the user which is provided by the {@link ConnectionService}. It also may contain a
  * reason for the the disconnect, which is intended for logging and not for display to the user.
- * @hide
  */
-@SystemApi
 public final class DisconnectCause implements Parcelable {
 
     /** Disconnected because of an unknown or unspecified reason. */
diff --git a/telecomm/java/android/telecom/GatewayInfo.java b/telecomm/java/android/telecom/GatewayInfo.java
index 3efab0f..583c3e2 100644
--- a/telecomm/java/android/telecom/GatewayInfo.java
+++ b/telecomm/java/android/telecom/GatewayInfo.java
@@ -30,9 +30,7 @@
  * <li> Call the appropriate routing number
  * <li> Display information about how the call is being routed to the user
  * </ol>
- * @hide
  */
-@SystemApi
 public class GatewayInfo implements Parcelable {
 
     private final String mGatewayProviderPackageName;
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index 67b6328..402df30 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -16,7 +16,6 @@
 
 package android.telecom;
 
-import android.annotation.SystemApi;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.res.Resources.NotFoundException;
@@ -35,9 +34,7 @@
 /**
  * Describes a distinct account, line of service or call placement method that the system
  * can use to place phone calls.
- * @hide
  */
-@SystemApi
 public class PhoneAccount implements Parcelable {
 
     /**
@@ -302,6 +299,9 @@
      * The raw callback number used for this {@code PhoneAccount}, as distinct from
      * {@link #getAddress()}. For the majority of {@code PhoneAccount}s this should be registered
      * as {@code null}.  It is used by the system for SIM-based {@code PhoneAccount} registration
+     * where {@link android.telephony.TelephonyManager#setLine1NumberForDisplay(String, String)}
+     * has been used to alter the callback number.
+     * <p>
      *
      * @return The subscription number, suitable for display to the user.
      */
@@ -405,12 +405,17 @@
     }
 
     private Drawable getIcon(Context context, int resId) {
+        if (resId == 0) {
+            return null;
+        }
+
         Context packageContext;
         try {
             packageContext = context.createPackageContext(
                     mAccountHandle.getComponentName().getPackageName(), 0);
         } catch (PackageManager.NameNotFoundException e) {
-            Log.w(this, "Cannot find package %s", mAccountHandle.getComponentName().getPackageName());
+            Log.w(this, "Cannot find package %s",
+                    mAccountHandle.getComponentName().getPackageName());
             return null;
         }
         try {
@@ -473,4 +478,19 @@
         in.readList(supportedUriSchemes, classLoader);
         mSupportedUriSchemes = Collections.unmodifiableList(supportedUriSchemes);
     }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder().append("[PhoneAccount: ")
+                .append(mAccountHandle)
+                .append(" Capabilities: ")
+                .append(mCapabilities)
+                .append(" Schemes: ");
+        for (String scheme : mSupportedUriSchemes) {
+            sb.append(scheme)
+                    .append(" ");
+        }
+        sb.append("]");
+        return sb.toString();
+    }
 }
diff --git a/telecomm/java/android/telecom/PhoneAccountHandle.java b/telecomm/java/android/telecom/PhoneAccountHandle.java
index 652befe5..768188b 100644
--- a/telecomm/java/android/telecom/PhoneAccountHandle.java
+++ b/telecomm/java/android/telecom/PhoneAccountHandle.java
@@ -16,7 +16,6 @@
 
 package android.telecom;
 
-import android.annotation.SystemApi;
 import android.content.ComponentName;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -25,9 +24,7 @@
 
 /**
  * The unique identifier for a {@link PhoneAccount}.
- * @hide
  */
-@SystemApi
 public class PhoneAccountHandle implements Parcelable {
     private ComponentName mComponentName;
     private String mId;
@@ -74,9 +71,11 @@
 
     @Override
     public String toString() {
+        // Note: Log.pii called for mId as it can contain personally identifying phone account
+        // information such as SIP account IDs.
         return new StringBuilder().append(mComponentName)
                     .append(", ")
-                    .append(mId)
+                    .append(Log.pii(mId))
                     .toString();
     }
 
diff --git a/telecomm/java/android/telecom/PhoneCapabilities.java b/telecomm/java/android/telecom/PhoneCapabilities.java
index de2abcb..9c67503 100644
--- a/telecomm/java/android/telecom/PhoneCapabilities.java
+++ b/telecomm/java/android/telecom/PhoneCapabilities.java
@@ -16,14 +16,10 @@
 
 package android.telecom;
 
-import android.annotation.SystemApi;
-
 /**
  * Defines capabilities a phone call can support, such as conference calling and video telephony.
  * Also defines properties of a phone call, such as whether it is using VoLTE technology.
- * @hide
  */
-@SystemApi
 public final class PhoneCapabilities {
     /** Call can currently be put on hold or unheld. */
     public static final int HOLD               = 0x00000001;
@@ -96,43 +92,65 @@
             | ADD_CALL | RESPOND_VIA_TEXT | MUTE | MANAGE_CONFERENCE | SEPARATE_FROM_CONFERENCE
             | DISCONNECT_FROM_CONFERENCE;
 
+    /**
+     * Whether this set of capabilities supports the specified capability.
+     * @param capabilities The set of capabilities.
+     * @param capability The capability to check capabilities for.
+     * @return Whether the specified capability is supported.
+     * @hide
+     */
+    public static boolean can(int capabilities, int capability) {
+        return (capabilities & capability) != 0;
+    }
+
+    /**
+     * Removes the specified capability from the set of capabilities and returns the new set.
+     * @param capabilities The set of capabilities.
+     * @param capability The capability to remove from the set.
+     * @return The set of capabilities, with the capability removed.
+     * @hide
+     */
+    public static int remove(int capabilities, int capability) {
+        return capabilities & ~capability;
+    }
+
     public static String toString(int capabilities) {
         StringBuilder builder = new StringBuilder();
         builder.append("[Capabilities:");
-        if ((capabilities & HOLD) != 0) {
+        if (can(capabilities, HOLD)) {
             builder.append(" HOLD");
         }
-        if ((capabilities & SUPPORT_HOLD) != 0) {
+        if (can(capabilities, SUPPORT_HOLD)) {
             builder.append(" SUPPORT_HOLD");
         }
-        if ((capabilities & MERGE_CONFERENCE) != 0) {
+        if (can(capabilities, MERGE_CONFERENCE)) {
             builder.append(" MERGE_CONFERENCE");
         }
-        if ((capabilities & SWAP_CONFERENCE) != 0) {
+        if (can(capabilities, SWAP_CONFERENCE)) {
             builder.append(" SWAP_CONFERENCE");
         }
-        if ((capabilities & ADD_CALL) != 0) {
+        if (can(capabilities, ADD_CALL)) {
             builder.append(" ADD_CALL");
         }
-        if ((capabilities & RESPOND_VIA_TEXT) != 0) {
+        if (can(capabilities, RESPOND_VIA_TEXT)) {
             builder.append(" RESPOND_VIA_TEXT");
         }
-        if ((capabilities & MUTE) != 0) {
+        if (can(capabilities, MUTE)) {
             builder.append(" MUTE");
         }
-        if ((capabilities & MANAGE_CONFERENCE) != 0) {
+        if (can(capabilities, MANAGE_CONFERENCE)) {
             builder.append(" MANAGE_CONFERENCE");
         }
-        if ((capabilities & SUPPORTS_VT_LOCAL) != 0) {
+        if (can(capabilities, SUPPORTS_VT_LOCAL)) {
             builder.append(" SUPPORTS_VT_LOCAL");
         }
-        if ((capabilities & SUPPORTS_VT_REMOTE) != 0) {
+        if (can(capabilities, SUPPORTS_VT_REMOTE)) {
             builder.append(" SUPPORTS_VT_REMOTE");
         }
-        if ((capabilities & VoLTE) != 0) {
+        if (can(capabilities, VoLTE)) {
             builder.append(" VoLTE");
         }
-        if ((capabilities & VoWIFI) != 0) {
+        if (can(capabilities, VoWIFI)) {
             builder.append(" VoWIFI");
         }
         builder.append("]");
diff --git a/telecomm/java/android/telecom/RemoteConference.java b/telecomm/java/android/telecom/RemoteConference.java
index b548274..eba7580 100644
--- a/telecomm/java/android/telecom/RemoteConference.java
+++ b/telecomm/java/android/telecom/RemoteConference.java
@@ -18,7 +18,6 @@
 
 import com.android.internal.telecom.IConnectionService;
 
-import android.annotation.SystemApi;
 import android.os.RemoteException;
 
 import java.util.ArrayList;
@@ -30,9 +29,7 @@
 
 /**
  * Represents a conference call which can contain any number of {@link Connection} objects.
- * @hide
  */
-@SystemApi
 public final class RemoteConference {
 
     public abstract static class Callback {
diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
index 4a89692..9a094df 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -20,7 +20,6 @@
 import com.android.internal.telecom.IVideoCallback;
 import com.android.internal.telecom.IVideoProvider;
 
-import android.annotation.SystemApi;
 import android.net.Uri;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -38,9 +37,7 @@
  *
  * @see ConnectionService#createRemoteOutgoingConnection(PhoneAccountHandle, ConnectionRequest)
  * @see ConnectionService#createRemoteIncomingConnection(PhoneAccountHandle, ConnectionRequest)
- * @hide
  */
-@SystemApi
 public final class RemoteConnection {
 
     public static abstract class Callback {
diff --git a/telecomm/java/android/telecom/StatusHints.java b/telecomm/java/android/telecom/StatusHints.java
index dd3a639..a32eae7 100644
--- a/telecomm/java/android/telecom/StatusHints.java
+++ b/telecomm/java/android/telecom/StatusHints.java
@@ -16,7 +16,6 @@
 
 package android.telecom;
 
-import android.annotation.SystemApi;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -30,9 +29,7 @@
 
 /**
  * Contains status label and icon displayed in the in-call UI.
- * @hide
  */
-@SystemApi
 public final class StatusHints implements Parcelable {
 
     private final ComponentName mPackageName;
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index e87615e..ed221d2 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -60,7 +60,6 @@
     /**
      * The {@link android.content.Intent} action used to configure a
      * {@link android.telecom.ConnectionService}.
-     * @hide
      */
     public static final String ACTION_CONNECTION_SERVICE_CONFIGURE =
             "android.telecom.action.CONNECTION_SERVICE_CONFIGURE";
@@ -74,7 +73,6 @@
     /**
      * The {@link android.content.Intent} action used to show the settings page used to configure
      * {@link PhoneAccount} preferences.
-     * @hide
      */
     public static final String ACTION_CHANGE_PHONE_ACCOUNTS =
             "android.telecom.action.CHANGE_PHONE_ACCOUNTS";
@@ -105,7 +103,6 @@
      * {@link PhoneAccountHandle} to use when making the call.
      * <p class="note">
      * Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
-     * @hide
      */
     public static final String EXTRA_PHONE_ACCOUNT_HANDLE =
             "android.telecom.extra.PHONE_ACCOUNT_HANDLE";
@@ -154,7 +151,6 @@
     /**
      * Optional extra for {@link android.telephony.TelephonyManager#ACTION_PHONE_STATE_CHANGED}
      * containing the component name of the associated connection service.
-     * @hide
      */
     public static final String EXTRA_CONNECTION_SERVICE =
             "android.telecom.extra.CONNECTION_SERVICE";
@@ -190,7 +186,6 @@
      * {@link ConnectionService}s which interact with {@link RemoteConnection}s should only populate
      * this if the {@link android.telephony.TelephonyManager#getLine1Number()} value, as that is the
      * user's expected caller ID.
-     * @hide
      */
     public static final String EXTRA_CALL_BACK_NUMBER = "android.telecom.extra.CALL_BACK_NUMBER";
 
@@ -437,7 +432,6 @@
      * {@code PhoneAccount}.
      *
      * @return The phone account handle of the current connection manager.
-     * @hide
      */
     public PhoneAccountHandle getConnectionManager() {
         return getSimCallManager();
@@ -495,7 +489,6 @@
      *
      * @return {@code true} if the device has more than one account registered and {@code false}
      * otherwise.
-     * @hide
      */
     public boolean hasMultipleCallCapableAccounts() {
         return getCallCapablePhoneAccounts().size() > 1;
@@ -505,7 +498,6 @@
      *  Returns a list of all {@link PhoneAccount}s registered for the calling package.
      *
      * @return A list of {@code PhoneAccountHandle} objects.
-     * @hide
      */
     public List<PhoneAccountHandle> getPhoneAccountsForPackage() {
         try {
@@ -524,7 +516,6 @@
      *
      * @param account The {@link PhoneAccountHandle}.
      * @return The {@link PhoneAccount} object.
-     * @hide
      */
     public PhoneAccount getPhoneAccount(PhoneAccountHandle account) {
         try {
@@ -595,7 +586,6 @@
      * Register a {@link PhoneAccount} for use by the system.
      *
      * @param account The complete {@link PhoneAccount}.
-     * @hide
      */
     @SystemApi
     public void registerPhoneAccount(PhoneAccount account) {
@@ -612,7 +602,6 @@
      * Remove a {@link PhoneAccount} registration from the system.
      *
      * @param accountHandle A {@link PhoneAccountHandle} for the {@link PhoneAccount} to unregister.
-     * @hide
      */
     @SystemApi
     public void unregisterPhoneAccount(PhoneAccountHandle accountHandle) {
@@ -627,7 +616,6 @@
 
     /**
      * Remove all Accounts that belong to the calling package from the system.
-     * @hide
      */
     @SystemApi
     public void clearAccounts() {
@@ -834,7 +822,6 @@
      *            {@link #registerPhoneAccount}.
      * @param extras A bundle that will be passed through to
      *            {@link ConnectionService#onCreateIncomingConnection}.
-     * @hide
      */
     @SystemApi
     public void addNewIncomingCall(PhoneAccountHandle phoneAccount, Bundle extras) {
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 52d0516..8c2a4eb 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -864,4 +864,23 @@
                 || radioTechnology == RIL_RADIO_TECHNOLOGY_EVDO_B
                 || radioTechnology == RIL_RADIO_TECHNOLOGY_EHRPD;
     }
+
+    /**
+     * Returns a merged ServiceState consisting of the base SS with voice settings from the
+     * voice SS. The voice SS is only used if it is IN_SERVICE (otherwise the base SS is returned).
+     * @hide
+     * */
+    public static ServiceState mergeServiceStates(ServiceState baseSs, ServiceState voiceSs) {
+        if (voiceSs.mVoiceRegState != STATE_IN_SERVICE) {
+            return baseSs;
+        }
+
+        ServiceState newSs = new ServiceState(baseSs);
+
+        // voice overrides
+        newSs.mVoiceRegState = voiceSs.mVoiceRegState;
+        newSs.mIsEmergencyOnly = false; // only get here if voice is IN_SERVICE
+
+        return newSs;
+    }
 }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index b72a920..7b5234a 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -669,6 +669,32 @@
     }
 
     /**
+     * Returns the NAI. Return null if NAI is not available.
+     *
+     */
+    /** {@hide}*/
+    public String getNai() {
+        return getNai(getDefaultSim());
+    }
+
+    /**
+     * Returns the NAI. Return null if NAI is not available.
+     *
+     *  @param slotId of which Nai is returned
+     */
+    /** {@hide}*/
+    public String getNai(int slotId) {
+        long[] subId = SubscriptionManager.getSubId(slotId);
+        try {
+            return getSubscriberInfo().getNaiForSubscriber(subId[0]);
+        } catch (RemoteException ex) {
+            return null;
+        } catch (NullPointerException ex) {
+            return null;
+        }
+    }
+
+    /**
      * Returns the current location of the device.
      *<p>
      * If there is only one radio in the device and that radio has an LTE connection,
@@ -1778,7 +1804,6 @@
      *
      * @param alphaTag alpha-tagging of the dailing nubmer
      * @param number The dialing number
-     * @hide
      */
     public void setLine1NumberForDisplay(String alphaTag, String number) {
         setLine1NumberForDisplayForSubscriber(getDefaultSubscription(), alphaTag, number);
@@ -2423,6 +2448,7 @@
      *
      * <p>Requires Permission:
      *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
      *
      * @param AID Application id. See ETSI 102.221 and 101.220.
      * @return an IccOpenLogicalChannelResponse object.
@@ -2443,6 +2469,7 @@
      *
      * <p>Requires Permission:
      *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
      *
      * @param channel is the channel id to be closed as retruned by a successful
      *            iccOpenLogicalChannel.
@@ -2464,6 +2491,7 @@
      *
      * <p>Requires Permission:
      *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
      *
      * @param channel is the channel id to be closed as returned by a successful
      *            iccOpenLogicalChannel.
@@ -2495,6 +2523,7 @@
      *
      * <p>Requires Permission:
      *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
      *
      * @param cla Class of the APDU command.
      * @param instruction Instruction of the APDU command.
@@ -2522,6 +2551,7 @@
      *
      * <p>Requires Permission:
      *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
      *
      * @param fileID
      * @param command
@@ -2547,6 +2577,7 @@
      *
      * <p>Requires Permission:
      *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
      *
      * @param content String containing SAT/USAT response in hexadecimal
      *                format starting with command tag. See TS 102 223 for
@@ -3011,7 +3042,6 @@
      * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
      *
      * @return true on success; false on any failure.
-     * @hide
      */
     public boolean setGlobalPreferredNetworkType() {
         return setPreferredNetworkType(RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA);
@@ -3019,23 +3049,10 @@
 
     /**
      * Values used to return status for hasCarrierPrivileges call.
-     * @hide
      */
     public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1;
-    /**
-     * Values used to return status for hasCarrierPrivileges call.
-     * @hide
-     */
     public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0;
-    /**
-     * Values used to return status for hasCarrierPrivileges call.
-     * @hide
-     */
     public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1;
-    /**
-     * Values used to return status for hasCarrierPrivileges call.
-     * @hide
-     */
     public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2;
 
     /**
@@ -3052,7 +3069,6 @@
      *         CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED if the carrier rules are not loaded.
      *         CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES if there was an error loading carrier
      *             rules (or if there are no rules).
-     * @hide
      */
     public int hasCarrierPrivileges() {
         try {
@@ -3079,7 +3095,6 @@
      *
      * @param brand The brand name to display/set.
      * @return true if the operation was executed correctly.
-     * @hide
      */
     public boolean setOperatorBrandOverride(String brand) {
         try {
@@ -3513,4 +3528,25 @@
         }
         return -1;
     }
+
+    /** @hide */
+    @SystemApi
+    public void enableVideoCalling(boolean enable) {
+        try {
+            getITelephony().enableVideoCalling(enable);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#enableVideoCalling", e);
+        }
+    }
+
+    /** @hide */
+    @SystemApi
+    public boolean isVideoCallingEnabled() {
+        try {
+            return getITelephony().isVideoCallingEnabled();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#isVideoCallingEnabled", e);
+        }
+        return false;
+    }
 }
diff --git a/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl b/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl
index acd1eb9..11da6e6 100644
--- a/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl
+++ b/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl
@@ -104,4 +104,14 @@
             in int srcAccessTech, in int targetAccessTech, in ImsReasonInfo reasonInfo);
     void callSessionHandoverFailed(in IImsCallSession session,
             in int srcAccessTech, in int targetAccessTech, in ImsReasonInfo reasonInfo);
+
+    /**
+     * Notifies the TTY mode change by remote party.
+     * @param mode one of the following:
+     * - {@link com.android.internal.telephony.Phone#TTY_MODE_OFF}
+     * - {@link com.android.internal.telephony.Phone#TTY_MODE_FULL}
+     * - {@link com.android.internal.telephony.Phone#TTY_MODE_HCO}
+     * - {@link com.android.internal.telephony.Phone#TTY_MODE_VCO}
+     */
+    void callSessionTtyModeReceived(in IImsCallSession session, in int mode);
 }
diff --git a/telephony/java/com/android/ims/internal/IImsConfig.aidl b/telephony/java/com/android/ims/internal/IImsConfig.aidl
index e8d921e..c5ccf5f 100644
--- a/telephony/java/com/android/ims/internal/IImsConfig.aidl
+++ b/telephony/java/com/android/ims/internal/IImsConfig.aidl
@@ -73,9 +73,9 @@
      *
      * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
      * @param value in Integer format.
-     * @return void.
+     * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants.
      */
-    void setProvisionedValue(int item, int value);
+    int setProvisionedValue(int item, int value);
 
     /**
      * Sets the value for IMS service/capabilities parameters by the operator device
@@ -84,9 +84,9 @@
      *
      * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
      * @param value in String format.
-     * @return void.
+     * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants.
      */
-    void setProvisionedStringValue(int item, String value);
+    int setProvisionedStringValue(int item, String value);
 
     /**
      * Gets the value of the specified IMS feature item for specified network type.
diff --git a/telephony/java/com/android/ims/internal/IImsService.aidl b/telephony/java/com/android/ims/internal/IImsService.aidl
index 5138305..b9cee42 100644
--- a/telephony/java/com/android/ims/internal/IImsService.aidl
+++ b/telephony/java/com/android/ims/internal/IImsService.aidl
@@ -26,6 +26,8 @@
 import com.android.ims.internal.IImsUt;
 import com.android.ims.internal.IImsConfig;
 
+import android.os.Message;
+
 /**
  * {@hide}
  */
@@ -64,10 +66,13 @@
      */
     void turnOffIms();
 
-
     /**
      * ECBM interface for Emergency Callback mode mechanism.
      */
     IImsEcbm getEcbmInterface(int serviceId);
 
+   /**
+     * Used to set current TTY Mode.
+     */
+    void setUiTTYMode(int serviceId, int uiTtyMode, in Message onComplete);
 }
diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
index d706203..98fd70c 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
@@ -27,6 +27,11 @@
      */
     String getDeviceId();
 
+     /**
+     * Retrieves the unique Network Access ID
+     */
+    String getNaiForSubscriber(long subId);
+
     /**
      * Retrieves the unique device ID of a subId for the device, e.g., IMEI
      * for GSM phones.
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 58807b2..b4d165c 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -28,7 +28,7 @@
 /**
  * Interface used to interact with the phone.  Mostly this is used by the
  * TelephonyManager class.  A few places are still using this directly.
- * Please clean them up if possible and use TelephonyManager insteadl.
+ * Please clean them up if possible and use TelephonyManager instead.
  *
  * {@hide}
  */
@@ -831,4 +831,18 @@
      * @return phone radio type and access technology
      */
     int getRadioAccessFamily(in int phoneId);
+
+    /**
+     * Enables or disables video calling.
+     *
+     * @param enable Whether to enable video calling.
+     */
+    void enableVideoCalling(boolean enable);
+
+    /**
+     * Whether video calling has been enabled by the user.
+     *
+     * @return {@code True} if the user has enabled video calling, {@code false} otherwise.
+     */
+    boolean isVideoCallingEnabled();
 }
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index d093a29..b5e82e3 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -161,6 +161,7 @@
     public static final int DATA_PROFILE_FOTA      = 3;
     public static final int DATA_PROFILE_CBS       = 4;
     public static final int DATA_PROFILE_OEM_BASE  = 1000;
+    public static final int DATA_PROFILE_INVALID   = 0xFFFFFFFF;
 
     int RIL_REQUEST_GET_SIM_STATUS = 1;
     int RIL_REQUEST_ENTER_SIM_PIN = 2;
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index afe1d5d..7f1dc71 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -793,4 +793,11 @@
     public Drawable loadItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo) {
         throw new UnsupportedOperationException();
     }
+
+    /**
+     * @hide
+     */
+    public Drawable loadUnbadgedItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo) {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/tests/VectorDrawableTest/AndroidManifest.xml b/tests/VectorDrawableTest/AndroidManifest.xml
index 7796953..991ec57 100644
--- a/tests/VectorDrawableTest/AndroidManifest.xml
+++ b/tests/VectorDrawableTest/AndroidManifest.xml
@@ -18,7 +18,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.test.dynamic" >
 
-    <uses-sdk android:minSdkVersion="20" />
+    <uses-sdk android:minSdkVersion="21" />
 
     <application
         android:hardwareAccelerated="true"
diff --git a/tests/VectorDrawableTest/res/anim/alpha_animation_progress_bar.xml b/tests/VectorDrawableTest/res/anim/alpha_animation_progress_bar.xml
new file mode 100644
index 0000000..867abc7
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/alpha_animation_progress_bar.xml
@@ -0,0 +1,24 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <objectAnimator
+        android:duration="1350"
+        android:propertyName="alpha"
+        android:valueFrom="1"
+        android:valueTo="0.2" />
+
+</set>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/anim/ic_bluethooth_v2_animation_dot_left.xml b/tests/VectorDrawableTest/res/anim/ic_bluethooth_v2_animation_dot_left.xml
new file mode 100644
index 0000000..b465ead
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/ic_bluethooth_v2_animation_dot_left.xml
@@ -0,0 +1,61 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="200"
+            android:propertyName="scaleX"
+            android:valueFrom="1"
+            android:valueTo="1"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="350"
+            android:propertyName="scaleX"
+            android:valueFrom="1"
+            android:valueTo="0"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="200"
+            android:propertyName="scaleY"
+            android:valueFrom="1"
+            android:valueTo="1"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="350"
+            android:propertyName="scaleY"
+            android:valueFrom="1"
+            android:valueTo="0"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="200"
+            android:propertyName="rotation"
+            android:valueFrom="0"
+            android:valueTo="0"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="350"
+            android:propertyName="rotation"
+            android:valueFrom="0"
+            android:valueTo="-45"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+    </set>
+</set>
diff --git a/tests/VectorDrawableTest/res/anim/ic_bluethooth_v2_animation_dot_right.xml b/tests/VectorDrawableTest/res/anim/ic_bluethooth_v2_animation_dot_right.xml
new file mode 100644
index 0000000..49ac165
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/ic_bluethooth_v2_animation_dot_right.xml
@@ -0,0 +1,61 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="200"
+            android:propertyName="scaleX"
+            android:valueFrom="1"
+            android:valueTo="1"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="350"
+            android:propertyName="scaleX"
+            android:valueFrom="1"
+            android:valueTo="0"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="200"
+            android:propertyName="scaleY"
+            android:valueFrom="1"
+            android:valueTo="1"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="350"
+            android:propertyName="scaleY"
+            android:valueFrom="1"
+            android:valueTo="0"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="200"
+            android:propertyName="rotation"
+            android:valueFrom="0"
+            android:valueTo="0"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="350"
+            android:propertyName="rotation"
+            android:valueFrom="0"
+            android:valueTo="45"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+    </set>
+</set>
diff --git a/tests/VectorDrawableTest/res/anim/ic_bluethooth_v2_animation_ic_signal_wifi_4_bar_48px_outlines_.xml b/tests/VectorDrawableTest/res/anim/ic_bluethooth_v2_animation_ic_signal_wifi_4_bar_48px_outlines_.xml
new file mode 100644
index 0000000..1bdfde6
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/ic_bluethooth_v2_animation_ic_signal_wifi_4_bar_48px_outlines_.xml
@@ -0,0 +1,31 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="200"
+            android:propertyName="alpha"
+            android:valueFrom="1"
+            android:valueTo="1"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="350"
+            android:propertyName="alpha"
+            android:valueFrom="1"
+            android:valueTo="0.5"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+    </set>
+</set>
diff --git a/tests/VectorDrawableTest/res/anim/ic_bluethooth_v2_animation_mask.xml b/tests/VectorDrawableTest/res/anim/ic_bluethooth_v2_animation_mask.xml
new file mode 100644
index 0000000..47efa18
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/ic_bluethooth_v2_animation_mask.xml
@@ -0,0 +1,33 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="200"
+            android:propertyName="pathData"
+            android:valueFrom="M 37.8337860107 -40.4599914551 c 0.0 0.0 -35.8077850342 30.0523681641 -35.8077850342 30.0523681641 c 0.0 0.0 12.925994873 12.9778747559 12.925994873 12.9778747559 c 0.0 0.0 -2.61700439453 2.09387207031 -2.61700439453 2.09387207031 c 0.0 0.0 -13.1259613037 -12.9893035889 -13.1259613037 -12.9893035889 c 0.0 0.0 -34.6200408936 26.9699249268 -34.6200408936 26.9699249268 c 0.0 0.0 55.9664764404 69.742401123 55.9664764404 69.742401123 c 0.0 0.0 73.2448120117 -59.1047973633 73.2448120117 -59.1047973633 c 0.0 0.0 -55.9664916992 -69.7423400879 -55.9664916992 -69.7423400879 Z"
+            android:valueTo="M 37.8337860107 -40.4599914551 c 0.0 0.0 -35.8077850342 30.0523681641 -35.8077850342 30.0523681641 c 0.0 0.0 12.925994873 12.9778747559 12.925994873 12.9778747559 c 0.0 0.0 -2.61700439453 2.09387207031 -2.61700439453 2.09387207031 c 0.0 0.0 -13.1259613037 -12.9893035889 -13.1259613037 -12.9893035889 c 0.0 0.0 -34.6200408936 26.9699249268 -34.6200408936 26.9699249268 c 0.0 0.0 55.9664764404 69.742401123 55.9664764404 69.742401123 c 0.0 0.0 73.2448120117 -59.1047973633 73.2448120117 -59.1047973633 c 0.0 0.0 -55.9664916992 -69.7423400879 -55.9664916992 -69.7423400879 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="133"
+            android:propertyName="pathData"
+            android:valueFrom="M 37.8337860107 -40.4599914551 c 0.0 0.0 -35.8077850342 30.0523681641 -35.8077850342 30.0523681641 c 0.0 0.0 12.925994873 12.9778747559 12.925994873 12.9778747559 c 0.0 0.0 -2.61700439453 2.09387207031 -2.61700439453 2.09387207031 c 0.0 0.0 -13.1259613037 -12.9893035889 -13.1259613037 -12.9893035889 c 0.0 0.0 -34.6200408936 26.9699249268 -34.6200408936 26.9699249268 c 0.0 0.0 55.9664764404 69.742401123 55.9664764404 69.742401123 c 0.0 0.0 73.2448120117 -59.1047973633 73.2448120117 -59.1047973633 c 0.0 0.0 -55.9664916992 -69.7423400879 -55.9664916992 -69.7423400879 Z"
+            android:valueTo="M 37.8337860107 -40.4599914551 c 0.0 0.0 -35.8077850342 29.7398681641 -35.8077850342 29.7398681641 c 0.0 0.0 27.2634735107 27.4966583252 27.2634735107 27.4966583252 c 0.0 0.0 -2.61700439453 2.4063873291 -2.61700439453 2.4063873291 c 0.0 0.0 -27.4634399414 -27.508102417 -27.4634399414 -27.508102417 c 0.0 0.0 -34.6200408936 26.9699249268 -34.6200408936 26.9699249268 c 0.0 0.0 55.9664764404 69.742401123 55.9664764404 69.742401123 c 0.0 0.0 73.2448120117 -59.1047973633 73.2448120117 -59.1047973633 c 0.0 0.0 -55.9664916992 -69.7423400879 -55.9664916992 -69.7423400879 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+    </set>
+</set>
diff --git a/tests/VectorDrawableTest/res/anim/ic_bluethooth_v2_animation_path_1.xml b/tests/VectorDrawableTest/res/anim/ic_bluethooth_v2_animation_path_1.xml
new file mode 100644
index 0000000..41fe866
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/ic_bluethooth_v2_animation_path_1.xml
@@ -0,0 +1,33 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="200"
+            android:propertyName="pathData"
+            android:valueFrom="M 10.6188659668 6.56344604492 c 0.0 0.0 21.7386016846 23.1297454834 21.7386016846 23.1297454834 "
+            android:valueTo="M 10.6188659668 6.56344604492 c 0.0 0.0 21.7386016846 23.1297454834 21.7386016846 23.1297454834 "
+            android:valueType="pathType"
+            android:interpolator="@interpolator/ic_bluethooth_v2_path_1_pathdata_interpolator" />
+        <objectAnimator
+            android:duration="350"
+            android:propertyName="pathData"
+            android:valueFrom="M 10.6188659668 6.56344604492 c 0.0 0.0 21.7386016846 23.1297454834 21.7386016846 23.1297454834 "
+            android:valueTo="M 8.62858581543 4.33430480957 c 0.0 0.0 28.1998138428 30.2359008789 28.1998138428 30.2359008789 "
+            android:valueType="pathType"
+            android:interpolator="@interpolator/ic_bluethooth_v2_path_1_pathdata_interpolator" />
+    </set>
+</set>
diff --git a/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_frame.xml b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_frame.xml
new file mode 100644
index 0000000..9cea85d
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_frame.xml
@@ -0,0 +1,31 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="367"
+            android:propertyName="alpha"
+            android:valueFrom="0.5"
+            android:valueTo="0.5"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="333"
+            android:propertyName="alpha"
+            android:valueFrom="0.5"
+            android:valueTo="1"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+    </set>
+</set>
diff --git a/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_screen.xml b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_screen.xml
new file mode 100644
index 0000000..61b018b
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_screen.xml
@@ -0,0 +1,31 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="367"
+            android:propertyName="alpha"
+            android:valueFrom="0"
+            android:valueTo="0"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="333"
+            android:propertyName="alpha"
+            android:valueFrom="0"
+            android:valueTo="1"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+    </set>
+</set>
diff --git a/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_wave1.xml b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_wave1.xml
new file mode 100644
index 0000000..002f7b2
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_wave1.xml
@@ -0,0 +1,33 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="200"
+            android:propertyName="pathData"
+            android:valueFrom="M 0 -4.0 a 4 4 0 0 1 4 4 a 4 4 0 0 1 -4 4 a 4 4 0 0 1 -4 -4 a 4 4 0 0 1 4 -4 Z"
+            android:valueTo="M 0 -4.0 a 4 4 0 0 1 4 4 a 4 4 0 0 1 -4 4 a 4 4 0 0 1 -4 -4 a 4 4 0 0 1 4 -4 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="500"
+            android:propertyName="pathData"
+            android:valueFrom="M 0 -4.0 a 4 4 0 0 1 4 4 a 4 4 0 0 1 -4 4 a 4 4 0 0 1 -4 -4 a 4 4 0 0 1 4 -4 Z"
+            android:valueTo="M 0 -20.0 a 20 20 0 0 1 20 20 a 20 20 0 0 1 -20 20 a 20 20 0 0 1 -20 -20 a 20 20 0 0 1 20 -20 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+    </set>
+</set>
diff --git a/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_wave2.xml b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_wave2.xml
new file mode 100644
index 0000000..0c2ee21
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_wave2.xml
@@ -0,0 +1,33 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="200"
+            android:propertyName="pathData"
+            android:valueFrom="M 0 -12.0 a 12 12 0 0 1 12 12 a 12 12 0 0 1 -12 12 a 12 12 0 0 1 -12 -12 a 12 12 0 0 1 12 -12 Z"
+            android:valueTo="M 0 -12.0 a 12 12 0 0 1 12 12 a 12 12 0 0 1 -12 12 a 12 12 0 0 1 -12 -12 a 12 12 0 0 1 12 -12 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="333"
+            android:propertyName="pathData"
+            android:valueFrom="M 0 -12.0 a 12 12 0 0 1 12 12 a 12 12 0 0 1 -12 12 a 12 12 0 0 1 -12 -12 a 12 12 0 0 1 12 -12 Z"
+            android:valueTo="M 0 -20.0 a 20 20 0 0 1 20 20 a 20 20 0 0 1 -20 20 a 20 20 0 0 1 -20 -20 a 20 20 0 0 1 20 -20 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+    </set>
+</set>
diff --git a/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_wave3.xml b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_wave3.xml
new file mode 100644
index 0000000..a75b2eaf
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_wave3.xml
@@ -0,0 +1,33 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="200"
+            android:propertyName="pathData"
+            android:valueFrom="M 0 -20.0 a 20 20 0 0 1 20 20 a 20 20 0 0 1 -20 20 a 20 20 0 0 1 -20 -20 a 20 20 0 0 1 20 -20 Z"
+            android:valueTo="M 0 -20.0 a 20 20 0 0 1 20 20 a 20 20 0 0 1 -20 20 a 20 20 0 0 1 -20 -20 a 20 20 0 0 1 20 -20 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="167"
+            android:propertyName="pathData"
+            android:valueFrom="M 0 -20.0 a 20 20 0 0 1 20 20 a 20 20 0 0 1 -20 20 a 20 20 0 0 1 -20 -20 a 20 20 0 0 1 20 -20 Z"
+            android:valueTo="M 0 -20.0 a 20 20 0 0 1 20 20 a 20 20 0 0 1 -20 20 a 20 20 0 0 1 -20 -20 a 20 20 0 0 1 20 -20 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+    </set>
+</set>
diff --git a/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_wave5.xml b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_wave5.xml
new file mode 100644
index 0000000..7e79b94
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_wave5.xml
@@ -0,0 +1,33 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="200"
+            android:propertyName="pathData"
+            android:valueFrom="M 0 -0.0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 Z"
+            android:valueTo="M 0 -0.0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="500"
+            android:propertyName="pathData"
+            android:valueFrom="M 0 -0.0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 Z"
+            android:valueTo="M 0 -12.0 a 12 12 0 0 1 12 12 a 12 12 0 0 1 -12 12 a 12 12 0 0 1 -12 -12 a 12 12 0 0 1 12 -12 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+    </set>
+</set>
diff --git a/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_wave6.xml b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_wave6.xml
new file mode 100644
index 0000000..0917e0e
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_wave6.xml
@@ -0,0 +1,33 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="200"
+            android:propertyName="pathData"
+            android:valueFrom="M 0 -0.0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 Z"
+            android:valueTo="M 0 -0.0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="333"
+            android:propertyName="pathData"
+            android:valueFrom="M 0 -0.0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 Z"
+            android:valueTo="M 0 -4.0 a 4 4 0 0 1 4 4 a 4 4 0 0 1 -4 4 a 4 4 0 0 1 -4 -4 a 4 4 0 0 1 4 -4 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+    </set>
+</set>
diff --git a/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_waves.xml b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_waves.xml
new file mode 100644
index 0000000..9cea85d
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_waves.xml
@@ -0,0 +1,31 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="367"
+            android:propertyName="alpha"
+            android:valueFrom="0.5"
+            android:valueTo="0.5"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="333"
+            android:propertyName="alpha"
+            android:valueFrom="0.5"
+            android:valueTo="1"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+    </set>
+</set>
diff --git a/tests/VectorDrawableTest/res/anim/ic_hourglass_animation_fill_outlines.xml b/tests/VectorDrawableTest/res/anim/ic_hourglass_animation_fill_outlines.xml
new file mode 100644
index 0000000..17499d5
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/ic_hourglass_animation_fill_outlines.xml
@@ -0,0 +1,22 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="333"
+        android:propertyName="rotation"
+        android:valueFrom="0"
+        android:valueTo="180"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/tests/VectorDrawableTest/res/anim/ic_hourglass_animation_hourglass_frame.xml b/tests/VectorDrawableTest/res/anim/ic_hourglass_animation_hourglass_frame.xml
new file mode 100644
index 0000000..17499d5
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/ic_hourglass_animation_hourglass_frame.xml
@@ -0,0 +1,22 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="333"
+        android:propertyName="rotation"
+        android:valueFrom="0"
+        android:valueTo="180"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/tests/VectorDrawableTest/res/anim/ic_hourglass_animation_mask_1.xml b/tests/VectorDrawableTest/res/anim/ic_hourglass_animation_mask_1.xml
new file mode 100644
index 0000000..541792e
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/ic_hourglass_animation_mask_1.xml
@@ -0,0 +1,33 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="333"
+            android:propertyName="pathData"
+            android:valueFrom="M 24 13.3999938965 c 0 0.0 -24 0.0 -24 0.0 c 0 0.0 0 10.6000061035 0 10.6000061035 c 0 0 24 0 24 0 c 0 0 0 -10.6000061035 0 -10.6000061035 Z"
+            android:valueTo="M 24 13.3999938965 c 0 0.0 -24 0.0 -24 0.0 c 0 0.0 0 10.6000061035 0 10.6000061035 c 0 0 24 0 24 0 c 0 0 0 -10.6000061035 0 -10.6000061035 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="1000"
+            android:propertyName="pathData"
+            android:valueFrom="M 24 13.3999938965 c 0 0.0 -24 0.0 -24 0.0 c 0 0.0 0 10.6000061035 0 10.6000061035 c 0 0 24 0 24 0 c 0 0 0 -10.6000061035 0 -10.6000061035 Z"
+            android:valueTo="M 24 0.00173950195312 c 0 0.0 -24 0.0 -24 0.0 c 0 0.0 0 10.6982574463 0 10.6982574463 c 0 0.0 24 0.0 24 0.0 c 0 0.0 0 -10.6982574463 0 -10.6982574463 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+    </set>
+</set>
diff --git a/tests/VectorDrawableTest/res/anim/ic_open_animation_ball_start.xml b/tests/VectorDrawableTest/res/anim/ic_open_animation_ball_start.xml
new file mode 100644
index 0000000..c26c8ed
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/ic_open_animation_ball_start.xml
@@ -0,0 +1,86 @@
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="833"
+            android:propertyName="translateX"
+            android:valueFrom="144"
+            android:valueTo="144"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="100"
+            android:propertyName="translateX"
+            android:valueFrom="144"
+            android:valueTo="147.411817411"
+            android:interpolator="@interpolator/ic_open_ball_start_translatex_interpolator" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="167"
+            android:propertyName="translateY"
+            android:valueFrom="144.58457376"
+            android:valueTo="144.58457376"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="333"
+            android:propertyName="translateY"
+            android:valueFrom="144.58457376"
+            android:valueTo="196.11111456"
+            android:interpolator="@interpolator/ic_open_ball_start_translatey_interpolator_1" />
+        <objectAnimator
+            android:duration="333"
+            android:propertyName="translateY"
+            android:valueFrom="196.11111456"
+            android:valueTo="196.11111456"
+            android:interpolator="@interpolator/ic_open_ball_start_translatey_interpolator_2" />
+        <objectAnimator
+            android:duration="100"
+            android:propertyName="translateY"
+            android:valueFrom="196.11111456"
+            android:valueTo="129.468428513"
+            android:interpolator="@interpolator/ic_open_ball_start_translatey_interpolator_3" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="167"
+            android:propertyName="scaleX"
+            android:valueFrom="0"
+            android:valueTo="0.71187984"
+            android:interpolator="@interpolator/ic_open_ball_start_scalex_interpolator_1" />
+        <objectAnimator
+            android:duration="667"
+            android:propertyName="scaleX"
+            android:valueFrom="0.71187984"
+            android:valueTo="0.71187984"
+            android:interpolator="@interpolator/ic_open_ball_start_scalex_interpolator_2" />
+        <objectAnimator
+            android:duration="100"
+            android:propertyName="scaleX"
+            android:valueFrom="0.71187984"
+            android:valueTo="0.586201598553"
+            android:interpolator="@interpolator/ic_open_ball_start_scalex_interpolator_3" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="167"
+            android:propertyName="scaleY"
+            android:valueFrom="0"
+            android:valueTo="0.71187984"
+            android:interpolator="@interpolator/ic_open_ball_start_scaley_interpolator_1" />
+        <objectAnimator
+            android:duration="667"
+            android:propertyName="scaleY"
+            android:valueFrom="0.71187984"
+            android:valueTo="0.71187984"
+            android:interpolator="@interpolator/ic_open_ball_start_scaley_interpolator_2" />
+        <objectAnimator
+            android:duration="100"
+            android:propertyName="scaleY"
+            android:valueFrom="0.71187984"
+            android:valueTo="0.586201598553"
+            android:interpolator="@interpolator/ic_open_ball_start_scaley_interpolator_3" />
+    </set>
+</set>
diff --git a/tests/VectorDrawableTest/res/anim/ic_open_animation_ball_swoop.xml b/tests/VectorDrawableTest/res/anim/ic_open_animation_ball_swoop.xml
new file mode 100644
index 0000000..5096514
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/ic_open_animation_ball_swoop.xml
@@ -0,0 +1,17 @@
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="933"
+            android:propertyName="rotation"
+            android:valueFrom="-90"
+            android:valueTo="-90"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="1367"
+            android:propertyName="rotation"
+            android:valueFrom="-90"
+            android:valueTo="-87"
+            android:interpolator="@android:interpolator/linear" />
+    </set>
+</set>
diff --git a/tests/VectorDrawableTest/res/anim/ic_open_animation_path_1.xml b/tests/VectorDrawableTest/res/anim/ic_open_animation_path_1.xml
new file mode 100644
index 0000000..ef8496e
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/ic_open_animation_path_1.xml
@@ -0,0 +1,48 @@
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="500"
+            android:propertyName="pathData"
+            android:valueFrom="M 0,-17.3838043213 c -9.625,0.0 -17.0795440674,8.28025817871 -17.0795440674,17.4052734375 c 0.0,9.75645446777 7.51704406738,17.6295623779 17.0795440674,17.353515625 c 11.5579986572,-0.333648681641 17.2784118652,-8.72853088379 17.2784118652,-17.353515625 c 0.0,-8.62501525879 -7.65341186523,-17.4052734375 -17.2784118652,-17.4052734375 Z"
+            android:valueTo="M 0,-17.3838043213 c -9.625,0.0 -17.0795440674,8.28025817871 -17.0795440674,17.4052734375 c 0.0,9.75645446777 7.51704406738,17.6295623779 17.0795440674,17.353515625 c 11.5579986572,-0.333648681641 17.2784118652,-8.72853088379 17.2784118652,-17.353515625 c 0.0,-8.62501525879 -7.65341186523,-17.4052734375 -17.2784118652,-17.4052734375 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="267"
+            android:propertyName="pathData"
+            android:valueFrom="M 0,-17.3838043213 c -9.625,0.0 -17.0795440674,8.28025817871 -17.0795440674,17.4052734375 c 0.0,9.75645446777 7.51704406738,17.6295623779 17.0795440674,17.353515625 c 11.5579986572,-0.333648681641 17.2784118652,-8.72853088379 17.2784118652,-17.353515625 c 0.0,-8.62501525879 -7.65341186523,-17.4052734375 -17.2784118652,-17.4052734375 Z"
+            android:valueTo="M 0,-6 c -9.625,0 -23.5648803711,6.97859191895 -23.5648803711,16.1035919189 c 0.0,8.875 6.62738037109,8.39640808105 23.5648803711,8.39640808105 c 17.0625,0.0 23.8825073242,0.375 23.8825073242,-8.25 c 0.0,-8.625 -14.2574920654,-16.25 -23.8825073242,-16.25 Z"
+            android:valueType="pathType"
+            android:interpolator="@interpolator/ic_open_path_1_pathdata_interpolator_1" />
+        <objectAnimator
+            android:duration="33"
+            android:propertyName="pathData"
+            android:valueFrom="M 0,-6 c -9.625,0 -23.5648803711,6.97859191895 -23.5648803711,16.1035919189 c 0.0,8.875 6.62738037109,8.39640808105 23.5648803711,8.39640808105 c 17.0625,0.0 23.8825073242,0.375 23.8825073242,-8.25 c 0.0,-8.625 -14.2574920654,-16.25 -23.8825073242,-16.25 Z"
+            android:valueTo="M 0,-6 c -9.625,0 -23.5648803711,6.97859191895 -23.5648803711,16.1035919189 c 0.0,8.875 6.62738037109,8.39640808105 23.5648803711,8.39640808105 c 17.0625,0.0 23.8825073242,0.375 23.8825073242,-8.25 c 0.0,-8.625 -14.2574920654,-16.25 -23.8825073242,-16.25 Z"
+            android:valueType="pathType"
+            android:interpolator="@interpolator/ic_open_path_1_pathdata_interpolator_2" />
+        <objectAnimator
+            android:duration="67"
+            android:propertyName="pathData"
+            android:valueFrom="M 0,-6 c -9.625,0 -23.5648803711,6.97859191895 -23.5648803711,16.1035919189 c 0.0,8.875 6.62738037109,8.39640808105 23.5648803711,8.39640808105 c 17.0625,0.0 23.8825073242,0.375 23.8825073242,-8.25 c 0.0,-8.625 -14.2574920654,-16.25 -23.8825073242,-16.25 Z"
+            android:valueTo="M 0,-17.3838043213 c -9.625,0.0 -17.0795440674,8.28025817871 -17.0795440674,17.4052734375 c 0.0,9.75645446777 7.51704406738,17.6295623779 17.0795440674,17.353515625 c 11.5579986572,-0.333648681641 17.2784118652,-8.72853088379 17.2784118652,-17.353515625 c 0.0,-8.62501525879 -7.65341186523,-17.4052734375 -17.2784118652,-17.4052734375 Z"
+            android:valueType="pathType"
+            android:interpolator="@interpolator/ic_open_path_1_pathdata_interpolator_3" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="933"
+            android:propertyName="fillAlpha"
+            android:valueFrom="1"
+            android:valueTo="1"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="17"
+            android:propertyName="fillAlpha"
+            android:valueFrom="1"
+            android:valueTo="0"
+            android:interpolator="@android:interpolator/linear" />
+    </set>
+</set>
diff --git a/tests/VectorDrawableTest/res/anim/ic_open_animation_path_1_1.xml b/tests/VectorDrawableTest/res/anim/ic_open_animation_path_1_1.xml
new file mode 100644
index 0000000..4961204
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/ic_open_animation_path_1_1.xml
@@ -0,0 +1,74 @@
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="917"
+            android:propertyName="strokeAlpha"
+            android:valueFrom="0"
+            android:valueTo="0"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="17"
+            android:propertyName="strokeAlpha"
+            android:valueFrom="0"
+            android:valueTo="1"
+            android:interpolator="@android:interpolator/linear" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="917"
+            android:propertyName="strokeWidth"
+            android:valueFrom="0"
+            android:valueTo="0"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="17"
+            android:propertyName="strokeWidth"
+            android:valueFrom="0"
+            android:valueTo="20"
+            android:interpolator="@android:interpolator/linear" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="933"
+            android:propertyName="trimPathStart"
+            android:valueFrom="0.06"
+            android:valueTo="0.06"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="383"
+            android:propertyName="trimPathStart"
+            android:valueFrom="0.06"
+            android:valueTo="0.19231"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="983"
+            android:propertyName="trimPathStart"
+            android:valueFrom="0.19231"
+            android:valueTo="0.999"
+            android:interpolator="@interpolator/ic_open_path_1_1_trimpathstart_interpolator_2" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="933"
+            android:propertyName="trimPathEnd"
+            android:valueFrom="0.061"
+            android:valueTo="0.061"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="300"
+            android:propertyName="trimPathEnd"
+            android:valueFrom="0.061"
+            android:valueTo="0.19231"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="1067"
+            android:propertyName="trimPathEnd"
+            android:valueFrom="0.19231"
+            android:valueTo="1"
+            android:interpolator="@interpolator/ic_open_path_1_1_trimpathend_interpolator_2" />
+    </set>
+</set>
diff --git a/tests/VectorDrawableTest/res/anim/ic_rotate_2_portrait_v2_animation_arrows_1.xml b/tests/VectorDrawableTest/res/anim/ic_rotate_2_portrait_v2_animation_arrows_1.xml
new file mode 100644
index 0000000..496e3ed
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/ic_rotate_2_portrait_v2_animation_arrows_1.xml
@@ -0,0 +1,37 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="333"
+        android:startOffset="317"
+        android:propertyXName="scaleX"
+        android:propertyYName="scaleY"
+        android:pathData="M 1 1 l -0.1 -0.1 "
+        android:valueType="pathType"
+        android:interpolator="@interpolator/ic_rotate_2_portrait_v2_arrows_1_scalex_interpolator" />
+    <objectAnimator
+        android:duration="617"
+        android:startOffset="200"
+        android:propertyName="rotation"
+        android:valueFrom="0"
+        android:valueTo="-221"
+        android:interpolator="@interpolator/ic_rotate_2_portrait_v2_arrows_1_rotation_interpolator" />
+    <objectAnimator
+        android:duration="83"
+        android:startOffset="600"
+        android:propertyName="alpha"
+        android:valueFrom="1"
+        android:valueTo="0" />
+</set>
diff --git a/tests/VectorDrawableTest/res/anim/ic_rotate_2_portrait_v2_animation_device_1.xml b/tests/VectorDrawableTest/res/anim/ic_rotate_2_portrait_v2_animation_device_1.xml
new file mode 100644
index 0000000..47e1e71
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/ic_rotate_2_portrait_v2_animation_device_1.xml
@@ -0,0 +1,23 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="400"
+        android:startOffset="200"
+        android:propertyName="rotation"
+        android:valueFrom="0"
+        android:valueTo="-135"
+        android:interpolator="@interpolator/ic_rotate_2_portrait_v2_device_1_rotation_interpolator" />
+</set>
diff --git a/tests/VectorDrawableTest/res/anim/ic_rotate_2_portrait_v2_animation_device_2.xml b/tests/VectorDrawableTest/res/anim/ic_rotate_2_portrait_v2_animation_device_2.xml
new file mode 100644
index 0000000..f1126cf
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/ic_rotate_2_portrait_v2_animation_device_2.xml
@@ -0,0 +1,24 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="217"
+        android:startOffset="267"
+        android:propertyName="pathData"
+        android:valueFrom="M -3.5 -20.5 c -1.19999694824 -1.19999694824 -3.10000610352 -1.19999694824 -4.19999694824 0.0 c 0.0 0.0 -12.8000030518 12.6999969482 -12.8000030518 12.6999969482 c -1.19999694824 1.19999694824 -1.19999694824 3.10000610352 0.0 4.19999694824 c 0.0 0.0 24.0 24.0000152588 24.0 24.0000152588 c 1.19999694824 1.19999694824 3.10000610352 1.19999694824 4.19999694824 0.0 c 0.0 0.0 12.6999969482 -12.700012207 12.6999969482 -12.700012207 c 1.20001220703 -1.19999694824 1.20001220703 -3.09999084473 0.0 -4.19999694824 c 0.0 0.0 -23.8999938965 -24.0 -23.8999938965 -24.0 Z M 2.84999084473 15.5500183105 c 0.0 0.0 -18.6000061035 -18.5000457764 -18.6000061035 -18.5000457764 c 0.0 0.0 12.5999908447 -12.8000030518 12.5999908447 -12.8000030518 c 0.0 0.0 18.6000213623 18.5000457764 18.6000213623 18.5000457764 c 0.0 0.0 -12.6000061035 12.8000030518 -12.6000061035 12.8000030518 Z"
+        android:valueTo="M -3.34053039551 -22.9980926514 c -1.3207244873 -1.3207244873 -3.46876525879 -1.26383972168 -4.74829101563 0.125762939453 c 0.0 0.0 -14.8512420654 14.7411804199 -14.8512420654 14.7411804199 c -1.39259338379 1.392578125 -1.44947814941 3.54061889648 -0.125762939453 4.74827575684 c 0.0 0.0 26.4143981934 26.4144134521 26.4143981934 26.4144134521 c 1.3207244873 1.3207244873 3.46876525879 1.26382446289 4.74829101562 -0.125762939453 c 0.0 0.0 14.7381896973 -14.7381896973 14.7381896973 -14.7381896973 c 1.392578125 -1.39259338379 1.44947814941 -3.54061889648 0.125762939453 -4.74829101562 c 0.0 0.0 -26.3013458252 -26.417388916 -26.3013458252 -26.417388916 Z M 2.87156677246 16.9857940674 c 0.0 0.0 -19.7573547363 -19.7573699951 -19.7573547363 -19.7573699951 c 0.0 0.0 14.0142059326 -14.2142181396 14.0142059326 -14.2142181396 c 0.0 0.0 19.7573699951 19.7573699951 19.7573699951 19.7573699951 c 0.0 0.0 -14.0142211914 14.2142181396 -14.0142211914 14.2142181396 Z"
+        android:valueType="pathType"
+        android:interpolator="@interpolator/ic_rotate_2_portrait_v2_device_2_pathdata_interpolator" />
+</set>
diff --git a/tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_cross_1.xml b/tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_cross_1.xml
new file mode 100644
index 0000000..993493b
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_cross_1.xml
@@ -0,0 +1,31 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="200"
+            android:propertyName="alpha"
+            android:valueFrom="0"
+            android:valueTo="0"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="17"
+            android:propertyName="alpha"
+            android:valueFrom="0"
+            android:valueTo="1"
+            android:interpolator="@android:interpolator/linear" />
+    </set>
+</set>
diff --git a/tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_ic_signal_airplane.xml b/tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_ic_signal_airplane.xml
new file mode 100644
index 0000000..1bdfde6
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_ic_signal_airplane.xml
@@ -0,0 +1,31 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="200"
+            android:propertyName="alpha"
+            android:valueFrom="1"
+            android:valueTo="1"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="350"
+            android:propertyName="alpha"
+            android:valueFrom="1"
+            android:valueTo="0.5"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+    </set>
+</set>
diff --git a/tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_mask_2.xml b/tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_mask_2.xml
new file mode 100644
index 0000000..94b0a32
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_mask_2.xml
@@ -0,0 +1,33 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="200"
+            android:propertyName="pathData"
+            android:valueFrom="M 37.8337860107 -40.4599914551 c 0.0 0.0 -35.8077850342 31.5523681641 -35.8077850342 31.5523681641 c 0.0 0.0 9.55097961426 9.55285644531 9.55097961426 9.55285644531 c 0.0 0.0 -2.61698913574 2.09387207031 -2.61698913574 2.09387207031 c 0.0 0.0 -9.75096130371 -9.56428527832 -9.75096130371 -9.56428527832 c 0.0 0.0 -34.6200408936 25.4699249268 -34.6200408936 25.4699249268 c 0.0 0.0 55.9664764404 69.742401123 55.9664764404 69.742401123 c 0.0 0.0 73.2448120117 -59.1047973633 73.2448120117 -59.1047973633 c 0.0 0.0 -55.9664916992 -69.7423400879 -55.9664916992 -69.7423400879 Z"
+            android:valueTo="M 37.8337860107 -40.4599914551 c 0.0 0.0 -35.8077850342 31.5523681641 -35.8077850342 31.5523681641 c 0.0 0.0 9.55097961426 9.55285644531 9.55097961426 9.55285644531 c 0.0 0.0 -2.61698913574 2.09387207031 -2.61698913574 2.09387207031 c 0.0 0.0 -9.75096130371 -9.56428527832 -9.75096130371 -9.56428527832 c 0.0 0.0 -34.6200408936 25.4699249268 -34.6200408936 25.4699249268 c 0.0 0.0 55.9664764404 69.742401123 55.9664764404 69.742401123 c 0.0 0.0 73.2448120117 -59.1047973633 73.2448120117 -59.1047973633 c 0.0 0.0 -55.9664916992 -69.7423400879 -55.9664916992 -69.7423400879 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="350"
+            android:propertyName="pathData"
+            android:valueFrom="M 37.8337860107 -40.4599914551 c 0.0 0.0 -35.8077850342 31.5523681641 -35.8077850342 31.5523681641 c 0.0 0.0 9.55097961426 9.55285644531 9.55097961426 9.55285644531 c 0.0 0.0 -2.61698913574 2.09387207031 -2.61698913574 2.09387207031 c 0.0 0.0 -9.75096130371 -9.56428527832 -9.75096130371 -9.56428527832 c 0.0 0.0 -34.6200408936 25.4699249268 -34.6200408936 25.4699249268 c 0.0 0.0 55.9664764404 69.742401123 55.9664764404 69.742401123 c 0.0 0.0 73.2448120117 -59.1047973633 73.2448120117 -59.1047973633 c 0.0 0.0 -55.9664916992 -69.7423400879 -55.9664916992 -69.7423400879 Z"
+            android:valueTo="M 37.8337860107 -40.3974914551 c 0.0 0.0 -35.8077850342 31.5523681641 -35.8077850342 31.5523681641 c 0.0 0.0 40.9884796143 40.9278411865 40.9884796143 40.9278411865 c 0.0 0.0 -2.61700439453 2.0938873291 -2.61700439453 2.0938873291 c 0.0 0.0 -41.1884460449 -40.9392852783 -41.1884460449 -40.9392852783 c 0.0 0.0 -34.6200408936 25.4699249268 -34.6200408936 25.4699249268 c 0.0 0.0 55.9664764404 69.742401123 55.9664764404 69.742401123 c 0.0 0.0 73.2448120117 -59.1047973633 73.2448120117 -59.1047973633 c 0.0 0.0 -55.9664916992 -69.7423400879 -55.9664916992 -69.7423400879 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+    </set>
+</set>
diff --git a/tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_path_1_1.xml b/tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_path_1_1.xml
new file mode 100644
index 0000000..0a4a7c4
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_path_1_1.xml
@@ -0,0 +1,33 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="200"
+            android:propertyName="pathData"
+            android:valueFrom="M 7.54049682617 3.9430847168 c 0.0 0.0 0.324981689453 0.399978637695 0.324981689453 0.399978637695 "
+            android:valueTo="M 7.54049682617 3.9430847168 c 0.0 0.0 0.324981689453 0.399978637695 0.324981689453 0.399978637695 "
+            android:valueType="pathType"
+            android:interpolator="@interpolator/ic_signal_airplane_v2_path_1_1_pathdata_interpolator" />
+        <objectAnimator
+            android:duration="350"
+            android:propertyName="pathData"
+            android:valueFrom="M 7.54049682617 3.9430847168 c 0.0 0.0 0.324981689453 0.399978637695 0.324981689453 0.399978637695 "
+            android:valueTo="M 7.54049682617 3.9430847168 c 0.0 0.0 31.5749816895 31.4499664307 31.5749816895 31.4499664307 "
+            android:valueType="pathType"
+            android:interpolator="@interpolator/ic_signal_airplane_v2_path_1_1_pathdata_interpolator" />
+    </set>
+</set>
diff --git a/tests/VectorDrawableTest/res/drawable/animation_vector_progress_bar.xml b/tests/VectorDrawableTest/res/drawable/animation_vector_progress_bar.xml
index 6621e41..4d46ee8 100644
--- a/tests/VectorDrawableTest/res/drawable/animation_vector_progress_bar.xml
+++ b/tests/VectorDrawableTest/res/drawable/animation_vector_progress_bar.xml
@@ -19,5 +19,7 @@
     <target
         android:name="pie1"
         android:animation="@anim/trim_path_animation_progress_bar" />
-
+    <target
+        android:name="root_bar"
+        android:animation="@anim/alpha_animation_progress_bar" />
 </animated-vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/ic_bluethooth_v2.xml b/tests/VectorDrawableTest/res/drawable/ic_bluethooth_v2.xml
new file mode 100644
index 0000000..5f068fc
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/ic_bluethooth_v2.xml
@@ -0,0 +1,81 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="48dp"
+    android:width="48dp"
+    android:viewportHeight="48"
+    android:viewportWidth="48"
+    android:name="root_bt">
+    <group
+        android:name="ic_signal_wifi_4_bar_48px_outlines_"
+        android:translateX="21.9995"
+        android:translateY="25.73401" >
+        <group
+            android:name="ic_signal_wifi_4_bar_48px_outlines__pivot"
+            android:translateX="-23.21545"
+            android:translateY="-18.86649" >
+            <clip-path
+                android:name="mask"
+                android:pathData="M 37.8337860107 -40.4599914551 c 0.0 0.0 -35.8077850342 30.0523681641 -35.8077850342 30.0523681641 c 0.0 0.0 12.925994873 12.9778747559 12.925994873 12.9778747559 c 0.0 0.0 -2.61700439453 2.09387207031 -2.61700439453 2.09387207031 c 0.0 0.0 -13.1259613037 -12.9893035889 -13.1259613037 -12.9893035889 c 0.0 0.0 -34.6200408936 26.9699249268 -34.6200408936 26.9699249268 c 0.0 0.0 55.9664764404 69.742401123 55.9664764404 69.742401123 c 0.0 0.0 73.2448120117 -59.1047973633 73.2448120117 -59.1047973633 c 0.0 0.0 -55.9664916992 -69.7423400879 -55.9664916992 -69.7423400879 Z" />
+            <group
+                android:name="cross"
+                android:rotation="-1.88453332239" >
+                <path
+                    android:name="path_1"
+                    android:pathData="M 10.6188659668 6.56344604492 c 0.0 0.0 21.7386016846 23.1297454834 21.7386016846 23.1297454834 "
+                    android:strokeColor="#FF777777"
+                    android:strokeWidth="4"
+                    android:fillColor="#00000000" />
+            </group>
+            <group
+                android:name="bluetooth"
+                android:translateX="23.38789"
+                android:translateY="18.72031" >
+                <path
+                    android:name="path_4"
+                    android:pathData="M 11.3999938965 -8.60000610352 c 0.0 0.0 -11.3999938965 -11.3999938965 -11.3999938965 -11.3999938965 c 0 0 -2 0 -2 0 c 0 0 0 15.1999969482 0 15.1999969482 c 0 0.0 -9.19999694824 -9.19999694824 -9.19999694824 -9.19999694824 c 0.0 0 -2.80000305176 2.80000305176 -2.80000305176 2.80000305176 c 0 0.0 11.1999969482 11.1999969482 11.1999969482 11.1999969482 c 0.0 0 -11.1999969482 11.1999969482 -11.1999969482 11.1999969482 c 0 0.0 2.80000305176 2.80000305176 2.80000305176 2.80000305176 c 0.0 0 9.19999694824 -9.19999694824 9.19999694824 -9.19999694824 c 0 0.0 0 15.1999969482 0 15.1999969482 c 0 0 2 0 2 0 c 0 0 11.3999938965 -11.3999938965 11.3999938965 -11.3999938965 c 0.0 0.0 -8.59999084473 -8.60000610352 -8.59999084473 -8.60000610352 c 0.0 0 8.59999084473 -8.60000610352 8.59999084473 -8.60000610352 Z M 2 -12.3000030518 c 0 0.0 3.80000305176 3.80000305176 3.80000305176 3.80000305176 c 0.0 0.0 -3.80000305176 3.69999694824 -3.80000305176 3.69999694824 c 0 0.0 0 -7.5 0 -7.5 Z M 5.80000305176 8.60000610352 c 0.0 0.0 -3.80000305176 3.69999694824 -3.80000305176 3.69999694824 c 0 0.0 0 -7.5 0 -7.5 c 0 0.0 3.80000305176 3.80000305176 3.80000305176 3.80000305176 Z"
+                    android:fillColor="#FF777777" />
+            </group>
+            <group
+                android:name="dot_left"
+                android:translateX="20.16992"
+                android:translateY="18.64258" >
+                <group
+                    android:name="dot_left_pivot"
+                    android:translateX="-20.16992"
+                    android:translateY="-18.64258" >
+                    <path
+                        android:name="dot_left_1"
+                        android:pathData="M 13.3878936768 18.7203063965 c 0.0 0.0 -4.0 -4.0 -4.0 -4.0 c 0.0 0.0 -4.0 4.0 -4.0 4.0 c 0.0 0.0 4.0 4.0 4.0 4.0 c 0.0 0.0 4.0 -4.0 4.0 -4.0 Z"
+                        android:fillColor="#FF777777" />
+                </group>
+            </group>
+            <group
+                android:name="dot_right"
+                android:translateX="26.16094"
+                android:translateY="18.60898" >
+                <group
+                    android:name="dot_right_pivot"
+                    android:translateX="-26.16094"
+                    android:translateY="-18.60898" >
+                    <path
+                        android:name="dot_right_1"
+                        android:pathData="M 37.3878936768 14.7203063965 c 0.0 0.0 -4.0 4.0 -4.0 4.0 c 0.0 0.0 4.0 4.0 4.0 4.0 c 0.0 0.0 4.0 -4.0 4.0 -4.0 c 0.0 0.0 -4.0 -4.0 -4.0 -4.0 Z"
+                        android:fillColor="#FF777777" />
+                </group>
+            </group>
+        </group>
+    </group>
+</vector>
diff --git a/tests/VectorDrawableTest/res/drawable/ic_bluethooth_v2_animation.xml b/tests/VectorDrawableTest/res/drawable/ic_bluethooth_v2_animation.xml
new file mode 100644
index 0000000..aa05468
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/ic_bluethooth_v2_animation.xml
@@ -0,0 +1,32 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/ic_bluethooth_v2" >
+    <target
+        android:name="root_bt"
+        android:animation="@anim/ic_bluethooth_v2_animation_ic_signal_wifi_4_bar_48px_outlines_" />
+    <target
+        android:name="mask"
+        android:animation="@anim/ic_bluethooth_v2_animation_mask" />
+    <target
+        android:name="path_1"
+        android:animation="@anim/ic_bluethooth_v2_animation_path_1" />
+    <target
+        android:name="dot_left"
+        android:animation="@anim/ic_bluethooth_v2_animation_dot_left" />
+    <target
+        android:name="dot_right"
+        android:animation="@anim/ic_bluethooth_v2_animation_dot_right" />
+</animated-vector>
diff --git a/tests/VectorDrawableTest/res/drawable/ic_cast_v2.xml b/tests/VectorDrawableTest/res/drawable/ic_cast_v2.xml
new file mode 100644
index 0000000..207804a
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/ic_cast_v2.xml
@@ -0,0 +1,123 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="48dp"
+    android:width="48dp"
+    android:viewportHeight="48"
+    android:viewportWidth="48" >
+    <group
+        android:name="ic_cast_connected_48px_outlines"
+        android:translateX="24"
+        android:translateY="24" >
+        <group
+            android:name="ic_cast_connected_48px_outlines_pivot"
+            android:translateX="-24"
+            android:translateY="-24" >
+            <clip-path
+                android:name="mask_1"
+                android:pathData="M 46.6999969482 3.80000305176 c 0.0 0.0 -44.6999664307 0.0 -44.6999664307 0.0 c 0.0 0.0 0.29997253418 38.25 0.29997253418 38.25 c 0.0 0.0 44.8000030518 -0.100021362305 44.8000030518 -0.100021362305 c 0.0 0.0 -0.400009155273 -38.1499786377 -0.400009155273 -38.1499786377 Z" />
+            <group
+                android:name="waves"
+                android:alpha="0.5" >
+                <group
+                    android:name="wave1_position"
+                    android:translateX="2"
+                    android:translateY="42" >
+                    <path
+                        android:name="wave1"
+                        android:pathData="M 0 -4.0 a 4 4 0 0 1 4 4 a 4 4 0 0 1 -4 4 a 4 4 0 0 1 -4 -4 a 4 4 0 0 1 4 -4 Z"
+                        android:strokeColor="#FF777777"
+                        android:strokeWidth="4"
+                        android:fillColor="#00000000" />
+                </group>
+                <group
+                    android:name="wave2_position"
+                    android:translateX="2"
+                    android:translateY="42" >
+                    <path
+                        android:name="wave2"
+                        android:pathData="M 0 -12.0 a 12 12 0 0 1 12 12 a 12 12 0 0 1 -12 12 a 12 12 0 0 1 -12 -12 a 12 12 0 0 1 12 -12 Z"
+                        android:strokeColor="#FF777777"
+                        android:strokeWidth="4"
+                        android:fillColor="#00000000" />
+                </group>
+                <group
+                    android:name="wave3_position"
+                    android:translateX="2"
+                    android:translateY="42" >
+                    <path
+                        android:name="wave3"
+                        android:pathData="M 0 -20.0 a 20 20 0 0 1 20 20 a 20 20 0 0 1 -20 20 a 20 20 0 0 1 -20 -20 a 20 20 0 0 1 20 -20 Z"
+                        android:strokeColor="#FF777777"
+                        android:strokeWidth="4"
+                        android:fillColor="#00000000" />
+                </group>
+                <group
+                    android:name="wave5_position"
+                    android:translateX="2"
+                    android:translateY="42" >
+                    <path
+                        android:name="wave5"
+                        android:pathData="M 0 -0.0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 Z"
+                        android:strokeColor="#FF777777"
+                        android:strokeWidth="4"
+                        android:fillColor="#00000000" />
+                </group>
+                <group
+                    android:name="wave6_position"
+                    android:translateX="2"
+                    android:translateY="42" >
+                    <path
+                        android:name="wave6"
+                        android:pathData="M 0 -0.0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 Z"
+                        android:strokeColor="#FF777777"
+                        android:strokeWidth="4"
+                        android:fillColor="#00000000" />
+                </group>
+                <group
+                    android:name="ellipse_path_1_position"
+                    android:translateX="2"
+                    android:translateY="42" >
+                    <path
+                        android:name="ellipse_path_1"
+                        android:pathData="M 0 -2.0 a 2 2 0 0 1 2 2 a 2 2 0 0 1 -2 2 a 2 2 0 0 1 -2 -2 a 2 2 0 0 1 2 -2 Z"
+                        android:strokeColor="#FF777777"
+                        android:strokeWidth="4"
+                        android:fillColor="#00000000" />
+                </group>
+            </group>
+            <group
+                android:name="screen"
+                android:translateX="24"
+                android:translateY="24"
+                android:alpha="0" >
+                <path
+                    android:name="screen_1"
+                    android:pathData="M 14 -10 c 0 0 -28 0 -28 0 c 0 0 0 3.30000305176 0 3.30000305176 c 7.89999389648 2.59999084473 14.1999969482 8.80000305176 16.6999969482 16.6999969482 c 0.0 0 11.3000030518 0 11.3000030518 0 c 0 0 0 -20 0 -20 Z"
+                    android:fillColor="#FF777777" />
+            </group>
+            <group
+                android:name="frame"
+                android:translateX="24"
+                android:translateY="24"
+                android:alpha="0.5" >
+                <path
+                    android:name="box"
+                    android:pathData="M 18 -18 c 0 0 -36 0 -36 0 c -2.19999694824 0 -4 1.80000305176 -4 4 c 0 0 0 6 0 6 c 0 0 4 0 4 0 c 0 0 0 -6 0 -6 c 0 0 36 0 36 0 c 0 0 0 28 0 28 c 0 0 -14 0 -14 0 c 0 0 0 4 0 4 c 0 0 14 0 14 0 c 2.19999694824 0 4 -1.80000305176 4 -4 c 0 0 0 -28 0 -28 c 0 -2.19999694824 -1.80000305176 -4 -4 -4 Z"
+                    android:fillColor="#FF777777" />
+            </group>
+        </group>
+    </group>
+</vector>
diff --git a/tests/VectorDrawableTest/res/drawable/ic_cast_v2_animation.xml b/tests/VectorDrawableTest/res/drawable/ic_cast_v2_animation.xml
new file mode 100644
index 0000000..7884212
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/ic_cast_v2_animation.xml
@@ -0,0 +1,41 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/ic_cast_v2" >
+    <target
+        android:name="waves"
+        android:animation="@anim/ic_cast_v2_animation_waves" />
+    <target
+        android:name="wave1"
+        android:animation="@anim/ic_cast_v2_animation_wave1" />
+    <target
+        android:name="wave2"
+        android:animation="@anim/ic_cast_v2_animation_wave2" />
+    <target
+        android:name="wave3"
+        android:animation="@anim/ic_cast_v2_animation_wave3" />
+    <target
+        android:name="wave5"
+        android:animation="@anim/ic_cast_v2_animation_wave5" />
+    <target
+        android:name="wave6"
+        android:animation="@anim/ic_cast_v2_animation_wave6" />
+    <target
+        android:name="screen"
+        android:animation="@anim/ic_cast_v2_animation_screen" />
+    <target
+        android:name="frame"
+        android:animation="@anim/ic_cast_v2_animation_frame" />
+</animated-vector>
diff --git a/tests/VectorDrawableTest/res/drawable/ic_hourglass.xml b/tests/VectorDrawableTest/res/drawable/ic_hourglass.xml
new file mode 100644
index 0000000..5b40922
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/ic_hourglass.xml
@@ -0,0 +1,74 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:width="24dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24" >
+    <group
+        android:name="hourglass_frame"
+        android:translateX="12"
+        android:translateY="12"
+        android:scaleX="0.75"
+        android:scaleY="0.75" >
+        <group
+            android:name="hourglass_frame_pivot"
+            android:translateX="-12"
+            android:translateY="-12" >
+            <group
+                android:name="group_2_2"
+                android:translateX="12"
+                android:translateY="6.5" >
+                <path
+                    android:name="path_2_2"
+                    android:pathData="M 6.52099609375 -3.89300537109 c 0.0 0.0 -6.52099609375 6.87901306152 -6.52099609375 6.87901306152 c 0 0.0 -6.52099609375 -6.87901306152 -6.52099609375 -6.87901306152 c 0.0 0.0 13.0419921875 0.0 13.0419921875 0.0 Z M 9.99800109863 -6.5 c 0.0 0.0 -19.9960021973 0.0 -19.9960021973 0.0 c -0.890991210938 0.0 -1.33700561523 1.07699584961 -0.707000732422 1.70700073242 c 0.0 0.0 10.7050018311 11.2929992676 10.7050018311 11.2929992676 c 0 0.0 10.7050018311 -11.2929992676 10.7050018311 -11.2929992676 c 0.630004882812 -0.630004882812 0.183990478516 -1.70700073242 -0.707000732422 -1.70700073242 Z"
+                    android:fillColor="#FF777777" />
+            </group>
+            <group
+                android:name="group_1_2"
+                android:translateX="12"
+                android:translateY="17.5" >
+                <path
+                    android:name="path_2_1"
+                    android:pathData="M 0 -2.98600769043 c 0 0.0 6.52099609375 6.87901306152 6.52099609375 6.87901306152 c 0.0 0.0 -13.0419921875 0.0 -13.0419921875 0.0 c 0.0 0.0 6.52099609375 -6.87901306152 6.52099609375 -6.87901306152 Z M 0 -6.5 c 0 0.0 -10.7050018311 11.2929992676 -10.7050018311 11.2929992676 c -0.630004882812 0.630004882812 -0.184005737305 1.70700073242 0.707000732422 1.70700073242 c 0.0 0.0 19.9960021973 0.0 19.9960021973 0.0 c 0.890991210938 0.0 1.33699035645 -1.07699584961 0.707000732422 -1.70700073242 c 0.0 0.0 -10.7050018311 -11.2929992676 -10.7050018311 -11.2929992676 Z"
+                    android:fillColor="#FF777777" />
+            </group>
+        </group>
+    </group>
+    <group
+        android:name="fill_outlines"
+        android:translateX="12"
+        android:translateY="12"
+        android:scaleX="0.75"
+        android:scaleY="0.75" >
+        <group
+            android:name="fill_outlines_pivot"
+            android:translateX="-12"
+            android:translateY="-12" >
+            <clip-path
+                android:name="mask_1"
+                android:pathData="M 24 13.3999938965 c 0 0.0 -24 0.0 -24 0.0 c 0 0.0 0 10.6000061035 0 10.6000061035 c 0 0 24 0 24 0 c 0 0 0 -10.6000061035 0 -10.6000061035 Z" />
+            <group
+                android:name="group_1_3"
+                android:translateX="12"
+                android:translateY="12" >
+                <path
+                    android:name="path_1_6"
+                    android:pathData="M 10.7100067139 10.2900085449 c 0.629989624023 0.629989624023 0.179992675781 1.70999145508 -0.710006713867 1.70999145508 c 0 0 -20 0 -20 0 c -0.889999389648 0 -1.33999633789 -1.08000183105 -0.710006713867 -1.70999145508 c 0.0 0.0 9.76000976562 -10.2900085449 9.76000976563 -10.2900085449 c 0.0 0 -9.76000976562 -10.2899932861 -9.76000976563 -10.2899932861 c -0.629989624023 -0.630004882812 -0.179992675781 -1.71000671387 0.710006713867 -1.71000671387 c 0 0 20 0 20 0 c 0.889999389648 0 1.33999633789 1.08000183105 0.710006713867 1.71000671387 c 0.0 0.0 -9.76000976562 10.2899932861 -9.76000976563 10.2899932861 c 0.0 0 9.76000976562 10.2900085449 9.76000976563 10.2900085449 Z"
+                    android:fillColor="#FF777777" />
+            </group>
+        </group>
+    </group>
+</vector>
diff --git a/tests/VectorDrawableTest/res/drawable/ic_hourglass_animation.xml b/tests/VectorDrawableTest/res/drawable/ic_hourglass_animation.xml
new file mode 100644
index 0000000..3d87376
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/ic_hourglass_animation.xml
@@ -0,0 +1,26 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/ic_hourglass" >
+    <target
+        android:name="hourglass_frame"
+        android:animation="@anim/ic_hourglass_animation_hourglass_frame" />
+    <target
+        android:name="fill_outlines"
+        android:animation="@anim/ic_hourglass_animation_fill_outlines" />
+    <target
+        android:name="mask_1"
+        android:animation="@anim/ic_hourglass_animation_mask_1" />
+</animated-vector>
diff --git a/tests/VectorDrawableTest/res/drawable/ic_open.xml b/tests/VectorDrawableTest/res/drawable/ic_open.xml
new file mode 100644
index 0000000..ad96094
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/ic_open.xml
@@ -0,0 +1,56 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="288dp"
+    android:width="288dp"
+    android:viewportHeight="288"
+    android:viewportWidth="288" >
+    <group
+        android:name="ball_start"
+        android:translateX="147.411817411"
+        android:translateY="129.468428513"
+        android:scaleX="0.586201598553"
+        android:scaleY="0.586201598553" >
+        <group
+            android:name="shape_1"
+            android:scaleX="0.76"
+            android:scaleY="0.748114397321" >
+            <path
+                android:name="path_1"
+                android:pathData="M 0,-17.3838043213 c -9.625,0.0 -17.0795440674,8.28025817871 -17.0795440674,17.4052734375 c 0.0,9.75645446777 7.51704406738,17.6295623779 17.0795440674,17.353515625 c 11.5579986572,-0.333648681641 17.2784118652,-8.72853088379 17.2784118652,-17.353515625 c 0.0,-8.62501525879 -7.65341186523,-17.4052734375 -17.2784118652,-17.4052734375 Z"
+                android:fillColor="#FFFF9000"
+                android:fillAlpha="0" />
+        </group>
+    </group>
+    <group
+        android:name="ball_swoop"
+        android:translateX="144"
+        android:translateY="144"
+        android:scaleX="0.752248"
+        android:scaleY="0.752248"
+        android:rotation="-87.6585365854" >
+        <path
+            android:name="path_1_1"
+            android:pathData="M -56.7679443359,1.03857421875 c 0.0,0.0 191.916503906,-13.9097290039 191.916503906,88.0704345703 c 0.0,58.4487304688 -83.6709594727,90.1372070312 -137.004882812,90.1372070312 c -82.1782226562,0.0 -177.867431641,-63.5512695312 -177.867431641,-178.207641602 c 0.0,-115.985717773 98.7650146484,-178.160949707 177.986938477,-178.160949707 c 76.2376251221,0.0 178.1640625,60.6796875 178.1640625,178.185058594 "
+            android:strokeColor="#FFFF9000"
+            android:strokeAlpha="1"
+            android:strokeWidth="20"
+            android:strokeLineCap="round"
+            android:trimPathStart="0.93025"
+            android:trimPathEnd="0.96248"
+            android:trimPathOffset="0"
+            android:fillColor="#00000000" />
+    </group>
+</vector>
diff --git a/tests/VectorDrawableTest/res/drawable/ic_open_animation.xml b/tests/VectorDrawableTest/res/drawable/ic_open_animation.xml
new file mode 100644
index 0000000..83ee90b
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/ic_open_animation.xml
@@ -0,0 +1,29 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/ic_open" >
+    <target
+        android:name="ball_start"
+        android:animation="@anim/ic_open_animation_ball_start" />
+    <target
+        android:name="path_1"
+        android:animation="@anim/ic_open_animation_path_1" />
+    <target
+        android:name="ball_swoop"
+        android:animation="@anim/ic_open_animation_ball_swoop" />
+    <target
+        android:name="path_1_1"
+        android:animation="@anim/ic_open_animation_path_1_1" />
+</animated-vector>
diff --git a/tests/VectorDrawableTest/res/drawable/ic_rotate_2_portrait_v2.xml b/tests/VectorDrawableTest/res/drawable/ic_rotate_2_portrait_v2.xml
new file mode 100644
index 0000000..b549423
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/ic_rotate_2_portrait_v2.xml
@@ -0,0 +1,59 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="48dp"
+    android:viewportHeight="48"
+    android:viewportWidth="48"
+    android:width="48dp" >
+
+    <group
+        android:name="ic_screen_rotation_48px_outlines_1"
+        android:translateX="24"
+        android:translateY="24" >
+        <group
+            android:name="ic_screen_rotation_48px_outlines_1_pivot"
+            android:translateX="-24.15"
+            android:translateY="-24.25" >
+            <group
+                android:name="arrows_1"
+                android:translateX="24.1"
+                android:translateY="24.1" >
+                <group
+                    android:name="arrows_1_pivot"
+                    android:translateX="-24.1"
+                    android:translateY="-24.1" >
+                    <path
+                        android:name="arrow_top_1"
+                        android:fillColor="#FF777777"
+                        android:pathData="M 33.1499938965 5.25 c 6.5 3.10000610352 11.1999969482 9.40000915527 11.8999938965 17.0 c 0.0 0.0 3.00001525879 0.0 3.00001525879 0.0 c -1.00001525879 -12.3000030518 -11.3000030518 -22.0 -23.9000091553 -22.0 c -0.399993896484 0.0 -0.899993896484 0.0 -1.30000305176 0.100006103516 c 0.0 0.0 7.60000610352 7.59999084473 7.60000610352 7.59999084473 c 0.0 0.0 2.69999694824 -2.69999694824 2.69999694824 -2.69999694824 Z" />
+                    <path
+                        android:name="arrow_bottom_1"
+                        android:fillColor="#FF777777"
+                        android:pathData="M 15.1499938965 43.25 c -6.5 -3.09999084473 -11.1999969482 -9.5 -11.8999938965 -17.0 c 0.0 0.0 -3.0 0.0 -3.0 0.0 c 1.0 12.3000030518 11.299987793 22.0 23.8999938965 22.0 c 0.399993896484 0.0 0.899993896484 0.0 1.30000305176 -0.0999908447266 c 0.0 0.0 -7.60000610352 -7.60000610352 -7.60000610352 -7.60000610352 c 0.0 0.0 -2.69999694824 2.69999694824 -2.69999694824 2.69999694824 Z" />
+                </group>
+            </group>
+            <group
+                android:name="device_1"
+                android:translateX="24.14999"
+                android:translateY="24.25" >
+                <path
+                    android:name="device_2"
+                    android:fillColor="#FF777777"
+                    android:pathData="M -3.5 -20.5 c -1.19999694824 -1.19999694824 -3.10000610352 -1.19999694824 -4.19999694824 0.0 c 0.0 0.0 -12.8000030518 12.6999969482 -12.8000030518 12.6999969482 c -1.19999694824 1.19999694824 -1.19999694824 3.10000610352 0.0 4.19999694824 c 0.0 0.0 24.0 24.0000152588 24.0 24.0000152588 c 1.19999694824 1.19999694824 3.10000610352 1.19999694824 4.19999694824 0.0 c 0.0 0.0 12.6999969482 -12.700012207 12.6999969482 -12.700012207 c 1.20001220703 -1.19999694824 1.20001220703 -3.09999084473 0.0 -4.19999694824 c 0.0 0.0 -23.8999938965 -24.0 -23.8999938965 -24.0 Z M 2.84999084473 15.5500183105 c 0.0 0.0 -18.6000061035 -18.5000457764 -18.6000061035 -18.5000457764 c 0.0 0.0 12.5999908447 -12.8000030518 12.5999908447 -12.8000030518 c 0.0 0.0 18.6000213623 18.5000457764 18.6000213623 18.5000457764 c 0.0 0.0 -12.6000061035 12.8000030518 -12.6000061035 12.8000030518 Z" />
+            </group>
+        </group>
+    </group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/ic_rotate_2_portrait_v2_animation.xml b/tests/VectorDrawableTest/res/drawable/ic_rotate_2_portrait_v2_animation.xml
new file mode 100644
index 0000000..199fbf8
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/ic_rotate_2_portrait_v2_animation.xml
@@ -0,0 +1,26 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/ic_rotate_2_portrait_v2" >
+    <target
+        android:name="arrows_1"
+        android:animation="@anim/ic_rotate_2_portrait_v2_animation_arrows_1" />
+    <target
+        android:name="device_1"
+        android:animation="@anim/ic_rotate_2_portrait_v2_animation_device_1" />
+    <target
+        android:name="device_2"
+        android:animation="@anim/ic_rotate_2_portrait_v2_animation_device_2" />
+</animated-vector>
diff --git a/tests/VectorDrawableTest/res/drawable/ic_signal_airplane_v2.xml b/tests/VectorDrawableTest/res/drawable/ic_signal_airplane_v2.xml
new file mode 100644
index 0000000..8b2a1a8
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/ic_signal_airplane_v2.xml
@@ -0,0 +1,52 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="48dp"
+    android:width="48dp"
+    android:viewportHeight="48"
+    android:viewportWidth="48" >
+    <group
+        android:name="ic_signal_airplane"
+        android:translateX="21.9995"
+        android:translateY="25.73401" >
+        <group
+            android:name="ic_signal_airplane_pivot"
+            android:translateX="-23.21545"
+            android:translateY="-18.86649" >
+            <clip-path
+                android:name="mask_2"
+                android:pathData="M 37.8337860107 -40.4599914551 c 0.0 0.0 -35.8077850342 31.5523681641 -35.8077850342 31.5523681641 c 0.0 0.0 9.55097961426 9.55285644531 9.55097961426 9.55285644531 c 0.0 0.0 -2.61698913574 2.09387207031 -2.61698913574 2.09387207031 c 0.0 0.0 -9.75096130371 -9.56428527832 -9.75096130371 -9.56428527832 c 0.0 0.0 -34.6200408936 25.4699249268 -34.6200408936 25.4699249268 c 0.0 0.0 55.9664764404 69.742401123 55.9664764404 69.742401123 c 0.0 0.0 73.2448120117 -59.1047973633 73.2448120117 -59.1047973633 c 0.0 0.0 -55.9664916992 -69.7423400879 -55.9664916992 -69.7423400879 Z" />
+            <group
+                android:name="cross_1"
+                android:alpha="0" >
+                <path
+                    android:name="path_1_1"
+                    android:pathData="M 7.54049682617 3.9430847168 c 0.0 0.0 0.324981689453 0.399978637695 0.324981689453 0.399978637695 "
+                    android:strokeColor="#FF777777"
+                    android:strokeWidth="3.5"
+                    android:fillColor="#00000000" />
+            </group>
+            <group
+                android:name="plane"
+                android:translateX="23.481"
+                android:translateY="18.71151" >
+                <path
+                    android:name="path_3_2"
+                    android:pathData="M 18.9439849854 7.98849487305 c 0.0 0.0 0.0 -4.0 0.0 -4.0 c 0.0 0.0 -16.0 -10.0 -16.0 -10.0 c 0.0 0.0 0.0 -11.0 0.0 -11.0 c 0.0 -1.70001220703 -1.30000305176 -3.0 -3.0 -3.0 c -1.69999694824 0.0 -3.0 1.29998779297 -3.0 3.0 c 0.0 0.0 0.0 11.0 0.0 11.0 c 0.0 0.0 -16.0 10.0 -16.0 10.0 c 0.0 0.0 0.0 4.0 0.0 4.0 c 0.0 0.0 16.0 -5.0 16.0 -5.0 c 0.0 0.0 0.0 11.0 0.0 11.0 c 0.0 0.0 -4.0 3.0 -4.0 3.0 c 0.0 0.0 0.0 3.0 0.0 3.0 c 0.0 0.0 7.0 -2.0 7.0 -2.0 c 0.0 0.0 7.0 2.0 7.0 2.0 c 0.0 0.0 0.0 -3.0 0.0 -3.0 c 0.0 0.0 -4.0 -3.0 -4.0 -3.0 c 0.0 0.0 0.0 -11.0 0.0 -11.0 c 0.0 0.0 16.0 5.0 16.0 5.0 Z"
+                    android:fillColor="#FF777777" />
+            </group>
+        </group>
+    </group>
+</vector>
diff --git a/tests/VectorDrawableTest/res/drawable/ic_signal_airplane_v2_animation.xml b/tests/VectorDrawableTest/res/drawable/ic_signal_airplane_v2_animation.xml
new file mode 100644
index 0000000..bde2b38
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/ic_signal_airplane_v2_animation.xml
@@ -0,0 +1,29 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/ic_signal_airplane_v2" >
+    <target
+        android:name="ic_signal_airplane"
+        android:animation="@anim/ic_signal_airplane_v2_animation_ic_signal_airplane" />
+    <target
+        android:name="mask_2"
+        android:animation="@anim/ic_signal_airplane_v2_animation_mask_2" />
+    <target
+        android:name="cross_1"
+        android:animation="@anim/ic_signal_airplane_v2_animation_cross_1" />
+    <target
+        android:name="path_1_1"
+        android:animation="@anim/ic_signal_airplane_v2_animation_path_1_1" />
+</animated-vector>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable29.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable29.xml
new file mode 100644
index 0000000..c0e9b2a
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable29.xml
@@ -0,0 +1,28 @@
+<!--
+ Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:height="48dp"
+        android:width="48dp"
+        android:viewportHeight="1"
+        android:viewportWidth="1" >
+
+    <group>
+        <path
+            android:name="box1"
+            android:pathData="l0.0.0.5.0.0.5-0.5.0.0-.5z"
+            android:fillColor="#ff00ff00"/>
+    </group>
+</vector>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_progress_bar.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable_progress_bar.xml
index 4544cae..22cd995 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable_progress_bar.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable_progress_bar.xml
@@ -17,7 +17,8 @@
         android:height="64dp"
         android:width="64dp"
         android:viewportHeight="64"
-        android:viewportWidth="64" >
+        android:viewportWidth="64"
+        android:name="root_bar" >
 
     <group
         android:name="root"
diff --git a/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator.xml b/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator.xml
index 0cffa0a..489596c 100644
--- a/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator.xml
+++ b/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator.xml
@@ -1,2 +1,16 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
 <pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
     android:pathData="m0,0q0.4,0.05 0.6,0.3t0.3,0.3l0.1,0.4" />
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator_favorite.xml b/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator_favorite.xml
index 935d5b5..3d125e4 100644
--- a/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator_favorite.xml
+++ b/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator_favorite.xml
@@ -1,2 +1,16 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
 <pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
     android:pathData="L0.1, 0 C0.10066,0 0.198,1 0.2, 1 L 1,1" />
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator_grouping_1_01.xml b/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator_grouping_1_01.xml
index 8c57395..6877bd9 100644
--- a/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator_grouping_1_01.xml
+++ b/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator_grouping_1_01.xml
@@ -1,2 +1,16 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
 <pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
     android:pathData="L 0.09 1 L 1,1" />
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/interpolator/ic_bluethooth_v2_path_1_pathdata_interpolator.xml b/tests/VectorDrawableTest/res/interpolator/ic_bluethooth_v2_path_1_pathdata_interpolator.xml
new file mode 100644
index 0000000..4917f77
--- /dev/null
+++ b/tests/VectorDrawableTest/res/interpolator/ic_bluethooth_v2_path_1_pathdata_interpolator.xml
@@ -0,0 +1,16 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0 0 c 0.16666666667 0.0 0.2 1.0 1.0 1.0" />
diff --git a/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scalex_interpolator_1.xml b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scalex_interpolator_1.xml
new file mode 100644
index 0000000..601cfc6
--- /dev/null
+++ b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scalex_interpolator_1.xml
@@ -0,0 +1,16 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0 0 c 0.33333333,0.0 0.202777547991,1.0 1.0,1.0" />
diff --git a/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scalex_interpolator_2.xml b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scalex_interpolator_2.xml
new file mode 100644
index 0000000..5011ef9
--- /dev/null
+++ b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scalex_interpolator_2.xml
@@ -0,0 +1,16 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0 0 c 0.0103034467173,0.0 0.701918866569,1.0 1.0,1.0" />
diff --git a/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scalex_interpolator_3.xml b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scalex_interpolator_3.xml
new file mode 100644
index 0000000..7b0af97
--- /dev/null
+++ b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scalex_interpolator_3.xml
@@ -0,0 +1,16 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0 0 c 0.649706648701,0.0 0.884285938423,1.92358061843 1.0,1.0" />
diff --git a/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scaley_interpolator_1.xml b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scaley_interpolator_1.xml
new file mode 100644
index 0000000..601cfc6
--- /dev/null
+++ b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scaley_interpolator_1.xml
@@ -0,0 +1,16 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0 0 c 0.33333333,0.0 0.202777547991,1.0 1.0,1.0" />
diff --git a/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scaley_interpolator_2.xml b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scaley_interpolator_2.xml
new file mode 100644
index 0000000..5011ef9
--- /dev/null
+++ b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scaley_interpolator_2.xml
@@ -0,0 +1,16 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0 0 c 0.0103034467173,0.0 0.701918866569,1.0 1.0,1.0" />
diff --git a/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scaley_interpolator_3.xml b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scaley_interpolator_3.xml
new file mode 100644
index 0000000..7b0af97
--- /dev/null
+++ b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scaley_interpolator_3.xml
@@ -0,0 +1,16 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0 0 c 0.649706648701,0.0 0.884285938423,1.92358061843 1.0,1.0" />
diff --git a/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_translatex_interpolator.xml b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_translatex_interpolator.xml
new file mode 100644
index 0000000..ea11d1f
--- /dev/null
+++ b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_translatex_interpolator.xml
@@ -0,0 +1,16 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0 0 c 0.353876322169,0.0 0.686452288267,-1.02094740172 1.0,1.0" />
diff --git a/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_translatey_interpolator_1.xml b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_translatey_interpolator_1.xml
new file mode 100644
index 0000000..7bd5c49
--- /dev/null
+++ b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_translatey_interpolator_1.xml
@@ -0,0 +1,16 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0 0 c 0.754478769148,0.0 0.97,1.0 1.0,1.0" />
diff --git a/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_translatey_interpolator_2.xml b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_translatey_interpolator_2.xml
new file mode 100644
index 0000000..b0ab6e8
--- /dev/null
+++ b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_translatey_interpolator_2.xml
@@ -0,0 +1,16 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0 0 c 0.33333333,0.0 0.83333333333,1.0 1.0,1.0" />
diff --git a/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_translatey_interpolator_3.xml b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_translatey_interpolator_3.xml
new file mode 100644
index 0000000..61060a6
--- /dev/null
+++ b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_translatey_interpolator_3.xml
@@ -0,0 +1,16 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0 0 c 0.324310863613,0.0 0.735625629425,-0.0161527278292 1.0,1.0" />
diff --git a/tests/VectorDrawableTest/res/interpolator/ic_open_path_1_1_trimpathend_interpolator_2.xml b/tests/VectorDrawableTest/res/interpolator/ic_open_path_1_1_trimpathend_interpolator_2.xml
new file mode 100644
index 0000000..7e19ef6
--- /dev/null
+++ b/tests/VectorDrawableTest/res/interpolator/ic_open_path_1_1_trimpathend_interpolator_2.xml
@@ -0,0 +1,16 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0 0 c 0.744517024668,0.120263649138 0.135947812437,0.994319475209 1.0,1.0" />
diff --git a/tests/VectorDrawableTest/res/interpolator/ic_open_path_1_1_trimpathstart_interpolator_2.xml b/tests/VectorDrawableTest/res/interpolator/ic_open_path_1_1_trimpathstart_interpolator_2.xml
new file mode 100644
index 0000000..1280715
--- /dev/null
+++ b/tests/VectorDrawableTest/res/interpolator/ic_open_path_1_1_trimpathstart_interpolator_2.xml
@@ -0,0 +1,16 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0 0 c 0.781904890372,0.126303002187 0.188007240906,0.953418294755 1.0,1.0" />
diff --git a/tests/VectorDrawableTest/res/interpolator/ic_open_path_1_pathdata_interpolator_1.xml b/tests/VectorDrawableTest/res/interpolator/ic_open_path_1_pathdata_interpolator_1.xml
new file mode 100644
index 0000000..ddf966e
--- /dev/null
+++ b/tests/VectorDrawableTest/res/interpolator/ic_open_path_1_pathdata_interpolator_1.xml
@@ -0,0 +1,16 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0 0 c 0.000100000000012,0.0 0.0,1.0 1.0,1.0" />
diff --git a/tests/VectorDrawableTest/res/interpolator/ic_open_path_1_pathdata_interpolator_2.xml b/tests/VectorDrawableTest/res/interpolator/ic_open_path_1_pathdata_interpolator_2.xml
new file mode 100644
index 0000000..624e304
--- /dev/null
+++ b/tests/VectorDrawableTest/res/interpolator/ic_open_path_1_pathdata_interpolator_2.xml
@@ -0,0 +1,16 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0 0 c 9.99999999007e-05,0.0 0.0,1.0 1.0,1.0" />
diff --git a/tests/VectorDrawableTest/res/interpolator/ic_open_path_1_pathdata_interpolator_3.xml b/tests/VectorDrawableTest/res/interpolator/ic_open_path_1_pathdata_interpolator_3.xml
new file mode 100644
index 0000000..3ebee0b
--- /dev/null
+++ b/tests/VectorDrawableTest/res/interpolator/ic_open_path_1_pathdata_interpolator_3.xml
@@ -0,0 +1,16 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0 0 c 0.000100000000051,0.0 0.83333333333,1.0 1.0,1.0" />
diff --git a/tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_arrows_1_rotation_interpolator.xml b/tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_arrows_1_rotation_interpolator.xml
new file mode 100644
index 0000000..f798a84
--- /dev/null
+++ b/tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_arrows_1_rotation_interpolator.xml
@@ -0,0 +1,16 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0 0 c 0.4 0.0 0.2 1.0 1.0 1.0" />
diff --git a/tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_arrows_1_scalex_interpolator.xml b/tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_arrows_1_scalex_interpolator.xml
new file mode 100644
index 0000000..314cf44
--- /dev/null
+++ b/tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_arrows_1_scalex_interpolator.xml
@@ -0,0 +1,16 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0 0.0 L 1.0 1.0 " />
diff --git a/tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_device_1_rotation_interpolator.xml b/tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_device_1_rotation_interpolator.xml
new file mode 100644
index 0000000..f798a84
--- /dev/null
+++ b/tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_device_1_rotation_interpolator.xml
@@ -0,0 +1,16 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0 0 c 0.4 0.0 0.2 1.0 1.0 1.0" />
diff --git a/tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_device_2_pathdata_interpolator.xml b/tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_device_2_pathdata_interpolator.xml
new file mode 100644
index 0000000..f798a84
--- /dev/null
+++ b/tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_device_2_pathdata_interpolator.xml
@@ -0,0 +1,16 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0 0 c 0.4 0.0 0.2 1.0 1.0 1.0" />
diff --git a/tests/VectorDrawableTest/res/interpolator/ic_signal_airplane_v2_path_1_1_pathdata_interpolator.xml b/tests/VectorDrawableTest/res/interpolator/ic_signal_airplane_v2_path_1_1_pathdata_interpolator.xml
new file mode 100644
index 0000000..4917f77
--- /dev/null
+++ b/tests/VectorDrawableTest/res/interpolator/ic_signal_airplane_v2_path_1_1_pathdata_interpolator.xml
@@ -0,0 +1,16 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0 0 c 0.16666666667 0.0 0.2 1.0 1.0 1.0" />
diff --git a/tests/VectorDrawableTest/res/interpolator/trim_end_interpolator.xml b/tests/VectorDrawableTest/res/interpolator/trim_end_interpolator.xml
index b2770cd..54b5ebd 100644
--- a/tests/VectorDrawableTest/res/interpolator/trim_end_interpolator.xml
+++ b/tests/VectorDrawableTest/res/interpolator/trim_end_interpolator.xml
@@ -1,2 +1,16 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
 <pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
     android:pathData="C0.2,0 0.1,1 0.5, 1 L 1,1" />
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/interpolator/trim_start_interpolator.xml b/tests/VectorDrawableTest/res/interpolator/trim_start_interpolator.xml
index 798f7e6..c06c196 100644
--- a/tests/VectorDrawableTest/res/interpolator/trim_start_interpolator.xml
+++ b/tests/VectorDrawableTest/res/interpolator/trim_start_interpolator.xml
@@ -1,2 +1,16 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
 <pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
     android:pathData="L0.5,0 C 0.7,0 0.6,1 1, 1" />
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
index 05bf166..3045839 100644
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
@@ -26,6 +26,12 @@
     private static final String LOGCAT = "AnimatedVectorDrawableTest";
 
     protected int[] icon = {
+            R.drawable.ic_open_animation,
+            R.drawable.ic_rotate_2_portrait_v2_animation,
+            R.drawable.ic_signal_airplane_v2_animation,
+            R.drawable.ic_hourglass_animation,
+            R.drawable.ic_cast_v2_animation,
+            R.drawable.ic_bluethooth_v2_animation,
             R.drawable.animation_vector_linear_progress_bar,
             R.drawable.animation_vector_drawable_grouping_1,
             R.drawable.animation_vector_progress_bar,
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
index 37e0435..1cd6533 100644
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
@@ -56,6 +56,7 @@
             R.drawable.vector_drawable26,
             R.drawable.vector_drawable27,
             R.drawable.vector_drawable28,
+            R.drawable.vector_drawable29,
     };
 
     @Override
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index 117fc24..b7f64f6 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -1141,9 +1141,10 @@
 ssize_t AaptAssets::slurpFullTree(Bundle* bundle, const String8& srcDir,
                                     const AaptGroupEntry& kind,
                                     const String8& resType,
-                                    sp<FilePathStore>& fullResPaths)
+                                    sp<FilePathStore>& fullResPaths,
+                                    const bool overwrite)
 {
-    ssize_t res = AaptDir::slurpFullTree(bundle, srcDir, kind, resType, fullResPaths);
+    ssize_t res = AaptDir::slurpFullTree(bundle, srcDir, kind, resType, fullResPaths, overwrite);
     if (res > 0) {
         mGroupEntries.add(kind);
     }
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index d809c5b..7ae5368 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -591,7 +591,8 @@
                                   const String8& srcDir,
                                   const AaptGroupEntry& kind,
                                   const String8& resType,
-                                  sp<FilePathStore>& fullResPaths);
+                                  sp<FilePathStore>& fullResPaths,
+                                  const bool overwrite=false);
 
     ssize_t slurpResourceTree(Bundle* bundle, const String8& srcDir);
     ssize_t slurpResourceZip(Bundle* bundle, const char* filename);
diff --git a/tools/aapt/AaptConfig.cpp b/tools/aapt/AaptConfig.cpp
index 32a0cd3..f447462 100644
--- a/tools/aapt/AaptConfig.cpp
+++ b/tools/aapt/AaptConfig.cpp
@@ -240,7 +240,9 @@
     }
 
     uint16_t minSdk = 0;
-    if (config->smallestScreenWidthDp != ResTable_config::SCREENWIDTH_ANY
+    if (config->density == ResTable_config::DENSITY_ANY) {
+        minSdk = SDK_L;
+    } else if (config->smallestScreenWidthDp != ResTable_config::SCREENWIDTH_ANY
             || config->screenWidthDp != ResTable_config::SCREENWIDTH_ANY
             || config->screenHeightDp != ResTable_config::SCREENHEIGHT_ANY) {
         minSdk = SDK_HONEYCOMB_MR2;
@@ -255,8 +257,6 @@
                 != ResTable_config::SCREENLONG_ANY
             || config->density != ResTable_config::DENSITY_DEFAULT) {
         minSdk = SDK_DONUT;
-    } else if ((config->density == ResTable_config::DENSITY_ANY)) {
-        minSdk = SDK_L;
     }
 
     if (minSdk > config->sdkVersion) {
diff --git a/tools/aapt/ConfigDescription.h b/tools/aapt/ConfigDescription.h
index 779c423..4f999a2 100644
--- a/tools/aapt/ConfigDescription.h
+++ b/tools/aapt/ConfigDescription.h
@@ -28,10 +28,12 @@
         memset(this, 0, sizeof(*this));
         size = sizeof(android::ResTable_config);
     }
+
     ConfigDescription(const android::ResTable_config&o) {
         *static_cast<android::ResTable_config*>(this) = o;
         size = sizeof(android::ResTable_config);
     }
+
     ConfigDescription(const ConfigDescription&o) {
         *static_cast<android::ResTable_config*>(this) = o;
     }
@@ -41,6 +43,7 @@
         size = sizeof(android::ResTable_config);
         return *this;
     }
+
     ConfigDescription& operator=(const ConfigDescription& o) {
         *static_cast<android::ResTable_config*>(this) = o;
         return *this;
diff --git a/tools/aapt/ResourceIdCache.cpp b/tools/aapt/ResourceIdCache.cpp
index d60a07fc..8835fb0 100644
--- a/tools/aapt/ResourceIdCache.cpp
+++ b/tools/aapt/ResourceIdCache.cpp
@@ -9,8 +9,6 @@
 #include <utils/Log.h>
 #include "ResourceIdCache.h"
 #include <map>
-using namespace std;
-
 
 static size_t mHits = 0;
 static size_t mMisses = 0;
@@ -29,7 +27,7 @@
     CacheEntry(const android::String16& name, uint32_t resId) : hashedName(name), id(resId) { }
 };
 
-static map< uint32_t, CacheEntry > mIdMap;
+static std::map< uint32_t, CacheEntry > mIdMap;
 
 
 // djb2; reasonable choice for strings when collisions aren't particularly important
@@ -63,7 +61,7 @@
         bool onlyPublic) {
     const String16 hashedName = makeHashableName(package, type, name, onlyPublic);
     const uint32_t hashcode = hash(hashedName);
-    map<uint32_t, CacheEntry>::iterator item = mIdMap.find(hashcode);
+    std::map<uint32_t, CacheEntry>::iterator item = mIdMap.find(hashcode);
     if (item == mIdMap.end()) {
         // cache miss
         mMisses++;
diff --git a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
index 8898856..b8b5fed 100644
--- a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
+++ b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
@@ -223,7 +223,7 @@
         result.decimalSeparator = '.';
         result.groupingSeparator = ',';
         result.patternSeparator = ' ';
-        result.percent = '%';
+        result.percent = "%";
         result.perMill = '\u2030';
         result.monetarySeparator = ' ';
         result.minusSign = "-";
diff --git a/tools/split-select/Abi.cpp b/tools/split-select/Abi.cpp
new file mode 100644
index 0000000..20654b6
--- /dev/null
+++ b/tools/split-select/Abi.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Abi.h"
+
+namespace split {
+namespace abi {
+
+static const std::vector<Variant> sNoneVariants = {};
+static const std::vector<Variant> sArmVariants =
+        {Variant::armeabi, Variant::armeabi_v7a, Variant::arm64_v8a};
+static const std::vector<Variant> sIntelVariants = {Variant::x86, Variant::x86_64};
+static const std::vector<Variant> sMipsVariants = {Variant::mips, Variant::mips64};
+
+Family getFamily(Variant variant) {
+    switch (variant) {
+        case Variant::none:
+            return Family::none;
+        case Variant::armeabi:
+        case Variant::armeabi_v7a:
+        case Variant::arm64_v8a:
+            return Family::arm;
+        case Variant::x86:
+        case Variant::x86_64:
+            return Family::intel;
+        case Variant::mips:
+        case Variant::mips64:
+            return Family::mips;
+    }
+    return Family::none;
+}
+
+const std::vector<Variant>& getVariants(Family family) {
+    switch (family) {
+        case Family::none:
+            return sNoneVariants;
+        case Family::arm:
+            return sArmVariants;
+        case Family::intel:
+            return sIntelVariants;
+        case Family::mips:
+            return sMipsVariants;
+    }
+    return sNoneVariants;
+}
+
+const char* toString(Variant variant) {
+    switch (variant) {
+        case Variant::none:
+            return "";
+        case Variant::armeabi:
+            return "armeabi";
+        case Variant::armeabi_v7a:
+            return "armeabi-v7a";
+        case Variant::arm64_v8a:
+            return "arm64-v8a";
+        case Variant::x86:
+            return "x86";
+        case Variant::x86_64:
+            return "x86_64";
+        case Variant::mips:
+            return "mips";
+        case Variant::mips64:
+            return "mips64";
+    }
+    return "";
+}
+
+} // namespace abi
+} // namespace split
diff --git a/tools/split-select/Abi.h b/tools/split-select/Abi.h
new file mode 100644
index 0000000..3e00eba
--- /dev/null
+++ b/tools/split-select/Abi.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef H_ANDROID_SPLIT_ABI
+#define H_ANDROID_SPLIT_ABI
+
+#include <vector>
+
+namespace split {
+namespace abi {
+
+enum class Variant {
+    none = 0,
+    armeabi,
+    armeabi_v7a,
+    arm64_v8a,
+    x86,
+    x86_64,
+    mips,
+    mips64,
+};
+
+enum class Family {
+    none,
+    arm,
+    intel,
+    mips,
+};
+
+Family getFamily(Variant variant);
+const std::vector<Variant>& getVariants(Family family);
+const char* toString(Variant variant);
+
+} // namespace abi
+} // namespace split
+
+#endif // H_ANDROID_SPLIT_ABI
diff --git a/tools/split-select/Android.mk b/tools/split-select/Android.mk
new file mode 100644
index 0000000..d0b7287
--- /dev/null
+++ b/tools/split-select/Android.mk
@@ -0,0 +1,119 @@
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# This tool is prebuilt if we're doing an app-only build.
+ifeq ($(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)),)
+
+# TODO(adamlesinski): Enable OS X builds when I figure out how
+# to build with clang and libc++
+ifneq ($(HOST_OS),darwin)
+
+# ==========================================================
+# Setup some common variables for the different build
+# targets here.
+# ==========================================================
+LOCAL_PATH:= $(call my-dir)
+
+main := Main.cpp
+sources := \
+    Abi.cpp \
+    Grouper.cpp \
+    Rule.cpp \
+    RuleGenerator.cpp \
+    SplitDescription.cpp
+
+testSources := \
+    Grouper_test.cpp \
+    Rule_test.cpp \
+    RuleGenerator_test.cpp
+
+cIncludes := \
+    external/zlib \
+    frameworks/base/tools
+
+hostLdLibs :=
+hostStaticLibs := \
+    libaapt \
+    libandroidfw \
+    libpng \
+    liblog \
+    libutils \
+    libcutils \
+    libexpat \
+    libziparchive-host
+
+cFlags := -std=c++11 -Wall -Werror
+
+ifeq ($(HOST_OS),linux)
+    hostLdLibs += -lrt -ldl -lpthread
+endif
+
+# Statically link libz for MinGW (Win SDK under Linux),
+# and dynamically link for all others.
+ifneq ($(strip $(USE_MINGW)),)
+    hostStaticLibs += libz
+else
+    hostLdLibs += -lz
+endif
+
+
+# ==========================================================
+# Build the host static library: libsplit-select
+# ==========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libsplit-select
+
+LOCAL_SRC_FILES := $(sources)
+
+LOCAL_C_INCLUDES += $(cIncludes)
+LOCAL_CFLAGS += $(cFlags) -D_DARWIN_UNLIMITED_STREAMS
+
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+
+# ==========================================================
+# Build the host tests: libsplit-select_tests
+# ==========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libsplit-select_tests
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(testSources)
+
+LOCAL_C_INCLUDES += $(cIncludes)
+LOCAL_STATIC_LIBRARIES += libsplit-select $(hostStaticLibs)
+LOCAL_LDLIBS += $(hostLdLibs)
+LOCAL_CFLAGS += $(cFlags)
+
+include $(BUILD_HOST_NATIVE_TEST)
+
+# ==========================================================
+# Build the host executable: split-select
+# ==========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := split-select
+
+LOCAL_SRC_FILES := $(main)
+
+LOCAL_C_INCLUDES += $(cIncludes)
+LOCAL_STATIC_LIBRARIES += libsplit-select $(hostStaticLibs)
+LOCAL_LDLIBS += $(hostLdLibs)
+LOCAL_CFLAGS += $(cFlags)
+
+include $(BUILD_HOST_EXECUTABLE)
+
+endif # Not OS X
+endif # No TARGET_BUILD_APPS or TARGET_BUILD_PDK
diff --git a/tools/split-select/Grouper.cpp b/tools/split-select/Grouper.cpp
new file mode 100644
index 0000000..15edf89
--- /dev/null
+++ b/tools/split-select/Grouper.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Grouper.h"
+
+#include "SplitDescription.h"
+
+#include <utils/KeyedVector.h>
+#include <utils/Vector.h>
+
+using namespace android;
+
+namespace split {
+
+template <typename Key, typename Value>
+static void addToVector(KeyedVector<Key, SortedVector<Value> >& group,
+        const Key& key, const Value& value) {
+    ssize_t idx = group.indexOfKey(key);
+    if (idx < 0) {
+        idx = group.add(key, SortedVector<Value>());
+    }
+    group.editValueAt(idx).add(value);
+}
+
+Vector<SortedVector<SplitDescription> >
+groupByMutualExclusivity(const Vector<SplitDescription>& splits) {
+    Vector<SortedVector<SplitDescription> > groups;
+
+    // Find mutually exclusive splits and group them.
+    KeyedVector<SplitDescription, SortedVector<SplitDescription> > densityGroups;
+    KeyedVector<SplitDescription, SortedVector<SplitDescription> > abiGroups;
+    KeyedVector<SplitDescription, SortedVector<SplitDescription> > localeGroups;
+    for (const SplitDescription& split : splits) {
+        if (split.config.density != 0) {
+            SplitDescription key(split);
+            key.config.density = 0;
+            key.config.sdkVersion = 0; // Ignore density so we can support anydpi.
+            addToVector(densityGroups, key, split);
+        } else if (split.abi != abi::Variant::none) {
+            SplitDescription key(split);
+            key.abi = abi::Variant::none;
+            addToVector(abiGroups, key, split);
+        } else if (split.config.locale != 0) {
+            SplitDescription key(split);
+            key.config.clearLocale();
+            addToVector(localeGroups, key, split);
+        } else {
+            groups.add();
+            groups.editTop().add(split);
+        }
+    }
+
+    const size_t densityCount = densityGroups.size();
+    for (size_t i = 0; i < densityCount; i++) {
+        groups.add(densityGroups[i]);
+    }
+
+    const size_t abiCount = abiGroups.size();
+    for (size_t i = 0; i < abiCount; i++) {
+        groups.add(abiGroups[i]);
+    }
+
+    const size_t localeCount = localeGroups.size();
+    for (size_t i = 0; i < localeCount; i++) {
+        groups.add(localeGroups[i]);
+    }
+    return groups;
+}
+
+} // namespace split
diff --git a/tools/split-select/Grouper.h b/tools/split-select/Grouper.h
new file mode 100644
index 0000000..5cb0b5b
--- /dev/null
+++ b/tools/split-select/Grouper.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef H_ANDROID_SPLIT_GROUPER
+#define H_ANDROID_SPLIT_GROUPER
+
+#include "SplitDescription.h"
+
+#include <utils/SortedVector.h>
+#include <utils/Vector.h>
+
+namespace split {
+
+android::Vector<android::SortedVector<SplitDescription> >
+groupByMutualExclusivity(const android::Vector<SplitDescription>& splits);
+
+} // namespace split
+
+#endif // H_ANDROID_SPLIT_GROUPER
diff --git a/tools/split-select/Grouper_test.cpp b/tools/split-select/Grouper_test.cpp
new file mode 100644
index 0000000..4d146cd
--- /dev/null
+++ b/tools/split-select/Grouper_test.cpp
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Grouper.h"
+
+#include "SplitDescription.h"
+
+#include <gtest/gtest.h>
+#include <initializer_list>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+using namespace android;
+
+namespace split {
+
+class GrouperTest : public ::testing::Test {
+protected:
+    virtual void SetUp() {
+        Vector<SplitDescription> splits;
+        addSplit(splits, "en-rUS-sw600dp-hdpi");
+        addSplit(splits, "fr-rFR-sw600dp-hdpi");
+        addSplit(splits, "fr-rFR-sw600dp-xhdpi");
+        addSplit(splits, ":armeabi");
+        addSplit(splits, "en-rUS-sw300dp-xhdpi");
+        addSplit(splits, "large");
+        addSplit(splits, "pl-rPL");
+        addSplit(splits, "xlarge");
+        addSplit(splits, "en-rUS-sw600dp-xhdpi");
+        addSplit(splits, "en-rUS-sw300dp-hdpi");
+        addSplit(splits, "xxhdpi");
+        addSplit(splits, "hdpi");
+        addSplit(splits, "de-rDE");
+        addSplit(splits, "xhdpi");
+        addSplit(splits, ":x86");
+        addSplit(splits, "anydpi");
+        addSplit(splits, "v7");
+        addSplit(splits, "v8");
+        addSplit(splits, "sw600dp");
+        addSplit(splits, "sw300dp");
+        mGroups = groupByMutualExclusivity(splits);
+    }
+
+    void addSplit(Vector<SplitDescription>& splits, const char* str);
+    void expectHasGroupWithSplits(std::initializer_list<const char*> l);
+
+    Vector<SortedVector<SplitDescription> > mGroups;
+};
+
+TEST_F(GrouperTest, shouldHaveCorrectNumberOfGroups) {
+    EXPECT_EQ(12u, mGroups.size());
+}
+
+TEST_F(GrouperTest, shouldGroupDensities) {
+    expectHasGroupWithSplits({"en-rUS-sw300dp-hdpi", "en-rUS-sw300dp-xhdpi"});
+    expectHasGroupWithSplits({"en-rUS-sw600dp-hdpi", "en-rUS-sw600dp-xhdpi"});
+    expectHasGroupWithSplits({"fr-rFR-sw600dp-hdpi", "fr-rFR-sw600dp-xhdpi"});
+    expectHasGroupWithSplits({"hdpi", "xhdpi", "xxhdpi", "anydpi"});
+}
+
+TEST_F(GrouperTest, shouldGroupAbi) {
+    expectHasGroupWithSplits({":armeabi", ":x86"});
+}
+
+TEST_F(GrouperTest, shouldGroupLocale) {
+    expectHasGroupWithSplits({"pl-rPL", "de-rDE"});
+}
+
+TEST_F(GrouperTest, shouldGroupEachSplitIntoItsOwnGroup) {
+    expectHasGroupWithSplits({"large"});
+    expectHasGroupWithSplits({"xlarge"});
+    expectHasGroupWithSplits({"v7"});
+    expectHasGroupWithSplits({"v8"});
+    expectHasGroupWithSplits({"sw600dp"});
+    expectHasGroupWithSplits({"sw300dp"});
+}
+
+//
+// Helper methods
+//
+
+void GrouperTest::expectHasGroupWithSplits(std::initializer_list<const char*> l) {
+    Vector<SplitDescription> splits;
+    for (const char* str : l) {
+        splits.add();
+        if (!SplitDescription::parse(String8(str), &splits.editTop())) {
+            ADD_FAILURE() << "Failed to parse SplitDescription " << str;
+            return;
+        }
+    }
+    const size_t splitCount = splits.size();
+
+    const size_t groupCount = mGroups.size();
+    for (size_t i = 0; i < groupCount; i++) {
+        const SortedVector<SplitDescription>& group = mGroups[i];
+        if (group.size() != splitCount) {
+            continue;
+        }
+
+        size_t found = 0;
+        for (size_t j = 0; j < splitCount; j++) {
+            if (group.indexOf(splits[j]) >= 0) {
+                found++;
+            }
+        }
+
+        if (found == splitCount) {
+            return;
+        }
+    }
+
+    String8 errorMessage("Failed to find expected group [");
+    for (size_t i = 0; i < splitCount; i++) {
+        if (i != 0) {
+            errorMessage.append(", ");
+        }
+        errorMessage.append(splits[i].toString());
+    }
+    errorMessage.append("].\nActual:\n");
+
+    for (size_t i = 0; i < groupCount; i++) {
+        errorMessage.appendFormat("Group %d:\n", int(i + 1));
+        const SortedVector<SplitDescription>& group = mGroups[i];
+        for (size_t j = 0; j < group.size(); j++) {
+            errorMessage.append("  ");
+            errorMessage.append(group[j].toString());
+            errorMessage.append("\n");
+        }
+    }
+    ADD_FAILURE() << errorMessage.string();
+}
+
+void GrouperTest::addSplit(Vector<SplitDescription>& splits, const char* str) {
+    splits.add();
+    EXPECT_TRUE(SplitDescription::parse(String8(str), &splits.editTop()));
+}
+
+} // namespace split
diff --git a/tools/split-select/Main.cpp b/tools/split-select/Main.cpp
new file mode 100644
index 0000000..d6251c3
--- /dev/null
+++ b/tools/split-select/Main.cpp
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+#include <cstdio>
+
+#include "aapt/AaptUtil.h"
+
+#include "Grouper.h"
+#include "Rule.h"
+#include "RuleGenerator.h"
+#include "SplitDescription.h"
+
+#include <androidfw/AssetManager.h>
+#include <androidfw/ResourceTypes.h>
+#include <utils/KeyedVector.h>
+#include <utils/Vector.h>
+
+using namespace android;
+
+namespace split {
+
+static void usage() {
+    fprintf(stderr,
+            "split-select --help\n"
+            "split-select --target <config> --split <path/to/apk> [--split <path/to/apk> [...]]\n"
+            "split-select --generate --split <path/to/apk> [--split <path/to/apk> [...]]\n"
+            "\n"
+            "  --help                   Displays more information about this program.\n"
+            "  --target <config>        Performs the Split APK selection on the given configuration.\n"
+            "  --generate               Generates the logic for selecting the Split APK, in JSON format.\n"
+            "  --split <path/to/apk>    Includes a Split APK in the selection process.\n"
+            "\n"
+            "  Where <config> is an extended AAPT resource qualifier of the form\n"
+            "  'resource-qualifiers:extended-qualifiers', where 'resource-qualifiers' is an AAPT resource\n"
+            "  qualifier (ex: en-rUS-sw600dp-xhdpi), and 'extended-qualifiers' is an ordered list of one\n"
+            "  qualifier (or none) from each category:\n"
+            "    Architecture: armeabi, armeabi-v7a, arm64-v8a, x86, x86_64, mips\n");
+}
+
+static void help() {
+    usage();
+    fprintf(stderr, "\n"
+            "  Generates the logic for selecting a Split APK given some target Android device configuration.\n"
+            "  Using the flag --generate will emit a JSON encoded tree of rules that must be satisfied in order\n"
+            "  to install the given Split APK. Using the flag --target along with the device configuration\n"
+            "  will emit the set of Split APKs to install, following the same logic that would have been emitted\n"
+            "  via JSON.\n");
+}
+
+class SplitSelector {
+public:
+    SplitSelector() = default;
+    SplitSelector(const Vector<SplitDescription>& splits);
+
+    Vector<SplitDescription> getBestSplits(const SplitDescription& target) const;
+
+    template <typename RuleGenerator>
+    KeyedVector<SplitDescription, sp<Rule> > getRules() const;
+
+private:
+    Vector<SortedVector<SplitDescription> > mGroups;
+};
+
+SplitSelector::SplitSelector(const Vector<SplitDescription>& splits)
+    : mGroups(groupByMutualExclusivity(splits)) {
+}
+
+static void selectBestFromGroup(const SortedVector<SplitDescription>& splits,
+        const SplitDescription& target, Vector<SplitDescription>& splitsOut) {
+    SplitDescription bestSplit;
+    bool isSet = false;
+    const size_t splitCount = splits.size();
+    for (size_t j = 0; j < splitCount; j++) {
+        const SplitDescription& thisSplit = splits[j];
+        if (!thisSplit.match(target)) {
+            continue;
+        }
+
+        if (!isSet || thisSplit.isBetterThan(bestSplit, target)) {
+            isSet = true;
+            bestSplit = thisSplit;
+        }
+    }
+
+    if (isSet) {
+        splitsOut.add(bestSplit);
+    }
+}
+
+Vector<SplitDescription> SplitSelector::getBestSplits(const SplitDescription& target) const {
+    Vector<SplitDescription> bestSplits;
+    const size_t groupCount = mGroups.size();
+    for (size_t i = 0; i < groupCount; i++) {
+        selectBestFromGroup(mGroups[i], target, bestSplits);
+    }
+    return bestSplits;
+}
+
+template <typename RuleGenerator>
+KeyedVector<SplitDescription, sp<Rule> > SplitSelector::getRules() const {
+    KeyedVector<SplitDescription, sp<Rule> > rules;
+
+    const size_t groupCount = mGroups.size();
+    for (size_t i = 0; i < groupCount; i++) {
+        const SortedVector<SplitDescription>& splits = mGroups[i];
+        const size_t splitCount = splits.size();
+        for (size_t j = 0; j < splitCount; j++) {
+            sp<Rule> rule = Rule::simplify(RuleGenerator::generate(splits, j));
+            if (rule != NULL) {
+                rules.add(splits[j], rule);
+            }
+        }
+    }
+    return rules;
+}
+
+Vector<SplitDescription> select(const SplitDescription& target, const Vector<SplitDescription>& splits) {
+    const SplitSelector selector(splits);
+    return selector.getBestSplits(target);
+}
+
+void generate(const KeyedVector<String8, Vector<SplitDescription> >& splits) {
+    Vector<SplitDescription> allSplits;
+    const size_t apkSplitCount = splits.size();
+    for (size_t i = 0; i < apkSplitCount; i++) {
+        allSplits.appendVector(splits[i]);
+    }
+    const SplitSelector selector(allSplits);
+    KeyedVector<SplitDescription, sp<Rule> > rules(selector.getRules<RuleGenerator>());
+
+    fprintf(stdout, "[\n");
+    for (size_t i = 0; i < apkSplitCount; i++) {
+        sp<Rule> masterRule = new Rule();
+        masterRule->op = Rule::OR_SUBRULES;
+        const Vector<SplitDescription>& splitDescriptions = splits[i];
+        const size_t splitDescriptionCount = splitDescriptions.size();
+        for (size_t j = 0; j < splitDescriptionCount; j++) {
+            masterRule->subrules.add(rules.valueFor(splitDescriptions[j]));
+        }
+        masterRule = Rule::simplify(masterRule);
+        fprintf(stdout, "  {\n    \"path\": \"%s\",\n    \"rules\": %s\n  }%s\n",
+                splits.keyAt(i).string(),
+                masterRule->toJson(2).string(),
+                i < apkSplitCount - 1 ? "," : "");
+    }
+    fprintf(stdout, "]\n");
+}
+
+static void removeRuntimeQualifiers(ConfigDescription* outConfig) {
+    outConfig->imsi = 0;
+    outConfig->orientation = ResTable_config::ORIENTATION_ANY;
+    outConfig->screenWidth = ResTable_config::SCREENWIDTH_ANY;
+    outConfig->screenHeight = ResTable_config::SCREENHEIGHT_ANY;
+    outConfig->uiMode &= ResTable_config::UI_MODE_NIGHT_ANY;
+}
+
+static Vector<SplitDescription> extractSplitDescriptionsFromApk(const String8& path) {
+    AssetManager assetManager;
+    Vector<SplitDescription> splits;
+    int32_t cookie = 0;
+    if (!assetManager.addAssetPath(path, &cookie)) {
+        return splits;
+    }
+
+    const ResTable& res = assetManager.getResources(false);
+    if (res.getError() == NO_ERROR) {
+        Vector<ResTable_config> configs;
+        res.getConfigurations(&configs);
+        const size_t configCount = configs.size();
+        for (size_t i = 0; i < configCount; i++) {
+            splits.add();
+            splits.editTop().config = configs[i];
+        }
+    }
+
+    AssetDir* dir = assetManager.openNonAssetDir(cookie, "lib");
+    if (dir != NULL) {
+        const size_t fileCount = dir->getFileCount();
+        for (size_t i = 0; i < fileCount; i++) {
+            splits.add();
+            Vector<String8> parts = AaptUtil::splitAndLowerCase(dir->getFileName(i), '-');
+            if (parseAbi(parts, 0, &splits.editTop()) < 0) {
+                fprintf(stderr, "Malformed library %s\n", dir->getFileName(i).string());
+                splits.pop();
+            }
+        }
+        delete dir;
+    }
+    return splits;
+}
+
+static int main(int argc, char** argv) {
+    // Skip over the first argument.
+    argc--;
+    argv++;
+
+    bool generateFlag = false;
+    String8 targetConfigStr;
+    Vector<String8> splitApkPaths;
+    while (argc > 0) {
+        const String8 arg(*argv);
+        if (arg == "--target") {
+            argc--;
+            argv++;
+            if (argc < 1) {
+                fprintf(stderr, "Missing parameter for --split.\n");
+                usage();
+                return 1;
+            }
+            targetConfigStr.setTo(*argv);
+        } else if (arg == "--split") {
+            argc--;
+            argv++;
+            if (argc < 1) {
+                fprintf(stderr, "Missing parameter for --split.\n");
+                usage();
+                return 1;
+            }
+            splitApkPaths.add(String8(*argv));
+        } else if (arg == "--generate") {
+            generateFlag = true;
+        } else if (arg == "--help") {
+            help();
+            return 0;
+        } else {
+            fprintf(stderr, "Unknown argument '%s'\n", arg.string());
+            usage();
+            return 1;
+        }
+        argc--;
+        argv++;
+    }
+
+    if (!generateFlag && targetConfigStr == "") {
+        usage();
+        return 1;
+    }
+
+    if (splitApkPaths.size() == 0) {
+        usage();
+        return 1;
+    }
+
+    SplitDescription targetSplit;
+    if (!generateFlag) {
+        if (!SplitDescription::parse(targetConfigStr, &targetSplit)) {
+            fprintf(stderr, "Invalid --target config: '%s'\n",
+                    targetConfigStr.string());
+            usage();
+            return 1;
+        }
+
+        // We don't want to match on things that will change at run-time
+        // (orientation, w/h, etc.).
+        removeRuntimeQualifiers(&targetSplit.config);
+    }
+
+    KeyedVector<String8, Vector<SplitDescription> > apkPathSplitMap;
+    KeyedVector<SplitDescription, String8> splitApkPathMap;
+    Vector<SplitDescription> splitConfigs;
+    const size_t splitCount = splitApkPaths.size();
+    for (size_t i = 0; i < splitCount; i++) {
+        Vector<SplitDescription> splits = extractSplitDescriptionsFromApk(splitApkPaths[i]);
+        if (splits.isEmpty()) {
+            fprintf(stderr, "Invalid --split path: '%s'. No splits found.\n",
+                    splitApkPaths[i].string());
+            usage();
+            return 1;
+        }
+        apkPathSplitMap.replaceValueFor(splitApkPaths[i], splits);
+        const size_t apkSplitDescriptionCount = splits.size();
+        for (size_t j = 0; j < apkSplitDescriptionCount; j++) {
+            splitApkPathMap.replaceValueFor(splits[j], splitApkPaths[i]);
+        }
+        splitConfigs.appendVector(splits);
+    }
+
+    if (!generateFlag) {
+        Vector<SplitDescription> matchingConfigs = select(targetSplit, splitConfigs);
+        const size_t matchingConfigCount = matchingConfigs.size();
+        SortedVector<String8> matchingSplitPaths;
+        for (size_t i = 0; i < matchingConfigCount; i++) {
+            matchingSplitPaths.add(splitApkPathMap.valueFor(matchingConfigs[i]));
+        }
+
+        const size_t matchingSplitApkPathCount = matchingSplitPaths.size();
+        for (size_t i = 0; i < matchingSplitApkPathCount; i++) {
+            fprintf(stderr, "%s\n", matchingSplitPaths[i].string());
+        }
+    } else {
+        generate(apkPathSplitMap);
+    }
+    return 0;
+}
+
+} // namespace split
+
+int main(int argc, char** argv) {
+    return split::main(argc, argv);
+}
diff --git a/tools/split-select/Rule.cpp b/tools/split-select/Rule.cpp
new file mode 100644
index 0000000..9559fe2
--- /dev/null
+++ b/tools/split-select/Rule.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Rule.h"
+
+#include <utils/String8.h>
+
+using namespace android;
+
+namespace split {
+
+inline static void indentStr(String8& str, int indent) {
+    while (indent > 0) {
+        str.append("  ");
+        indent--;
+    }
+}
+
+String8 Rule::toJson(int indent) const {
+    String8 str;
+    indentStr(str, indent);
+    str.append("{\n");
+    indent++;
+    indentStr(str, indent);
+    str.append("\"op\": \"");
+    switch (op) {
+        case ALWAYS_TRUE:
+            str.append("ALWAYS_TRUE");
+            break;
+        case GREATER_THAN:
+            str.append("GREATER_THAN");
+            break;
+        case LESS_THAN:
+            str.append("LESS_THAN");
+            break;
+        case EQUALS:
+            str.append("EQUALS");
+            break;
+        case AND_SUBRULES:
+            str.append("AND_SUBRULES");
+            break;
+        case OR_SUBRULES:
+            str.append("OR_SUBRULES");
+            break;
+        case CONTAINS_ANY:
+            str.append("CONTAINS_ANY");
+            break;
+        default:
+            str.appendFormat("%d", op);
+            break;
+    }
+    str.append("\"");
+
+    if (negate) {
+        str.append(",\n");
+        indentStr(str, indent);
+        str.append("\"negate\": true");
+    }
+
+    bool includeKey = true;
+    switch (op) {
+        case AND_SUBRULES:
+        case OR_SUBRULES:
+            includeKey = false;
+            break;
+        default:
+            break;
+    }
+
+    if (includeKey) {
+        str.append(",\n");
+        indentStr(str, indent);
+        str.append("\"property\": \"");
+        switch (key) {
+            case NONE:
+                str.append("NONE");
+                break;
+            case SDK_VERSION:
+                str.append("SDK_VERSION");
+                break;
+            case SCREEN_DENSITY:
+                str.append("SCREEN_DENSITY");
+                break;
+            case NATIVE_PLATFORM:
+                str.append("NATIVE_PLATFORM");
+                break;
+            case LANGUAGE:
+                str.append("LANGUAGE");
+                break;
+            default:
+                str.appendFormat("%d", key);
+                break;
+        }
+        str.append("\"");
+    }
+
+    if (op == AND_SUBRULES || op == OR_SUBRULES) {
+        str.append(",\n");
+        indentStr(str, indent);
+        str.append("\"subrules\": [\n");
+        const size_t subruleCount = subrules.size();
+        for (size_t i = 0; i < subruleCount; i++) {
+            str.append(subrules[i]->toJson(indent + 1));
+            if (i != subruleCount - 1) {
+                str.append(",");
+            }
+            str.append("\n");
+        }
+        indentStr(str, indent);
+        str.append("]");
+    } else {
+        switch (key) {
+            case SDK_VERSION:
+            case SCREEN_DENSITY: {
+                str.append(",\n");
+                indentStr(str, indent);
+                str.append("\"args\": [");
+                const size_t argCount = longArgs.size();
+                for (size_t i = 0; i < argCount; i++) {
+                    if (i != 0) {
+                        str.append(", ");
+                    }
+                    str.appendFormat("%d", longArgs[i]);
+                }
+                str.append("]");
+                break;
+            }
+            case LANGUAGE:
+            case NATIVE_PLATFORM: {
+                str.append(",\n");
+                indentStr(str, indent);
+                str.append("\"args\": [");
+                const size_t argCount = stringArgs.size();
+                for (size_t i = 0; i < argCount; i++) {
+                    if (i != 0) {
+                        str.append(", ");
+                    }
+                    str.append(stringArgs[i]);
+                }
+                str.append("]");
+                break;
+            }
+            default:
+                break;
+        }
+    }
+    str.append("\n");
+    indent--;
+    indentStr(str, indent);
+    str.append("}");
+    return str;
+}
+
+sp<Rule> Rule::simplify(sp<Rule> rule) {
+    if (rule->op != AND_SUBRULES && rule->op != OR_SUBRULES) {
+        return rule;
+    }
+
+    Vector<sp<Rule> > newSubrules;
+    newSubrules.setCapacity(rule->subrules.size());
+    const size_t subruleCount = rule->subrules.size();
+    for (size_t i = 0; i < subruleCount; i++) {
+        sp<Rule> simplifiedRule = simplify(rule->subrules.editItemAt(i));
+        if (simplifiedRule != NULL) {
+            if (simplifiedRule->op == rule->op) {
+                newSubrules.appendVector(simplifiedRule->subrules);
+            } else {
+                newSubrules.add(simplifiedRule);
+            }
+        }
+    }
+
+    const size_t newSubruleCount = newSubrules.size();
+    if (newSubruleCount == 0) {
+        return NULL;
+    } else if (subruleCount == 1) {
+        return newSubrules.editTop();
+    }
+    rule->subrules = newSubrules;
+    return rule;
+}
+
+} // namespace split
diff --git a/tools/split-select/Rule.h b/tools/split-select/Rule.h
new file mode 100644
index 0000000..8029931
--- /dev/null
+++ b/tools/split-select/Rule.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef H_ANDROID_SPLIT_RULE
+#define H_ANDROID_SPLIT_RULE
+
+#include "SplitDescription.h"
+
+#include <utils/RefBase.h>
+#include <utils/StrongPointer.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+namespace split {
+
+struct Rule : public virtual android::RefBase {
+    inline Rule();
+
+    enum Operator {
+        LESS_THAN = 1,
+        GREATER_THAN,
+        EQUALS,
+        CONTAINS_ANY,
+        CONTAINS_ALL,
+        IS_TRUE,
+        IS_FALSE,
+        AND_SUBRULES,
+        OR_SUBRULES,
+        ALWAYS_TRUE,
+    };
+
+    Operator op;
+
+    enum Key {
+        NONE = 0,
+        SDK_VERSION,
+        SCREEN_DENSITY,
+        LANGUAGE,
+        NATIVE_PLATFORM,
+        TOUCH_SCREEN,
+        SCREEN_SIZE,
+        SCREEN_LAYOUT,
+    };
+
+    Key key;
+    bool negate;
+
+    android::Vector<android::String8> stringArgs;
+    android::Vector<int> longArgs;
+    android::Vector<double> doubleArgs;
+    android::Vector<android::sp<Rule> > subrules;
+
+    android::String8 toJson(int indent=0) const;
+
+    static android::sp<Rule> simplify(android::sp<Rule> rule);
+};
+
+Rule::Rule()
+: op(ALWAYS_TRUE)
+, key(NONE)
+, negate(false) {}
+
+} // namespace split
+
+#endif // H_ANDROID_SPLIT_RULE
diff --git a/tools/split-select/RuleGenerator.cpp b/tools/split-select/RuleGenerator.cpp
new file mode 100644
index 0000000..669ae78
--- /dev/null
+++ b/tools/split-select/RuleGenerator.cpp
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "RuleGenerator.h"
+
+#include <algorithm>
+#include <cmath>
+#include <vector>
+#include <androidfw/ResourceTypes.h>
+
+using namespace android;
+
+namespace split {
+
+// Calculate the point at which the density selection changes between l and h.
+static inline int findMid(int l, int h) {
+    double root = sqrt((h*h) + (8*l*h));
+    return (double(-h) + root) / 2.0;
+}
+
+sp<Rule> RuleGenerator::generateDensity(const Vector<int>& allDensities, size_t index) {
+    sp<Rule> densityRule = new Rule();
+    densityRule->op = Rule::AND_SUBRULES;
+
+    const bool anyDensity = allDensities[index] == ResTable_config::DENSITY_ANY;
+    sp<Rule> any = new Rule();
+    any->op = Rule::EQUALS;
+    any->key = Rule::SCREEN_DENSITY;
+    any->longArgs.add((int)ResTable_config::DENSITY_ANY);
+    any->negate = !anyDensity;
+    densityRule->subrules.add(any);
+
+    if (!anyDensity) {
+        if (index > 0) {
+            sp<Rule> gt = new Rule();
+            gt->op = Rule::GREATER_THAN;
+            gt->key = Rule::SCREEN_DENSITY;
+            gt->longArgs.add(findMid(allDensities[index - 1], allDensities[index]) - 1);
+            densityRule->subrules.add(gt);
+        }
+
+        if (index + 1 < allDensities.size() && allDensities[index + 1] != ResTable_config::DENSITY_ANY) {
+            sp<Rule> lt = new Rule();
+            lt->op = Rule::LESS_THAN;
+            lt->key = Rule::SCREEN_DENSITY;
+            lt->longArgs.add(findMid(allDensities[index], allDensities[index + 1]));
+            densityRule->subrules.add(lt);
+        }
+    }
+    return densityRule;
+}
+
+sp<Rule> RuleGenerator::generateAbi(const Vector<abi::Variant>& splitAbis, size_t index) {
+    const abi::Variant thisAbi = splitAbis[index];
+    const std::vector<abi::Variant>& familyVariants = abi::getVariants(abi::getFamily(thisAbi));
+
+    std::vector<abi::Variant>::const_iterator start =
+            std::find(familyVariants.begin(), familyVariants.end(), thisAbi);
+
+    std::vector<abi::Variant>::const_iterator end = familyVariants.end();
+    if (index + 1 < splitAbis.size()) {
+        end = std::find(start, familyVariants.end(), splitAbis[index + 1]);
+    }
+
+    sp<Rule> abiRule = new Rule();
+    abiRule->op = Rule::CONTAINS_ANY;
+    abiRule->key = Rule::NATIVE_PLATFORM;
+    while (start != end) {
+        abiRule->stringArgs.add(String8(abi::toString(*start)));
+        ++start;
+    }
+    return abiRule;
+}
+
+sp<Rule> RuleGenerator::generate(const SortedVector<SplitDescription>& group, size_t index) {
+    sp<Rule> rootRule = new Rule();
+    rootRule->op = Rule::AND_SUBRULES;
+
+    if (group[index].config.locale != 0) {
+        sp<Rule> locale = new Rule();
+        locale->op = Rule::EQUALS;
+        locale->key = Rule::LANGUAGE;
+        char str[RESTABLE_MAX_LOCALE_LEN];
+        group[index].config.getBcp47Locale(str);
+        locale->stringArgs.add(String8(str));
+        rootRule->subrules.add(locale);
+    }
+
+    if (group[index].config.sdkVersion != 0) {
+        sp<Rule> sdk = new Rule();
+        sdk->op = Rule::GREATER_THAN;
+        sdk->key = Rule::SDK_VERSION;
+        sdk->longArgs.add(group[index].config.sdkVersion - 1);
+        rootRule->subrules.add(sdk);
+    }
+
+    if (group[index].config.density != 0) {
+        size_t densityIndex = 0;
+        Vector<int> allDensities;
+        allDensities.add(group[index].config.density);
+
+        const size_t groupSize = group.size();
+        for (size_t i = 0; i < groupSize; i++) {
+            if (group[i].config.density != group[index].config.density) {
+                // This group differs by density.
+                allDensities.clear();
+                for (size_t j = 0; j < groupSize; j++) {
+                    allDensities.add(group[j].config.density);
+                }
+                densityIndex = index;
+                break;
+            }
+        }
+        rootRule->subrules.add(generateDensity(allDensities, densityIndex));
+    }
+
+    if (group[index].abi != abi::Variant::none) {
+        size_t abiIndex = 0;
+        Vector<abi::Variant> allVariants;
+        allVariants.add(group[index].abi);
+
+        const size_t groupSize = group.size();
+        for (size_t i = 0; i < groupSize; i++) {
+            if (group[i].abi != group[index].abi) {
+                // This group differs by ABI.
+                allVariants.clear();
+                for (size_t j = 0; j < groupSize; j++) {
+                    allVariants.add(group[j].abi);
+                }
+                abiIndex = index;
+                break;
+            }
+        }
+        rootRule->subrules.add(generateAbi(allVariants, abiIndex));
+    }
+
+    return rootRule;
+}
+
+} // namespace split
diff --git a/tools/split-select/RuleGenerator.h b/tools/split-select/RuleGenerator.h
new file mode 100644
index 0000000..619acd9
--- /dev/null
+++ b/tools/split-select/RuleGenerator.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef H_ANDROID_SPLIT_RULE_GENERATOR
+#define H_ANDROID_SPLIT_RULE_GENERATOR
+
+#include "Abi.h"
+#include "Rule.h"
+#include "SplitDescription.h"
+
+#include <utils/SortedVector.h>
+#include <utils/Vector.h>
+
+namespace split {
+
+struct RuleGenerator {
+    // Generate rules for a Split given the group of mutually exclusive splits it belongs to
+    static android::sp<Rule> generate(const android::SortedVector<SplitDescription>& group, size_t index);
+
+    static android::sp<Rule> generateAbi(const android::Vector<abi::Variant>& allVariants, size_t index);
+    static android::sp<Rule> generateDensity(const android::Vector<int>& allDensities, size_t index);
+};
+
+} // namespace split
+
+#endif // H_ANDROID_SPLIT_RULE_GENERATOR
diff --git a/tools/split-select/RuleGenerator_test.cpp b/tools/split-select/RuleGenerator_test.cpp
new file mode 100644
index 0000000..60baabe
--- /dev/null
+++ b/tools/split-select/RuleGenerator_test.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "RuleGenerator.h"
+
+#include <algorithm>
+#include <gtest/gtest.h>
+#include <utils/String8.h>
+
+using namespace android;
+
+namespace split {
+
+static void expectDensityRule(const Vector<int>& densities, int density, int greaterThan, int lessThan);
+static void expectAbiRule(const Vector<abi::Variant>& abis, abi::Variant variant,
+        std::initializer_list<const char*> matches);
+
+TEST(RuleGeneratorTest, testAbiRules) {
+    Vector<abi::Variant> abis;
+    abis.add(abi::Variant::armeabi);
+    abis.add(abi::Variant::armeabi_v7a);
+    abis.add(abi::Variant::x86);
+    std::sort(abis.begin(), abis.end());
+
+    expectAbiRule(abis, abi::Variant::armeabi, {"armeabi"});
+    expectAbiRule(abis, abi::Variant::armeabi_v7a, {"armeabi-v7a", "arm64-v8a"});
+    expectAbiRule(abis, abi::Variant::x86, {"x86", "x86_64"});
+}
+
+TEST(RuleGeneratorTest, testDensityRules) {
+    Vector<int> densities;
+    densities.add(ConfigDescription::DENSITY_HIGH);
+    densities.add(ConfigDescription::DENSITY_XHIGH);
+    densities.add(ConfigDescription::DENSITY_XXHIGH);
+    densities.add(ConfigDescription::DENSITY_ANY);
+
+    ASSERT_LT(263, ConfigDescription::DENSITY_XHIGH);
+    ASSERT_GT(262, ConfigDescription::DENSITY_HIGH);
+    ASSERT_LT(363, ConfigDescription::DENSITY_XXHIGH);
+    ASSERT_GT(362, ConfigDescription::DENSITY_XHIGH);
+
+    expectDensityRule(densities, ConfigDescription::DENSITY_HIGH, 0, 263);
+    expectDensityRule(densities, ConfigDescription::DENSITY_XHIGH, 262, 363);
+    expectDensityRule(densities, ConfigDescription::DENSITY_XXHIGH, 362, 0);
+    expectDensityRule(densities, ConfigDescription::DENSITY_ANY, 0, 0);
+}
+
+//
+// Helper methods.
+//
+
+static void expectDensityRule(const Vector<int>& densities, int density, int greaterThan, int lessThan) {
+    const int* iter = std::find(densities.begin(), densities.end(), density);
+    if (densities.end() == iter) {
+        ADD_FAILURE() << density << "dpi was not in the density list.";
+        return;
+    }
+
+    sp<Rule> rule = RuleGenerator::generateDensity(densities, iter - densities.begin());
+    if (rule->op != Rule::AND_SUBRULES) {
+        ADD_FAILURE() << "Op in rule for " << density << "dpi is not Rule::AND_SUBRULES.";
+        return;
+    }
+
+    size_t index = 0;
+
+    bool isAnyDpi = density == ConfigDescription::DENSITY_ANY;
+
+    sp<Rule> anyDpiRule = rule->subrules[index++];
+    EXPECT_EQ(Rule::EQUALS, anyDpiRule->op)
+            << "for " << density << "dpi ANY DPI rule";
+    EXPECT_EQ(Rule::SCREEN_DENSITY, anyDpiRule->key)
+            << "for " << density << "dpi ANY DPI rule";
+    EXPECT_EQ(isAnyDpi == false, anyDpiRule->negate)
+            << "for " << density << "dpi ANY DPI rule";
+    if (anyDpiRule->longArgs.size() == 1) {
+        EXPECT_EQ(ConfigDescription::DENSITY_ANY, anyDpiRule->longArgs[0])
+            << "for " << density << "dpi ANY DPI rule";
+    } else {
+        EXPECT_EQ(1u, anyDpiRule->longArgs.size())
+            << "for " << density << "dpi ANY DPI rule";
+    }
+
+
+    if (greaterThan != 0) {
+        sp<Rule> greaterThanRule = rule->subrules[index++];
+        EXPECT_EQ(Rule::GREATER_THAN, greaterThanRule->op)
+                << "for " << density << "dpi GREATER_THAN rule";
+        EXPECT_EQ(Rule::SCREEN_DENSITY, greaterThanRule->key)
+                << "for " << density << "dpi GREATER_THAN rule";
+        if (greaterThanRule->longArgs.size() == 1) {
+            EXPECT_EQ(greaterThan, greaterThanRule->longArgs[0])
+                << "for " << density << "dpi GREATER_THAN rule";
+        } else {
+            EXPECT_EQ(1u, greaterThanRule->longArgs.size())
+                << "for " << density << "dpi GREATER_THAN rule";
+        }
+    }
+
+    if (lessThan != 0) {
+        sp<Rule> lessThanRule = rule->subrules[index++];
+        EXPECT_EQ(Rule::LESS_THAN, lessThanRule->op)
+                << "for " << density << "dpi LESS_THAN rule";
+        EXPECT_EQ(Rule::SCREEN_DENSITY, lessThanRule->key)
+                << "for " << density << "dpi LESS_THAN rule";
+        if (lessThanRule->longArgs.size() == 1) {
+            EXPECT_EQ(lessThan, lessThanRule->longArgs[0])
+                << "for " << density << "dpi LESS_THAN rule";
+        } else {
+            EXPECT_EQ(1u, lessThanRule->longArgs.size())
+                << "for " << density << "dpi LESS_THAN rule";
+        }
+    }
+}
+
+static void expectAbiRule(const Vector<abi::Variant>& abis, abi::Variant variant,
+        std::initializer_list<const char*> matches) {
+    const abi::Variant* iter = std::find(abis.begin(), abis.end(), variant);
+    if (abis.end() == iter) {
+        ADD_FAILURE() << abi::toString(variant) << " was not in the abi list.";
+        return;
+    }
+
+    sp<Rule> rule = RuleGenerator::generateAbi(abis, iter - abis.begin());
+
+    EXPECT_EQ(Rule::CONTAINS_ANY, rule->op)
+            << "for " << abi::toString(variant) << " rule";
+    EXPECT_EQ(Rule::NATIVE_PLATFORM, rule->key)
+            << " for " << abi::toString(variant) << " rule";
+    EXPECT_EQ(matches.size(), rule->stringArgs.size())
+            << " for " << abi::toString(variant) << " rule";
+
+    for (const char* match : matches) {
+        if (rule->stringArgs.end() ==
+                std::find(rule->stringArgs.begin(), rule->stringArgs.end(), String8(match))) {
+            ADD_FAILURE() << "Rule for abi " << abi::toString(variant)
+                    << " does not contain match for expected abi " << match;
+        }
+    }
+}
+
+} // namespace split
diff --git a/tools/split-select/Rule_test.cpp b/tools/split-select/Rule_test.cpp
new file mode 100644
index 0000000..aca7433
--- /dev/null
+++ b/tools/split-select/Rule_test.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Rule.h"
+
+#include "SplitDescription.h"
+
+#include <algorithm>
+#include <string>
+#include <gtest/gtest.h>
+#include <utils/String8.h>
+
+using namespace android;
+
+namespace split {
+
+TEST(RuleTest, generatesValidJson) {
+    sp<Rule> rule = new Rule();
+    rule->op = Rule::AND_SUBRULES;
+
+    sp<Rule> subrule = new Rule();
+    subrule->op = Rule::EQUALS;
+    subrule->key = Rule::SDK_VERSION;
+    subrule->longArgs.add(7);
+    rule->subrules.add(subrule);
+
+    subrule = new Rule();
+    subrule->op = Rule::OR_SUBRULES;
+    rule->subrules.add(subrule);
+
+    sp<Rule> subsubrule = new Rule();
+    subsubrule->op = Rule::GREATER_THAN;
+    subsubrule->key = Rule::SCREEN_DENSITY;
+    subsubrule->longArgs.add(10);
+    subrule->subrules.add(subsubrule);
+
+    subsubrule = new Rule();
+    subsubrule->op = Rule::LESS_THAN;
+    subsubrule->key = Rule::SCREEN_DENSITY;
+    subsubrule->longArgs.add(5);
+    subrule->subrules.add(subsubrule);
+
+    std::string expected(
+            "{"
+            "  \"op\": \"AND_SUBRULES\","
+            "  \"subrules\": ["
+            "    {"
+            "      \"op\": \"EQUALS\","
+            "      \"property\": \"SDK_VERSION\","
+            "      \"args\": [7]"
+            "    },"
+            "    {"
+            "      \"op\": \"OR_SUBRULES\","
+            "      \"subrules\": ["
+            "        {"
+            "          \"op\": \"GREATER_THAN\","
+            "          \"property\": \"SCREEN_DENSITY\","
+            "          \"args\": [10]"
+            "        },"
+            "        {"
+            "          \"op\": \"LESS_THAN\","
+            "          \"property\": \"SCREEN_DENSITY\","
+            "          \"args\": [5]"
+            "        }"
+            "      ]"
+            "     }"
+            "  ]"
+            "}");
+    // Trim
+    expected.erase(std::remove_if(expected.begin(), expected.end(), ::isspace), expected.end());
+
+    std::string result(rule->toJson().string());
+
+    // Trim
+    result.erase(std::remove_if(result.begin(), result.end(), ::isspace), result.end());
+
+    ASSERT_EQ(expected, result);
+}
+
+TEST(RuleTest, simplifiesSingleSubruleRules) {
+    sp<Rule> rule = new Rule();
+    rule->op = Rule::AND_SUBRULES;
+
+    sp<Rule> subrule = new Rule();
+    subrule->op = Rule::EQUALS;
+    subrule->key = Rule::SDK_VERSION;
+    subrule->longArgs.add(7);
+    rule->subrules.add(subrule);
+
+    sp<Rule> simplified = Rule::simplify(rule);
+    EXPECT_EQ(Rule::EQUALS, simplified->op);
+    EXPECT_EQ(Rule::SDK_VERSION, simplified->key);
+    ASSERT_EQ(1u, simplified->longArgs.size());
+    EXPECT_EQ(7, simplified->longArgs[0]);
+}
+
+TEST(RuleTest, simplifiesNestedSameOpSubrules) {
+    sp<Rule> rule = new Rule();
+    rule->op = Rule::AND_SUBRULES;
+
+    sp<Rule> subrule = new Rule();
+    subrule->op = Rule::AND_SUBRULES;
+    rule->subrules.add(subrule);
+
+    sp<Rule> subsubrule = new Rule();
+    subsubrule->op = Rule::EQUALS;
+    subsubrule->key = Rule::SDK_VERSION;
+    subsubrule->longArgs.add(7);
+    subrule->subrules.add(subsubrule);
+
+    subrule = new Rule();
+    subrule->op = Rule::EQUALS;
+    subrule->key = Rule::SDK_VERSION;
+    subrule->longArgs.add(8);
+    rule->subrules.add(subrule);
+
+    sp<Rule> simplified = Rule::simplify(rule);
+    EXPECT_EQ(Rule::AND_SUBRULES, simplified->op);
+    ASSERT_EQ(2u, simplified->subrules.size());
+
+    sp<Rule> simplifiedSubrule = simplified->subrules[0];
+    EXPECT_EQ(Rule::EQUALS, simplifiedSubrule->op);
+    EXPECT_EQ(Rule::SDK_VERSION, simplifiedSubrule->key);
+    ASSERT_EQ(1u, simplifiedSubrule->longArgs.size());
+    EXPECT_EQ(7, simplifiedSubrule->longArgs[0]);
+
+    simplifiedSubrule = simplified->subrules[1];
+    EXPECT_EQ(Rule::EQUALS, simplifiedSubrule->op);
+    EXPECT_EQ(Rule::SDK_VERSION, simplifiedSubrule->key);
+    ASSERT_EQ(1u, simplifiedSubrule->longArgs.size());
+    EXPECT_EQ(8, simplifiedSubrule->longArgs[0]);
+}
+
+} // namespace split
diff --git a/tools/split-select/SplitDescription.cpp b/tools/split-select/SplitDescription.cpp
new file mode 100644
index 0000000..8037ef0
--- /dev/null
+++ b/tools/split-select/SplitDescription.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SplitDescription.h"
+
+#include "aapt/AaptConfig.h"
+#include "aapt/AaptUtil.h"
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+using namespace android;
+
+namespace split {
+
+SplitDescription::SplitDescription()
+: abi(abi::Variant::none) {
+}
+
+int SplitDescription::compare(const SplitDescription& rhs) const {
+    int cmp;
+    cmp = (int)abi - (int)rhs.abi;
+    if (cmp != 0) return cmp;
+    return config.compareLogical(rhs.config);
+}
+
+bool SplitDescription::isBetterThan(const SplitDescription& o, const SplitDescription& target) const {
+    if (abi != abi::Variant::none || o.abi != abi::Variant::none) {
+        abi::Family family = abi::getFamily(abi);
+        abi::Family oFamily = abi::getFamily(o.abi);
+        if (family != oFamily) {
+            return family != abi::Family::none;
+        }
+
+        if (int(target.abi) - int(abi) < int(target.abi) - int(o.abi)) {
+            return true;
+        }
+    }
+    return config.isBetterThan(o.config, &target.config);
+}
+
+bool SplitDescription::match(const SplitDescription& o) const {
+    if (abi != abi::Variant::none) {
+        abi::Family family = abi::getFamily(abi);
+        abi::Family oFamily = abi::getFamily(o.abi);
+        if (family != oFamily) {
+            return false;
+        }
+
+        if (int(abi) > int(o.abi)) {
+            return false;
+        }
+    }
+    return config.match(o.config);
+}
+
+String8 SplitDescription::toString() const {
+    String8 extension;
+    if (abi != abi::Variant::none) {
+        if (extension.isEmpty()) {
+            extension.append(":");
+        } else {
+            extension.append("-");
+        }
+        extension.append(abi::toString(abi));
+    }
+    String8 str(config.toString());
+    str.append(extension);
+    return str;
+}
+
+ssize_t parseAbi(const Vector<String8>& parts, const ssize_t index,
+        SplitDescription* outSplit) {
+    const ssize_t N = parts.size();
+    abi::Variant abi = abi::Variant::none;
+    ssize_t endIndex = index;
+    if (parts[endIndex] == "arm64") {
+        endIndex++;
+        if (endIndex < N) {
+            if (parts[endIndex] == "v8a") {
+                endIndex++;
+                abi = abi::Variant::arm64_v8a;
+            }
+        }
+    } else if (parts[endIndex] == "armeabi") {
+        endIndex++;
+        abi = abi::Variant::armeabi;
+        if (endIndex < N) {
+            if (parts[endIndex] == "v7a") {
+                endIndex++;
+                abi = abi::Variant::armeabi_v7a;
+            }
+        }
+    } else if (parts[endIndex] == "x86") {
+        endIndex++;
+        abi = abi::Variant::x86;
+    } else if (parts[endIndex] == "x86_64") {
+        endIndex++;
+        abi = abi::Variant::x86_64;
+    } else if (parts[endIndex] == "mips") {
+        endIndex++;
+        abi = abi::Variant::mips;
+    } else if (parts[endIndex] == "mips64") {
+        endIndex++;
+        abi = abi::Variant::mips64;
+    }
+
+    if (abi == abi::Variant::none && endIndex != index) {
+        return -1;
+    }
+
+    if (outSplit != NULL) {
+        outSplit->abi = abi;
+    }
+    return endIndex;
+}
+
+bool SplitDescription::parse(const String8& str, SplitDescription* outSplit) {
+    ssize_t index = str.find(":");
+
+    String8 configStr;
+    String8 extensionStr;
+    if (index >= 0) {
+        configStr.setTo(str.string(), index);
+        extensionStr.setTo(str.string() + index + 1);
+    } else {
+        configStr.setTo(str);
+    }
+
+    SplitDescription split;
+    if (!AaptConfig::parse(configStr, &split.config)) {
+        return false;
+    }
+
+    Vector<String8> parts = AaptUtil::splitAndLowerCase(extensionStr, '-');
+    const ssize_t N = parts.size();
+    index = 0;
+
+    if (extensionStr.length() == 0) {
+        goto success;
+    }
+
+    index = parseAbi(parts, index, &split);
+    if (index < 0) {
+        return false;
+    } else {
+        if (index == N) {
+            goto success;
+        }
+    }
+
+    // Unrecognized
+    return false;
+
+success:
+    if (outSplit != NULL) {
+        *outSplit = split;
+    }
+    return true;
+}
+
+} // namespace split
diff --git a/tools/split-select/SplitDescription.h b/tools/split-select/SplitDescription.h
new file mode 100644
index 0000000..5fcafc8
--- /dev/null
+++ b/tools/split-select/SplitDescription.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef H_ANDROID_SPLIT_SPLIT_DESCRIPTION
+#define H_ANDROID_SPLIT_SPLIT_DESCRIPTION
+
+#include "aapt/ConfigDescription.h"
+#include "Abi.h"
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+namespace split {
+
+struct SplitDescription {
+    SplitDescription();
+    SplitDescription(const SplitDescription&) = default;
+
+    ConfigDescription config;
+    abi::Variant abi;
+
+    int compare(const SplitDescription& rhs) const;
+    inline bool operator<(const SplitDescription& rhs) const;
+    inline bool operator==(const SplitDescription& rhs) const;
+    inline bool operator!=(const SplitDescription& rhs) const;
+
+    bool match(const SplitDescription& o) const;
+    bool isBetterThan(const SplitDescription& o, const SplitDescription& target) const;
+
+    android::String8 toString() const;
+
+    static bool parse(const android::String8& str, SplitDescription* outSplit);
+};
+
+ssize_t parseAbi(const android::Vector<android::String8>& parts, const ssize_t index,
+        SplitDescription* outSplit);
+
+bool SplitDescription::operator<(const SplitDescription& rhs) const {
+    return compare(rhs) < 0;
+}
+
+bool SplitDescription::operator==(const SplitDescription& rhs) const {
+    return compare(rhs) == 0;
+}
+
+bool SplitDescription::operator!=(const SplitDescription& rhs) const {
+    return compare(rhs) != 0;
+}
+
+} // namespace split
+
+#endif // H_ANDROID_SPLIT_SPLIT_DESCRIPTION
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 02e610c..0db7658 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -977,7 +977,8 @@
         if (this.didSelfAdd) sbuf.append(" didSelfAdd");
         if (this.selfAdded) sbuf.append(" selfAdded");
         if (this.noInternetAccess) sbuf.append(" noInternetAccess");
-        if (this.didSelfAdd || this.selfAdded || this.noInternetAccess) {
+        if (this.ephemeral) sbuf.append(" ephemeral");
+        if (this.didSelfAdd || this.selfAdded || this.noInternetAccess || this.ephemeral) {
             sbuf.append("\n");
         }
         sbuf.append(" KeyMgmt:");
@@ -1434,6 +1435,7 @@
             autoJoinStatus = source.autoJoinStatus;
             selfAdded = source.selfAdded;
             noInternetAccess = source.noInternetAccess;
+            ephemeral = source.ephemeral;
             if (source.visibility != null) {
                 visibility = new Visibility(source.visibility);
             }
@@ -1510,6 +1512,7 @@
         dest.writeInt(selfAdded ? 1 : 0);
         dest.writeInt(didSelfAdd ? 1 : 0);
         dest.writeInt(noInternetAccess ? 1 : 0);
+        dest.writeInt(ephemeral ? 1 : 0);
         dest.writeInt(creatorUid);
         dest.writeInt(lastConnectUid);
         dest.writeInt(lastUpdateUid);
@@ -1570,6 +1573,7 @@
                 config.selfAdded = in.readInt() != 0;
                 config.didSelfAdd = in.readInt() != 0;
                 config.noInternetAccess = in.readInt() != 0;
+                config.ephemeral = in.readInt() != 0;
                 config.creatorUid = in.readInt();
                 config.lastConnectUid = in.readInt();
                 config.lastUpdateUid = in.readInt();