Merge "Add new empty app test entry points." into lmp-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index c480a1b..fb26daf 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1056,6 +1056,7 @@
     field public static final int scrollbars = 16842974; // 0x10100de
     field public static final int scrollingCache = 16843006; // 0x10100fe
     field public static final deprecated int searchButtonText = 16843269; // 0x1010205
+    field public static final int searchHintIcon = 16844038; // 0x1010506
     field public static final int searchIcon = 16843907; // 0x1010483
     field public static final int searchMode = 16843221; // 0x10101d5
     field public static final int searchSettingsDescription = 16843402; // 0x101028a
@@ -3111,6 +3112,7 @@
     method public void removeAllUpdateListeners();
     method public void removeUpdateListener(android.animation.ValueAnimator.AnimatorUpdateListener);
     method public void reverse();
+    method public void setCurrentFraction(float);
     method public void setCurrentPlayTime(long);
     method public android.animation.ValueAnimator setDuration(long);
     method public void setEvaluator(android.animation.TypeEvaluator);
@@ -5402,8 +5404,8 @@
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
-    field public static final java.lang.String EXTRA_PROVISIONING_DONT_DISABLE_SYSTEM_APPS = "android.app.extra.PROVISIONING_DONT_DISABLE_SYSTEM_APPS";
     field public static final java.lang.String EXTRA_PROVISIONING_EMAIL_ADDRESS = "android.app.extra.PROVISIONING_EMAIL_ADDRESS";
+    field public static final java.lang.String EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED = "android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCAL_TIME = "android.app.extra.PROVISIONING_LOCAL_TIME";
     field public static final java.lang.String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.PROVISIONING_TIME_ZONE";
@@ -28512,8 +28514,8 @@
     method public android.os.Bundle getCarrierConfigValues();
     method public static android.telephony.SmsManager getDefault();
     method public static int getDefaultSmsSubscriptionId();
-    method public static android.telephony.SmsManager getSmsManagerForSubscriber(int);
-    method public int getSubId();
+    method public static android.telephony.SmsManager getSmsManagerForSubscriptionId(int);
+    method public int getSubscriptionId();
     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);
@@ -28545,6 +28547,7 @@
     field public static final java.lang.String MMS_CONFIG_NOTIFY_WAP_MMSC_ENABLED = "enabledNotifyWapMMSC";
     field public static final java.lang.String MMS_CONFIG_RECIPIENT_LIMIT = "recipientLimit";
     field public static final java.lang.String MMS_CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES = "sendMultipartSmsAsSeparateMessages";
+    field public static final java.lang.String MMS_CONFIG_SHOW_CELL_BROADCAST_APP_LINKS = "config_cellBroadcastAppLinks";
     field public static final java.lang.String MMS_CONFIG_SMS_DELIVERY_REPORT_ENABLED = "enableSMSDeliveryReports";
     field public static final java.lang.String MMS_CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD = "smsToMmsTextLengthThreshold";
     field public static final java.lang.String MMS_CONFIG_SMS_TO_MMS_TEXT_THRESHOLD = "smsToMmsTextThreshold";
@@ -28560,7 +28563,6 @@
     field public static final int MMS_ERROR_RETRY = 6; // 0x6
     field public static final int MMS_ERROR_UNABLE_CONNECT_MMS = 3; // 0x3
     field public static final int MMS_ERROR_UNSPECIFIED = 1; // 0x1
-    field public static final java.lang.String MMS_SHOW_CELL_BROADCAST_APP_LINKS = "config_cellBroadcastAppLinks";
     field public static final int RESULT_ERROR_GENERIC_FAILURE = 1; // 0x1
     field public static final int RESULT_ERROR_NO_SERVICE = 4; // 0x4
     field public static final int RESULT_ERROR_NULL_PDU = 3; // 0x3
@@ -28689,7 +28691,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 hasCarrierPrivileges();
     method public boolean hasIccCard();
     method public boolean iccCloseLogicalChannel(int);
     method public byte[] iccExchangeSimIO(int, int, int, int, int, java.lang.String);
@@ -28709,10 +28711,6 @@
     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
diff --git a/cmds/content/src/com/android/commands/content/Content.java b/cmds/content/src/com/android/commands/content/Content.java
index 948c9a2..bd34a9c 100644
--- a/cmds/content/src/com/android/commands/content/Content.java
+++ b/cmds/content/src/com/android/commands/content/Content.java
@@ -501,7 +501,7 @@
 
         @Override
         public void onExecute(IContentProvider provider) throws Exception {
-            final ParcelFileDescriptor fd = provider.openFile(null, mUri, "r", null);
+            final ParcelFileDescriptor fd = provider.openFile(null, mUri, "r", null, null);
             copy(new FileInputStream(fd.getFileDescriptor()), System.out);
         }
 
diff --git a/core/java/android/animation/TimeAnimator.java b/core/java/android/animation/TimeAnimator.java
index f9aa00e..1738ade 100644
--- a/core/java/android/animation/TimeAnimator.java
+++ b/core/java/android/animation/TimeAnimator.java
@@ -1,5 +1,23 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package android.animation;
 
+import android.view.animation.AnimationUtils;
+
 /**
  * This class provides a simple callback mechanism to listeners that is synchronized with all
  * other animators in the system. There is no duration, interpolation, or object value-setting
@@ -29,6 +47,13 @@
         return false;
     }
 
+    @Override
+    public void setCurrentPlayTime(long playTime) {
+        long currentTime = AnimationUtils.currentAnimationTimeMillis();
+        mStartTime = Math.max(mStartTime, currentTime - playTime);
+        animationFrame(currentTime);
+    }
+
     /**
      * Sets a listener that is sent update events throughout the life of
      * an animation.
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 07f79b8..d65b490 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -79,7 +79,7 @@
      * Set when setCurrentPlayTime() is called. If negative, animation is not currently seeked
      * to a value.
      */
-    long mSeekTime = -1;
+    float mSeekFraction = -1;
 
     /**
      * Set on the next frame after pause() is called, used to calculate a new startTime
@@ -537,14 +537,31 @@
      * @param playTime The time, in milliseconds, to which the animation is advanced or rewound.
      */
     public void setCurrentPlayTime(long playTime) {
+        float fraction = mUnscaledDuration > 0 ? (float) playTime / mUnscaledDuration :
+                playTime == 0 ? 0 : 1;
+        setCurrentFraction(fraction);
+    }
+
+    /**
+     * Sets the position of the animation to the specified fraction. This fraction should
+     * be between 0 and the total fraction of the animation, including any repetition. That is,
+     * a fraction of 0 will position the animation at the beginning, a value of 1 at the end,
+     * and a value of 2 at the beginning of a reversing animator that repeats once. If
+     * the animation has not yet been started, then it will not advance forward after it is
+     * set to this fraction; it will simply set the fraction to this value and perform any
+     * appropriate actions based on that fraction. If the animation is already running, then
+     * setCurrentFraction() will set the current fraction to this value and continue
+     * playing from that point.
+     *
+     * @param fraction The fraction to which the animation is advanced or rewound.
+     */
+    public void setCurrentFraction(float fraction) {
         initAnimation();
-        long currentTime = AnimationUtils.currentAnimationTimeMillis();
         if (mPlayingState != RUNNING) {
-            mSeekTime = playTime;
+            mSeekFraction = fraction;
             mPlayingState = SEEKED;
         }
-        mStartTime = currentTime - playTime;
-        doAnimationFrame(currentTime);
+        animateValue(fraction);
     }
 
     /**
@@ -948,6 +965,7 @@
         }
         mPlayingBackwards = playBackwards;
         mCurrentIteration = 0;
+        int prevPlayingState = mPlayingState;
         mPlayingState = STOPPED;
         mStarted = true;
         mStartedDelay = false;
@@ -957,7 +975,9 @@
         animationHandler.mPendingAnimations.add(this);
         if (mStartDelay == 0) {
             // This sets the initial value of the animation, prior to actually starting it running
-            setCurrentPlayTime(0);
+            if (prevPlayingState != SEEKED) {
+                setCurrentPlayTime(0);
+            }
             mPlayingState = STOPPED;
             mRunning = true;
             notifyStartListeners();
@@ -1221,12 +1241,12 @@
     final boolean doAnimationFrame(long frameTime) {
         if (mPlayingState == STOPPED) {
             mPlayingState = RUNNING;
-            if (mSeekTime < 0) {
+            if (mSeekFraction < 0) {
                 mStartTime = frameTime;
             } else {
-                mStartTime = frameTime - mSeekTime;
-                // Now that we're playing, reset the seek time
-                mSeekTime = -1;
+                long seekTime = (long) (mDuration * mSeekFraction);
+                mStartTime = frameTime - seekTime;
+                mSeekFraction = -1;
             }
         }
         if (mPaused) {
@@ -1292,7 +1312,7 @@
         if (mUpdateListeners != null) {
             anim.mUpdateListeners = new ArrayList<AnimatorUpdateListener>(mUpdateListeners);
         }
-        anim.mSeekTime = -1;
+        anim.mSeekFraction = -1;
         anim.mPlayingBackwards = false;
         anim.mCurrentIteration = 0;
         anim.mInitialized = false;
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index c3028b7..6ec48e5 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1186,6 +1186,18 @@
             return true;
         }
 
+        case CHECK_PERMISSION_WITH_TOKEN_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            String perm = data.readString();
+            int pid = data.readInt();
+            int uid = data.readInt();
+            IBinder token = data.readStrongBinder();
+            int res = checkPermissionWithToken(perm, pid, uid, token);
+            reply.writeNoException();
+            reply.writeInt(res);
+            return true;
+        }
+
         case CHECK_URI_PERMISSION_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             Uri uri = Uri.CREATOR.createFromParcel(data);
@@ -1193,7 +1205,8 @@
             int uid = data.readInt();
             int mode = data.readInt();
             int userId = data.readInt();
-            int res = checkUriPermission(uri, pid, uid, mode, userId);
+            IBinder callerToken = data.readStrongBinder();
+            int res = checkUriPermission(uri, pid, uid, mode, userId, callerToken);
             reply.writeNoException();
             reply.writeInt(res);
             return true;
@@ -3742,7 +3755,7 @@
         mRemote.transact(GET_INTENT_SENDER_TRANSACTION, data, reply, 0);
         reply.readException();
         IIntentSender res = IIntentSender.Stub.asInterface(
-            reply.readStrongBinder());
+                reply.readStrongBinder());
         data.recycle();
         reply.recycle();
         return res;
@@ -3851,6 +3864,22 @@
         reply.recycle();
         return res;
     }
+    public int checkPermissionWithToken(String permission, int pid, int uid, IBinder callerToken)
+            throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeString(permission);
+        data.writeInt(pid);
+        data.writeInt(uid);
+        data.writeStrongBinder(callerToken);
+        mRemote.transact(CHECK_PERMISSION_WITH_TOKEN_TRANSACTION, data, reply, 0);
+        reply.readException();
+        int res = reply.readInt();
+        data.recycle();
+        reply.recycle();
+        return res;
+    }
     public boolean clearApplicationUserData(final String packageName,
             final IPackageDataObserver observer, final int userId) throws RemoteException {
         Parcel data = Parcel.obtain();
@@ -3866,8 +3895,8 @@
         reply.recycle();
         return res;
     }
-    public int checkUriPermission(Uri uri, int pid, int uid, int mode, int userId)
-            throws RemoteException {
+    public int checkUriPermission(Uri uri, int pid, int uid, int mode, int userId,
+            IBinder callerToken) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
@@ -3876,6 +3905,7 @@
         data.writeInt(uid);
         data.writeInt(mode);
         data.writeInt(userId);
+        data.writeStrongBinder(callerToken);
         mRemote.transact(CHECK_URI_PERMISSION_TRANSACTION, data, reply, 0);
         reply.readException();
         int res = reply.readInt();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e3de44e..98a096c 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -84,6 +84,8 @@
 import android.util.SuperNotCalledException;
 import android.view.Display;
 import android.view.HardwareRenderer;
+import android.view.IWindowManager;
+import android.view.IWindowSessionCallback;
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.ViewManager;
@@ -2366,6 +2368,9 @@
         if (localLOGV) Slog.v(
             TAG, "Handling launch of " + r);
 
+        // Initialize before creating the activity
+        WindowManagerGlobal.initialize();
+
         Activity a = performLaunchActivity(r, customIntent);
 
         if (a != null) {
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 7fafc38..1de9b47 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1863,6 +1863,21 @@
         }
     }
 
+    /** @hide */
+    @Override
+    public int checkPermission(String permission, int pid, int uid, IBinder callerToken) {
+        if (permission == null) {
+            throw new IllegalArgumentException("permission is null");
+        }
+
+        try {
+            return ActivityManagerNative.getDefault().checkPermissionWithToken(
+                    permission, pid, uid, callerToken);
+        } catch (RemoteException e) {
+            return PackageManager.PERMISSION_DENIED;
+        }
+    }
+
     @Override
     public int checkCallingPermission(String permission) {
         if (permission == null) {
@@ -1951,7 +1966,19 @@
         try {
             return ActivityManagerNative.getDefault().checkUriPermission(
                     ContentProvider.getUriWithoutUserId(uri), pid, uid, modeFlags,
-                    resolveUserId(uri));
+                    resolveUserId(uri), null);
+        } catch (RemoteException e) {
+            return PackageManager.PERMISSION_DENIED;
+        }
+    }
+
+    /** @hide */
+    @Override
+    public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags, IBinder callerToken) {
+        try {
+            return ActivityManagerNative.getDefault().checkUriPermission(
+                    ContentProvider.getUriWithoutUserId(uri), pid, uid, modeFlags,
+                    resolveUserId(uri), callerToken);
         } catch (RemoteException e) {
             return PackageManager.PERMISSION_DENIED;
         }
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 6433f3f..5362303 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -219,9 +219,11 @@
 
     public int checkPermission(String permission, int pid, int uid)
             throws RemoteException;
-
-    public int checkUriPermission(Uri uri, int pid, int uid, int mode, int userId)
+    public int checkPermissionWithToken(String permission, int pid, int uid, IBinder callerToken)
             throws RemoteException;
+
+    public int checkUriPermission(Uri uri, int pid, int uid, int mode, int userId,
+            IBinder callerToken) throws RemoteException;
     public void grantUriPermission(IApplicationThread caller, String targetPkg, Uri uri,
             int mode, int userId) throws RemoteException;
     public void revokeUriPermission(IApplicationThread caller, Uri uri, int mode, int userId)
@@ -785,4 +787,5 @@
     int GET_TASK_DESCRIPTION_ICON_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+238;
     int LAUNCH_ASSIST_INTENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+239;
     int START_IN_PLACE_ANIMATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+240;
+    int CHECK_PERMISSION_WITH_TOKEN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+241;
 }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index ad1cf44..57d53aa 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -182,8 +182,8 @@
      * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
      * provisioning via an NFC bump.
      */
-    public static final String EXTRA_PROVISIONING_DONT_DISABLE_SYSTEM_APPS =
-            "android.app.extra.PROVISIONING_DONT_DISABLE_SYSTEM_APPS";
+    public static final String EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED =
+            "android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED";
 
     /**
      * A String extra holding the time zone {@link android.app.AlarmManager} that the device
@@ -3421,12 +3421,13 @@
     }
 
     /**
-     * Called by profile or device owners to check whether a user has been blocked from
-     * uninstalling a package.
+     * Check whether the current user has been blocked by device policy from uninstalling a package.
+     * Requires the caller to be the profile owner if checking a specific admin's policy.
      *
-     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param admin The name of the admin component whose blocking policy will be checked, or null
+     *        to check if any admin has blocked the uninstallation.
      * @param packageName package to check.
-     * @return true if the user shouldn't be able to uninstall the package.
+     * @return true if uninstallation is blocked.
      */
     public boolean isUninstallBlocked(ComponentName admin, String packageName) {
         if (mService != null) {
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 4c82efd..360f308 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -31,6 +31,7 @@
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.CancellationSignal;
+import android.os.IBinder;
 import android.os.ICancellationSignal;
 import android.os.OperationCanceledException;
 import android.os.ParcelFileDescriptor;
@@ -201,7 +202,7 @@
                 ICancellationSignal cancellationSignal) {
             validateIncomingUri(uri);
             uri = getUriWithoutUserId(uri);
-            if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
+            if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
                 return rejectQuery(uri, projection, selection, selectionArgs, sortOrder,
                         CancellationSignal.fromTransport(cancellationSignal));
             }
@@ -227,7 +228,7 @@
             validateIncomingUri(uri);
             int userId = getUserIdFromUri(uri);
             uri = getUriWithoutUserId(uri);
-            if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
+            if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
                 return rejectInsert(uri, initialValues);
             }
             final String original = setCallingPackage(callingPkg);
@@ -242,7 +243,7 @@
         public int bulkInsert(String callingPkg, Uri uri, ContentValues[] initialValues) {
             validateIncomingUri(uri);
             uri = getUriWithoutUserId(uri);
-            if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
+            if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
                 return 0;
             }
             final String original = setCallingPackage(callingPkg);
@@ -270,13 +271,13 @@
                     operations.set(i, operation);
                 }
                 if (operation.isReadOperation()) {
-                    if (enforceReadPermission(callingPkg, uri)
+                    if (enforceReadPermission(callingPkg, uri, null)
                             != AppOpsManager.MODE_ALLOWED) {
                         throw new OperationApplicationException("App op not allowed", 0);
                     }
                 }
                 if (operation.isWriteOperation()) {
-                    if (enforceWritePermission(callingPkg, uri)
+                    if (enforceWritePermission(callingPkg, uri, null)
                             != AppOpsManager.MODE_ALLOWED) {
                         throw new OperationApplicationException("App op not allowed", 0);
                     }
@@ -301,7 +302,7 @@
         public int delete(String callingPkg, Uri uri, String selection, String[] selectionArgs) {
             validateIncomingUri(uri);
             uri = getUriWithoutUserId(uri);
-            if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
+            if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
                 return 0;
             }
             final String original = setCallingPackage(callingPkg);
@@ -317,7 +318,7 @@
                 String[] selectionArgs) {
             validateIncomingUri(uri);
             uri = getUriWithoutUserId(uri);
-            if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
+            if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
                 return 0;
             }
             final String original = setCallingPackage(callingPkg);
@@ -330,11 +331,11 @@
 
         @Override
         public ParcelFileDescriptor openFile(
-                String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
-                throws FileNotFoundException {
+                String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal,
+                IBinder callerToken) throws FileNotFoundException {
             validateIncomingUri(uri);
             uri = getUriWithoutUserId(uri);
-            enforceFilePermission(callingPkg, uri, mode);
+            enforceFilePermission(callingPkg, uri, mode, callerToken);
             final String original = setCallingPackage(callingPkg);
             try {
                 return ContentProvider.this.openFile(
@@ -350,7 +351,7 @@
                 throws FileNotFoundException {
             validateIncomingUri(uri);
             uri = getUriWithoutUserId(uri);
-            enforceFilePermission(callingPkg, uri, mode);
+            enforceFilePermission(callingPkg, uri, mode, null);
             final String original = setCallingPackage(callingPkg);
             try {
                 return ContentProvider.this.openAssetFile(
@@ -382,7 +383,7 @@
                 Bundle opts, ICancellationSignal cancellationSignal) throws FileNotFoundException {
             validateIncomingUri(uri);
             uri = getUriWithoutUserId(uri);
-            enforceFilePermission(callingPkg, uri, "r");
+            enforceFilePermission(callingPkg, uri, "r", null);
             final String original = setCallingPackage(callingPkg);
             try {
                 return ContentProvider.this.openTypedAssetFile(
@@ -402,7 +403,7 @@
             validateIncomingUri(uri);
             int userId = getUserIdFromUri(uri);
             uri = getUriWithoutUserId(uri);
-            if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
+            if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
                 return null;
             }
             final String original = setCallingPackage(callingPkg);
@@ -418,7 +419,7 @@
             validateIncomingUri(uri);
             int userId = getUserIdFromUri(uri);
             uri = getUriWithoutUserId(uri);
-            if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
+            if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
                 return null;
             }
             final String original = setCallingPackage(callingPkg);
@@ -429,29 +430,33 @@
             }
         }
 
-        private void enforceFilePermission(String callingPkg, Uri uri, String mode)
-                throws FileNotFoundException, SecurityException {
+        private void enforceFilePermission(String callingPkg, Uri uri, String mode,
+                IBinder callerToken) throws FileNotFoundException, SecurityException {
             if (mode != null && mode.indexOf('w') != -1) {
-                if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
+                if (enforceWritePermission(callingPkg, uri, callerToken)
+                        != AppOpsManager.MODE_ALLOWED) {
                     throw new FileNotFoundException("App op not allowed");
                 }
             } else {
-                if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
+                if (enforceReadPermission(callingPkg, uri, callerToken)
+                        != AppOpsManager.MODE_ALLOWED) {
                     throw new FileNotFoundException("App op not allowed");
                 }
             }
         }
 
-        private int enforceReadPermission(String callingPkg, Uri uri) throws SecurityException {
-            enforceReadPermissionInner(uri);
+        private int enforceReadPermission(String callingPkg, Uri uri, IBinder callerToken)
+                throws SecurityException {
+            enforceReadPermissionInner(uri, callerToken);
             if (mReadOp != AppOpsManager.OP_NONE) {
                 return mAppOpsManager.noteOp(mReadOp, Binder.getCallingUid(), callingPkg);
             }
             return AppOpsManager.MODE_ALLOWED;
         }
 
-        private int enforceWritePermission(String callingPkg, Uri uri) throws SecurityException {
-            enforceWritePermissionInner(uri);
+        private int enforceWritePermission(String callingPkg, Uri uri, IBinder callerToken)
+                throws SecurityException {
+            enforceWritePermissionInner(uri, callerToken);
             if (mWriteOp != AppOpsManager.OP_NONE) {
                 return mAppOpsManager.noteOp(mWriteOp, Binder.getCallingUid(), callingPkg);
             }
@@ -467,7 +472,8 @@
     }
 
     /** {@hide} */
-    protected void enforceReadPermissionInner(Uri uri) throws SecurityException {
+    protected void enforceReadPermissionInner(Uri uri, IBinder callerToken)
+            throws SecurityException {
         final Context context = getContext();
         final int pid = Binder.getCallingPid();
         final int uid = Binder.getCallingUid();
@@ -480,7 +486,8 @@
         if (mExported && checkUser(pid, uid, context)) {
             final String componentPerm = getReadPermission();
             if (componentPerm != null) {
-                if (context.checkPermission(componentPerm, pid, uid) == PERMISSION_GRANTED) {
+                if (context.checkPermission(componentPerm, pid, uid, callerToken)
+                        == PERMISSION_GRANTED) {
                     return;
                 } else {
                     missingPerm = componentPerm;
@@ -497,7 +504,8 @@
                 for (PathPermission pp : pps) {
                     final String pathPerm = pp.getReadPermission();
                     if (pathPerm != null && pp.match(path)) {
-                        if (context.checkPermission(pathPerm, pid, uid) == PERMISSION_GRANTED) {
+                        if (context.checkPermission(pathPerm, pid, uid, callerToken)
+                                == PERMISSION_GRANTED) {
                             return;
                         } else {
                             // any denied <path-permission> means we lose
@@ -518,8 +526,8 @@
         final int callingUserId = UserHandle.getUserId(uid);
         final Uri userUri = (mSingleUser && !UserHandle.isSameUser(mMyUid, uid))
                 ? maybeAddUserId(uri, callingUserId) : uri;
-        if (context.checkUriPermission(userUri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION)
-                == PERMISSION_GRANTED) {
+        if (context.checkUriPermission(userUri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION,
+                callerToken) == PERMISSION_GRANTED) {
             return;
         }
 
@@ -532,7 +540,8 @@
     }
 
     /** {@hide} */
-    protected void enforceWritePermissionInner(Uri uri) throws SecurityException {
+    protected void enforceWritePermissionInner(Uri uri, IBinder callerToken)
+            throws SecurityException {
         final Context context = getContext();
         final int pid = Binder.getCallingPid();
         final int uid = Binder.getCallingUid();
@@ -545,7 +554,8 @@
         if (mExported && checkUser(pid, uid, context)) {
             final String componentPerm = getWritePermission();
             if (componentPerm != null) {
-                if (context.checkPermission(componentPerm, pid, uid) == PERMISSION_GRANTED) {
+                if (context.checkPermission(componentPerm, pid, uid, callerToken)
+                        == PERMISSION_GRANTED) {
                     return;
                 } else {
                     missingPerm = componentPerm;
@@ -562,7 +572,8 @@
                 for (PathPermission pp : pps) {
                     final String pathPerm = pp.getWritePermission();
                     if (pathPerm != null && pp.match(path)) {
-                        if (context.checkPermission(pathPerm, pid, uid) == PERMISSION_GRANTED) {
+                        if (context.checkPermission(pathPerm, pid, uid, callerToken)
+                                == PERMISSION_GRANTED) {
                             return;
                         } else {
                             // any denied <path-permission> means we lose
@@ -580,8 +591,8 @@
         }
 
         // last chance, check against any uri grants
-        if (context.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
-                == PERMISSION_GRANTED) {
+        if (context.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
+                callerToken) == PERMISSION_GRANTED) {
             return;
         }
 
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index cefc27f..e15ac94 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -288,7 +288,7 @@
                 remoteSignal = mContentProvider.createCancellationSignal();
                 signal.setRemote(remoteSignal);
             }
-            return mContentProvider.openFile(mPackageName, url, mode, remoteSignal);
+            return mContentProvider.openFile(mPackageName, url, mode, remoteSignal, null);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java
index 39286d6..f2e7fc4 100644
--- a/core/java/android/content/ContentProviderNative.java
+++ b/core/java/android/content/ContentProviderNative.java
@@ -234,9 +234,10 @@
                     String mode = data.readString();
                     ICancellationSignal signal = ICancellationSignal.Stub.asInterface(
                             data.readStrongBinder());
+                    IBinder callerToken = data.readStrongBinder();
 
                     ParcelFileDescriptor fd;
-                    fd = openFile(callingPkg, url, mode, signal);
+                    fd = openFile(callingPkg, url, mode, signal, callerToken);
                     reply.writeNoException();
                     if (fd != null) {
                         reply.writeInt(1);
@@ -575,7 +576,7 @@
 
     @Override
     public ParcelFileDescriptor openFile(
-            String callingPkg, Uri url, String mode, ICancellationSignal signal)
+            String callingPkg, Uri url, String mode, ICancellationSignal signal, IBinder token)
             throws RemoteException, FileNotFoundException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -586,6 +587,7 @@
             url.writeToParcel(data, 0);
             data.writeString(mode);
             data.writeStrongBinder(signal != null ? signal.asBinder() : null);
+            data.writeStrongBinder(token);
 
             mRemote.transact(IContentProvider.OPEN_FILE_TRANSACTION, data, reply, 0);
 
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index c9b7d0a..a73ba74 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -37,6 +37,7 @@
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Looper;
 import android.os.StatFs;
 import android.os.UserHandle;
@@ -2864,10 +2865,10 @@
 
     /**
      * Use with {@link #getSystemService} to retrieve a {@link
-     * android.app.UsageStatsManager} for interacting with the status bar.
+     * android.app.usage.UsageStatsManager} for interacting with the status bar.
      *
      * @see #getSystemService
-     * @see android.app.UsageStatsManager
+     * @see android.app.usage.UsageStatsManager
      * @hide
      */
     public static final String USAGE_STATS_SERVICE = "usagestats";
@@ -2921,6 +2922,11 @@
     @PackageManager.PermissionResult
     public abstract int checkPermission(@NonNull String permission, int pid, int uid);
 
+    /** @hide */
+    @PackageManager.PermissionResult
+    public abstract int checkPermission(@NonNull String permission, int pid, int uid,
+            IBinder callerToken);
+
     /**
      * Determine whether the calling process of an IPC you are handling has been
      * granted a particular permission.  This is basically the same as calling
@@ -3108,6 +3114,10 @@
     public abstract int checkUriPermission(Uri uri, int pid, int uid,
             @Intent.AccessUriMode int modeFlags);
 
+    /** @hide */
+    public abstract int checkUriPermission(Uri uri, int pid, int uid,
+            @Intent.AccessUriMode int modeFlags, IBinder callerToken);
+
     /**
      * Determine whether the calling process and user ID has been
      * granted permission to access a specific URI.  This is basically
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index ad7c350..cfae1cf 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -29,6 +29,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Looper;
 import android.os.UserHandle;
 import android.view.DisplayAdjustments;
@@ -566,6 +567,12 @@
         return mBase.checkPermission(permission, pid, uid);
     }
 
+    /** @hide */
+    @Override
+    public int checkPermission(String permission, int pid, int uid, IBinder callerToken) {
+        return mBase.checkPermission(permission, pid, uid, callerToken);
+    }
+
     @Override
     public int checkCallingPermission(String permission) {
         return mBase.checkCallingPermission(permission);
@@ -608,6 +615,12 @@
         return mBase.checkUriPermission(uri, pid, uid, modeFlags);
     }
 
+    /** @hide */
+    @Override
+    public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags, IBinder callerToken) {
+        return mBase.checkUriPermission(uri, pid, uid, modeFlags, callerToken);
+    }
+
     @Override
     public int checkCallingUriPermission(Uri uri, int modeFlags) {
         return mBase.checkCallingUriPermission(uri, modeFlags);
diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java
index f92a404..f858406 100644
--- a/core/java/android/content/IContentProvider.java
+++ b/core/java/android/content/IContentProvider.java
@@ -47,7 +47,8 @@
     public int update(String callingPkg, Uri url, ContentValues values, String selection,
             String[] selectionArgs) throws RemoteException;
     public ParcelFileDescriptor openFile(
-            String callingPkg, Uri url, String mode, ICancellationSignal signal)
+            String callingPkg, Uri url, String mode, ICancellationSignal signal,
+            IBinder callerToken)
             throws RemoteException, FileNotFoundException;
     public AssetFileDescriptor openAssetFile(
             String callingPkg, Uri url, String mode, ICancellationSignal signal)
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 57f6028..a13a2ea 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3763,7 +3763,7 @@
      * This flag is used to open a document into a new task rooted at the activity launched
      * by this Intent. Through the use of this flag, or its equivalent attribute,
      * {@link android.R.attr#documentLaunchMode} multiple instances of the same activity
-     * containing different douments will appear in the recent tasks list.
+     * containing different documents will appear in the recent tasks list.
      *
      * <p>The use of the activity attribute form of this,
      * {@link android.R.attr#documentLaunchMode}, is
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index 5b926ad..961a3f4 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -60,4 +60,6 @@
 
     void addNfcUnlockHandler(INfcUnlockHandler unlockHandler, in int[] techList);
     void removeNfcUnlockHandler(INfcUnlockHandler unlockHandler);
+
+    void verifyNfcPermission();
 }
diff --git a/core/java/android/nfc/NfcActivityManager.java b/core/java/android/nfc/NfcActivityManager.java
index dd9765d..d009295 100644
--- a/core/java/android/nfc/NfcActivityManager.java
+++ b/core/java/android/nfc/NfcActivityManager.java
@@ -254,7 +254,11 @@
             isResumed = state.resumed;
         }
         if (isResumed) {
+            // requestNfcServiceCallback() verifies permission also
             requestNfcServiceCallback();
+        } else {
+            // Crash API calls early in case NFC permission is missing
+            verifyNfcPermission();
         }
     }
 
@@ -268,7 +272,11 @@
             isResumed = state.resumed;
         }
         if (isResumed) {
+            // requestNfcServiceCallback() verifies permission also
             requestNfcServiceCallback();
+        } else {
+            // Crash API calls early in case NFC permission is missing
+            verifyNfcPermission();
         }
     }
 
@@ -281,7 +289,11 @@
             isResumed = state.resumed;
         }
         if (isResumed) {
+            // requestNfcServiceCallback() verifies permission also
             requestNfcServiceCallback();
+        } else {
+            // Crash API calls early in case NFC permission is missing
+            verifyNfcPermission();
         }
     }
 
@@ -295,7 +307,11 @@
             isResumed = state.resumed;
         }
         if (isResumed) {
+            // requestNfcServiceCallback() verifies permission also
             requestNfcServiceCallback();
+        } else {
+            // Crash API calls early in case NFC permission is missing
+            verifyNfcPermission();
         }
     }
 
@@ -308,7 +324,11 @@
             isResumed = state.resumed;
         }
         if (isResumed) {
+            // requestNfcServiceCallback() verifies permission also
             requestNfcServiceCallback();
+        } else {
+            // Crash API calls early in case NFC permission is missing
+            verifyNfcPermission();
         }
     }
 
@@ -324,6 +344,14 @@
         }
     }
 
+    void verifyNfcPermission() {
+        try {
+            NfcAdapter.sService.verifyNfcPermission();
+        } catch (RemoteException e) {
+            mAdapter.attemptDeadServiceRecovery(e);
+        }
+    }
+
     /** Callback from NFC service, usually on binder thread */
     @Override
     public BeamShareData createBeamShareData() {
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index bd6eeea..ffbed94 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -383,8 +383,8 @@
      *
      * <p/>Key for application restrictions.
      * <p/>Type: Boolean
-     * @see android.app.admin.DevicePolicyManager#addApplicationRestriction()
-     * @see android.app.admin.DevicePolicyManager#getApplicationRestriction()
+     * @see android.app.admin.DevicePolicyManager#setApplicationRestrictions()
+     * @see android.app.admin.DevicePolicyManager#getApplicationRestrictions()
      */
     public static final String KEY_RESTRICTIONS_PENDING = "restrictions_pending";
 
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index 270d786..4135e8b 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -637,7 +637,7 @@
         final Bundle out = new Bundle();
         try {
             if (METHOD_CREATE_DOCUMENT.equals(method)) {
-                enforceWritePermissionInner(documentUri);
+                enforceWritePermissionInner(documentUri, null);
 
                 final String mimeType = extras.getString(Document.COLUMN_MIME_TYPE);
                 final String displayName = extras.getString(Document.COLUMN_DISPLAY_NAME);
@@ -651,7 +651,7 @@
                 out.putParcelable(DocumentsContract.EXTRA_URI, newDocumentUri);
 
             } else if (METHOD_RENAME_DOCUMENT.equals(method)) {
-                enforceWritePermissionInner(documentUri);
+                enforceWritePermissionInner(documentUri, null);
 
                 final String displayName = extras.getString(Document.COLUMN_DISPLAY_NAME);
                 final String newDocumentId = renameDocument(documentId, displayName);
@@ -675,7 +675,7 @@
                 }
 
             } else if (METHOD_DELETE_DOCUMENT.equals(method)) {
-                enforceWritePermissionInner(documentUri);
+                enforceWritePermissionInner(documentUri, null);
                 deleteDocument(documentId);
 
                 // Document no longer exists, clean up any grants
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 0be4aea..3c12e06 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6601,6 +6601,15 @@
         public static final String ENHANCED_4G_MODE_ENABLED = "volte_vt_enabled";
 
         /**
+         * Whether user can enable/disable LTE as a preferred network. A carrier might control
+         * this via gservices, OMA-DM, carrier app, etc.
+         * <p>
+         * Type: int (0 for false, 1 for true)
+         * @hide
+         */
+        public static final String LTE_SERVICE_FORCED = "lte_service_forced";
+
+        /**
          * Settings to backup. This is here so that it's in the same place as the settings
          * keys and easy to update.
          *
diff --git a/core/java/android/service/carriermessaging/CarrierMessagingService.java b/core/java/android/service/carriermessaging/CarrierMessagingService.java
index 101f69b..7aea590 100644
--- a/core/java/android/service/carriermessaging/CarrierMessagingService.java
+++ b/core/java/android/service/carriermessaging/CarrierMessagingService.java
@@ -16,6 +16,7 @@
 
 package android.service.carriermessaging;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.app.Service;
@@ -93,7 +94,7 @@
      * @return True to keep an inbound SMS message and delivered to SMS apps. False to
      * drop the message.
      */
-    public boolean onFilterSms(MessagePdu pdu, String format, int destPort) {
+    public boolean onFilterSms(@NonNull MessagePdu pdu, @NonNull String format, int destPort) {
         // optional
         return true;
     }
@@ -105,9 +106,11 @@
      * @param format the format of the response PDU, typically "3gpp" or "3gpp2"
      * @param destAddress phone number of the recipient of the message
      *
-     * @return a {@link SendSmsResponse}.
+     * @return a possibly {code null} {@link SendSmsResponse}. Upon returning {@code null}, the SMS
+     *         is sent using the carrier network.
      */
-    public SendSmsResponse onSendTextSms(String text, String format, String destAddress) {
+    public @Nullable SendSmsResponse onSendTextSms(
+            @NonNull String text, @NonNull String format, @NonNull String destAddress) {
         // optional
         return null;
     }
@@ -120,10 +123,11 @@
      * @param destAddress phone number of the recipient of the message
      * @param destPort the destination port
      *
-     * @return a {@link SendSmsResponse}
+     * @return a possibly {code null} {@link SendSmsResponse}. Upon returning {@code null}, the SMS
+     *         is sent using the carrier network.
      */
-    public SendSmsResponse onSendDataSms(byte[] data, String format, String destAddress,
-            int destPort) {
+    public @Nullable SendSmsResponse onSendDataSms(@NonNull byte[] data, @NonNull String format,
+            @NonNull String destAddress, int destPort) {
         // optional
         return null;
     }
@@ -135,10 +139,11 @@
      * @param format format the format of the response PDU, typically "3gpp" or "3gpp2"
      * @param destAddress phone number of the recipient of the message
      *
-     * @return a {@link List} of {@link SendSmsResponse}, one for each message part.
+     * @return a possibly {code null} {@link List} of {@link SendSmsResponse}, one for each message
+     *         part. Upon returning {@code null}, the SMS is sent using the carrier network.
      */
-    public List<SendSmsResponse> onSendMultipartTextSms(List<String> parts, String format,
-            String destAddress) {
+    public @Nullable List<SendSmsResponse> onSendMultipartTextSms(@NonNull List<String> parts,
+            @NonNull String format, @NonNull String destAddress) {
         // optional
         return null;
     }
@@ -150,9 +155,10 @@
      * @param locationUrl the optional URL to send this MMS PDU. If this is not specified,
      *                    the PDU should be sent to the default MMSC URL.
      *
-     * @return a {@link SendMmsResult}.
+     * @return a possibly {@code null} {@link SendMmsResult}. Upon returning {@code null}, the
+     *         MMS is sent using the carrier network.
      */
-    public SendMmsResult onSendMms(Uri pduUri, @Nullable String locationUrl) {
+    public @Nullable SendMmsResult onSendMms(@NonNull Uri pduUri, @Nullable String locationUrl) {
         // optional
         return null;
     }
@@ -165,13 +171,13 @@
      *
      * @return a {@link SendMmsResult}.
      */
-    public int onDownloadMms(Uri contentUri, String locationUrl) {
+    public int onDownloadMms(@NonNull Uri contentUri, @NonNull String locationUrl) {
         // optional
         return DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK;
     }
 
     @Override
-    public IBinder onBind(Intent intent) {
+    public @Nullable IBinder onBind(@NonNull Intent intent) {
         if (!SERVICE_INTERFACE.equals(intent.getAction())) {
             return null;
         }
@@ -185,12 +191,24 @@
         private int mResult;
         private byte[] mSendConfPdu;
 
-        public SendMmsResult(int result, byte[] sendConfPdu) {
+        /**
+         * Constructs a SendMmsResult with the MMS send result, and the SenConf PDU.
+         *
+         * @param result the result which is one of {@link #SEND_STATUS_OK},
+         *               {@link #SEND_STATUS_RETRY_ON_CARRIER_NETWORK}, and
+         *               {@link #SEND_STATUS_ERROR}
+         * @param sendConfPdu a possibly {code null} SendConf PDU, which confirms that the message
+         *        was sent. sendConfPdu is ignored if the {@code result} is not
+         *        {@link #SEND_STATUS_OK}
+         */
+        public SendMmsResult(int result, @Nullable byte[] sendConfPdu) {
             mResult = result;
             mSendConfPdu = sendConfPdu;
         }
 
         /**
+         * Returns the result of sending the MMS.
+         *
          * @return the result which is one of {@link #SEND_STATUS_OK},
          *         {@link #SEND_STATUS_RETRY_ON_CARRIER_NETWORK}, and {@link #SEND_STATUS_ERROR}
          */
@@ -199,9 +217,11 @@
         }
 
         /**
-         * @return the SendConf PDU, which confirms that the message was sent.
+         * Returns the SendConf PDU, which confirms that the message was sent.
+         *
+         * @return the SendConf PDU
          */
-        public byte[] getSendConfPdu() {
+        public @Nullable byte[] getSendConfPdu() {
             return mSendConfPdu;
         }
     }
@@ -219,12 +239,15 @@
         private int mErrorCode;
 
         /**
+         * Constructs a SendSmsResponse for the message reference, the ack PDU, and error code for
+         * the just-sent SMS.
+         *
          * @param messageRef message reference of the just-sent SMS
          * @param ackPdu ackPdu for the just-sent SMS
          * @param errorCode error code. See 3GPP 27.005, 3.2.5 for GSM/UMTS,
          *     3GPP2 N.S0005 (IS-41C) Table 171 for CDMA, -1 if unknown or not applicable.
          */
-        public SendSmsResponse(int messageRef, byte[] ackPdu, int errorCode) {
+        public SendSmsResponse(int messageRef, @NonNull byte[] ackPdu, int errorCode) {
             mMessageRef = messageRef;
             mAckPdu = ackPdu;
             mErrorCode = errorCode;
@@ -244,7 +267,7 @@
          *
          * @return the ackPdu
          */
-        public byte[] getAckPdu() {
+        public @NonNull byte[] getAckPdu() {
             return mAckPdu;
         }
 
diff --git a/core/java/android/service/carriermessaging/MessagePdu.java b/core/java/android/service/carriermessaging/MessagePdu.java
index b81719f..3c78568 100644
--- a/core/java/android/service/carriermessaging/MessagePdu.java
+++ b/core/java/android/service/carriermessaging/MessagePdu.java
@@ -16,6 +16,7 @@
 
 package android.service.carriermessaging;
 
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -31,9 +32,14 @@
     private final List<byte[]> mPduList;
 
     /**
+     * Constructs a MessagePdu with the list of message PDUs.
+     *
      * @param pduList the list of message PDUs
      */
-    public MessagePdu(List<byte[]> pduList) {
+    public MessagePdu(@NonNull List<byte[]> pduList) {
+        if (pduList == null || pduList.contains(null)) {
+            throw new IllegalArgumentException("pduList must not be null or contain nulls");
+        }
         mPduList = pduList;
     }
 
@@ -42,7 +48,7 @@
      *
      * @return the list of PDUs
      */
-    public List<byte[]> getPdus() {
+    public @NonNull List<byte[]> getPdus() {
         return mPduList;
     }
 
@@ -51,9 +57,6 @@
         return 0;
     }
 
-    /**
-     * Writes the PDU into a {@link Parcel}.
-     */
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         if (mPduList == null) {
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index e82057c..02297e3 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -383,7 +383,6 @@
                                 okBottom = fitBottom;
                         }
                     } else {
-                        final boolean moreChars;
                         int endPos;
                         int above, below, top, bottom;
                         float currentTextWidth;
@@ -395,7 +394,6 @@
                             top = okTop;
                             bottom = okBottom;
                             currentTextWidth = okWidth;
-                            moreChars = (j + 1 < spanEnd);
                         } else if (fit != here) {
                             endPos = fit;
                             above = fitAscent;
@@ -403,7 +401,6 @@
                             top = fitTop;
                             bottom = fitBottom;
                             currentTextWidth = fitWidth;
-                            moreChars = (j + 1 < spanEnd);
                         } else {
                             // must make progress, so take next character
                             endPos = here + 1;
@@ -417,7 +414,6 @@
                             top = fmTop;
                             bottom = fmBottom;
                             currentTextWidth = widths[here - paraStart];
-                            moreChars = (endPos < spanEnd);
                         }
 
                         v = out(source, here, endPos,
@@ -425,7 +421,7 @@
                                 v, spacingmult, spacingadd, chooseHt,chooseHtv, fm, hasTabOrEmoji,
                                 needMultiply, chdirs, dir, easy, bufEnd, includepad, trackpad,
                                 chs, widths, paraStart, ellipsize, ellipsizedWidth,
-                                currentTextWidth, paint, moreChars);
+                                currentTextWidth, paint, true);
 
                         here = endPos;
                         j = here - 1; // restart j-span loop from here, compensating for the j++
diff --git a/core/java/android/transition/ChangeTransform.java b/core/java/android/transition/ChangeTransform.java
index a159b40..9749121 100644
--- a/core/java/android/transition/ChangeTransform.java
+++ b/core/java/android/transition/ChangeTransform.java
@@ -376,7 +376,7 @@
         while (outerTransition.mParent != null) {
             outerTransition = outerTransition.mParent;
         }
-        GhostListener listener = new GhostListener(view, ghostView, endMatrix);
+        GhostListener listener = new GhostListener(view, startValues.view, ghostView);
         outerTransition.addListener(listener);
 
         if (startValues.view != endValues.view) {
@@ -466,13 +466,13 @@
 
     private static class GhostListener extends Transition.TransitionListenerAdapter {
         private View mView;
+        private View mStartView;
         private GhostView mGhostView;
-	private Matrix mEndMatrix;
 
-        public GhostListener(View view, GhostView ghostView, Matrix endMatrix) {
+        public GhostListener(View view, View startView, GhostView ghostView) {
             mView = view;
+            mStartView = startView;
             mGhostView = ghostView;
-            mEndMatrix = endMatrix;
         }
 
         @Override
@@ -481,6 +481,7 @@
             GhostView.removeGhost(mView);
             mView.setTagInternal(R.id.transitionTransform, null);
             mView.setTagInternal(R.id.parentMatrix, null);
+            mStartView.setTransitionAlpha(1);
         }
 
         @Override
diff --git a/core/java/android/transition/SidePropagation.java b/core/java/android/transition/SidePropagation.java
index 623cdd1..ad6c2dd 100644
--- a/core/java/android/transition/SidePropagation.java
+++ b/core/java/android/transition/SidePropagation.java
@@ -44,8 +44,8 @@
      * farther from the edge. The default is {@link Gravity#BOTTOM}.
      *
      * @param side The side that is used to calculate the transition propagation. Must be one of
-     *             {@link Gravity#LEFT}, {@link Gravity#TOP}, {@link Gravity#RIGHT}, or
-     *             {@link Gravity#BOTTOM}.
+     *             {@link Gravity#LEFT}, {@link Gravity#TOP}, {@link Gravity#RIGHT},
+     *             {@link Gravity#BOTTOM}, {@link Gravity#START}, or {@link Gravity#END}.
      */
     public void setSide(int side) {
         mSide = side;
@@ -106,7 +106,7 @@
             epicenterY = (top + bottom) / 2;
         }
 
-        float distance = distance(viewCenterX, viewCenterY, epicenterX, epicenterY,
+        float distance = distance(sceneRoot, viewCenterX, viewCenterY, epicenterX, epicenterY,
                 left, top, right, bottom);
         float maxDistance = getMaxDistance(sceneRoot);
         float distanceFraction = distance/maxDistance;
@@ -119,10 +119,20 @@
         return Math.round(duration * directionMultiplier / mPropagationSpeed * distanceFraction);
     }
 
-    private int distance(int viewX, int viewY, int epicenterX, int epicenterY,
+    private int distance(View sceneRoot, int viewX, int viewY, int epicenterX, int epicenterY,
             int left, int top, int right, int bottom) {
+        final int side;
+        if (mSide == Gravity.START) {
+            final boolean isRtl = sceneRoot.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+            side = isRtl ? Gravity.RIGHT : Gravity.LEFT;
+        } else if (mSide == Gravity.END) {
+            final boolean isRtl = sceneRoot.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+            side = isRtl ? Gravity.LEFT : Gravity.RIGHT;
+        } else {
+            side = mSide;
+        }
         int distance = 0;
-        switch (mSide) {
+        switch (side) {
             case Gravity.LEFT:
                 distance = right - viewX + Math.abs(epicenterY - viewY);
                 break;
@@ -143,6 +153,8 @@
         switch (mSide) {
             case Gravity.LEFT:
             case Gravity.RIGHT:
+            case Gravity.START:
+            case Gravity.END:
                 return sceneRoot.getWidth();
             default:
                 return sceneRoot.getHeight();
diff --git a/core/java/android/transition/Slide.java b/core/java/android/transition/Slide.java
index ae2e4aa..be1d907 100644
--- a/core/java/android/transition/Slide.java
+++ b/core/java/android/transition/Slide.java
@@ -76,6 +76,20 @@
         }
     };
 
+    private static final CalculateSlide sCalculateStart = new CalculateSlideHorizontal() {
+        @Override
+        public float getGoneX(ViewGroup sceneRoot, View view) {
+            final boolean isRtl = sceneRoot.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+            final float x;
+            if (isRtl) {
+                x = view.getTranslationX() + sceneRoot.getWidth();
+            } else {
+                x = view.getTranslationX() - sceneRoot.getWidth();
+            }
+            return x;
+        }
+    };
+
     private static final CalculateSlide sCalculateTop = new CalculateSlideVertical() {
         @Override
         public float getGoneY(ViewGroup sceneRoot, View view) {
@@ -90,6 +104,20 @@
         }
     };
 
+    private static final CalculateSlide sCalculateEnd = new CalculateSlideHorizontal() {
+        @Override
+        public float getGoneX(ViewGroup sceneRoot, View view) {
+            final boolean isRtl = sceneRoot.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+            final float x;
+            if (isRtl) {
+                x = view.getTranslationX() - sceneRoot.getWidth();
+            } else {
+                x = view.getTranslationX() + sceneRoot.getWidth();
+            }
+            return x;
+        }
+    };
+
     private static final CalculateSlide sCalculateBottom = new CalculateSlideVertical() {
         @Override
         public float getGoneY(ViewGroup sceneRoot, View view) {
@@ -144,7 +172,8 @@
      *
      * @param slideEdge The edge of the scene to use for Views appearing and disappearing. One of
      *                  {@link android.view.Gravity#LEFT}, {@link android.view.Gravity#TOP},
-     *                  {@link android.view.Gravity#RIGHT}, {@link android.view.Gravity#BOTTOM}.
+     *                  {@link android.view.Gravity#RIGHT}, {@link android.view.Gravity#BOTTOM},
+     *                  {@link android.view.Gravity#START}, {@link android.view.Gravity#END}.
      * @attr ref android.R.styleable#Slide_slideEdge
      */
     public void setSlideEdge(int slideEdge) {
@@ -161,6 +190,12 @@
             case Gravity.BOTTOM:
                 mSlideCalculator = sCalculateBottom;
                 break;
+            case Gravity.START:
+                mSlideCalculator = sCalculateStart;
+                break;
+            case Gravity.END:
+                mSlideCalculator = sCalculateEnd;
+                break;
             default:
                 throw new IllegalArgumentException("Invalid slide direction");
         }
@@ -175,7 +210,8 @@
      *
      * @return the edge of the scene to use for Views appearing and disappearing. One of
      *         {@link android.view.Gravity#LEFT}, {@link android.view.Gravity#TOP},
-     *         {@link android.view.Gravity#RIGHT}, {@link android.view.Gravity#BOTTOM}.
+     *         {@link android.view.Gravity#RIGHT}, {@link android.view.Gravity#BOTTOM},
+     *         {@link android.view.Gravity#START}, {@link android.view.Gravity#END}.
      * @attr ref android.R.styleable#Slide_slideEdge
      */
     public int getSlideEdge() {
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 5579c13..2c8a499 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -274,7 +274,7 @@
     }
 
     private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) {
-        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
+        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Record View#draw()");
         updateViewTreeDisplayList(view);
 
         if (mRootNodeNeedsUpdate || !mRootNode.isValid()) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 77c1d7b..b54d462 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -56,6 +56,7 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.Trace;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.FloatProperty;
@@ -2400,12 +2401,6 @@
      */
     static final int PFLAG3_NESTED_SCROLLING_ENABLED = 0x80;
 
-    /**
-     * Flag indicating that outline was invalidated and should be rebuilt the next time
-     * the DisplayList is updated.
-     */
-    static final int PFLAG3_OUTLINE_INVALID = 0x100;
-
     /* End of masks for mPrivateFlags3 */
 
     static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED;
@@ -11277,7 +11272,7 @@
      * @see #setOutlineProvider(ViewOutlineProvider)
      */
     public void invalidateOutline() {
-        mPrivateFlags3 |= PFLAG3_OUTLINE_INVALID;
+        rebuildOutline();
 
         notifySubtreeAccessibilityStateChangedIfNeeded();
         invalidateViewProperty(false, false);
@@ -14411,143 +14406,158 @@
     public void buildDrawingCache(boolean autoScale) {
         if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ?
                 mDrawingCache == null : mUnscaledDrawingCache == null)) {
-            mCachingFailed = false;
+            if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+                Trace.traceBegin(Trace.TRACE_TAG_VIEW,
+                        "buildDrawingCache/SW Layer for " + getClass().getSimpleName());
+            }
+            try {
+                buildDrawingCacheImpl(autoScale);
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+            }
+        }
+    }
 
-            int width = mRight - mLeft;
-            int height = mBottom - mTop;
+    /**
+     * private, internal implementation of buildDrawingCache, used to enable tracing
+     */
+    private void buildDrawingCacheImpl(boolean autoScale) {
+        mCachingFailed = false;
 
-            final AttachInfo attachInfo = mAttachInfo;
-            final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired;
+        int width = mRight - mLeft;
+        int height = mBottom - mTop;
 
-            if (autoScale && scalingRequired) {
-                width = (int) ((width * attachInfo.mApplicationScale) + 0.5f);
-                height = (int) ((height * attachInfo.mApplicationScale) + 0.5f);
+        final AttachInfo attachInfo = mAttachInfo;
+        final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired;
+
+        if (autoScale && scalingRequired) {
+            width = (int) ((width * attachInfo.mApplicationScale) + 0.5f);
+            height = (int) ((height * attachInfo.mApplicationScale) + 0.5f);
+        }
+
+        final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor;
+        final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque();
+        final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache;
+
+        final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4);
+        final long drawingCacheSize =
+                ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize();
+        if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) {
+            if (width > 0 && height > 0) {
+                Log.w(VIEW_LOG_TAG, "View too large to fit into drawing cache, needs "
+                        + projectedBitmapSize + " bytes, only "
+                        + drawingCacheSize + " available");
+            }
+            destroyDrawingCache();
+            mCachingFailed = true;
+            return;
+        }
+
+        boolean clear = true;
+        Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache;
+
+        if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) {
+            Bitmap.Config quality;
+            if (!opaque) {
+                // Never pick ARGB_4444 because it looks awful
+                // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case
+                switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) {
+                    case DRAWING_CACHE_QUALITY_AUTO:
+                    case DRAWING_CACHE_QUALITY_LOW:
+                    case DRAWING_CACHE_QUALITY_HIGH:
+                    default:
+                        quality = Bitmap.Config.ARGB_8888;
+                        break;
+                }
+            } else {
+                // Optimization for translucent windows
+                // If the window is translucent, use a 32 bits bitmap to benefit from memcpy()
+                quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
             }
 
-            final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor;
-            final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque();
-            final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache;
+            // Try to cleanup memory
+            if (bitmap != null) bitmap.recycle();
 
-            final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4);
-            final long drawingCacheSize =
-                    ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize();
-            if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) {
-                if (width > 0 && height > 0) {
-                    Log.w(VIEW_LOG_TAG, "View too large to fit into drawing cache, needs "
-                            + projectedBitmapSize + " bytes, only "
-                            + drawingCacheSize + " available");
+            try {
+                bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(),
+                        width, height, quality);
+                bitmap.setDensity(getResources().getDisplayMetrics().densityDpi);
+                if (autoScale) {
+                    mDrawingCache = bitmap;
+                } else {
+                    mUnscaledDrawingCache = bitmap;
                 }
-                destroyDrawingCache();
+                if (opaque && use32BitCache) bitmap.setHasAlpha(false);
+            } catch (OutOfMemoryError e) {
+                // If there is not enough memory to create the bitmap cache, just
+                // ignore the issue as bitmap caches are not required to draw the
+                // view hierarchy
+                if (autoScale) {
+                    mDrawingCache = null;
+                } else {
+                    mUnscaledDrawingCache = null;
+                }
                 mCachingFailed = true;
                 return;
             }
 
-            boolean clear = true;
-            Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache;
+            clear = drawingCacheBackgroundColor != 0;
+        }
 
-            if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) {
-                Bitmap.Config quality;
-                if (!opaque) {
-                    // Never pick ARGB_4444 because it looks awful
-                    // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case
-                    switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) {
-                        case DRAWING_CACHE_QUALITY_AUTO:
-                        case DRAWING_CACHE_QUALITY_LOW:
-                        case DRAWING_CACHE_QUALITY_HIGH:
-                        default:
-                            quality = Bitmap.Config.ARGB_8888;
-                            break;
-                    }
-                } else {
-                    // Optimization for translucent windows
-                    // If the window is translucent, use a 32 bits bitmap to benefit from memcpy()
-                    quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
-                }
-
-                // Try to cleanup memory
-                if (bitmap != null) bitmap.recycle();
-
-                try {
-                    bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(),
-                            width, height, quality);
-                    bitmap.setDensity(getResources().getDisplayMetrics().densityDpi);
-                    if (autoScale) {
-                        mDrawingCache = bitmap;
-                    } else {
-                        mUnscaledDrawingCache = bitmap;
-                    }
-                    if (opaque && use32BitCache) bitmap.setHasAlpha(false);
-                } catch (OutOfMemoryError e) {
-                    // If there is not enough memory to create the bitmap cache, just
-                    // ignore the issue as bitmap caches are not required to draw the
-                    // view hierarchy
-                    if (autoScale) {
-                        mDrawingCache = null;
-                    } else {
-                        mUnscaledDrawingCache = null;
-                    }
-                    mCachingFailed = true;
-                    return;
-                }
-
-                clear = drawingCacheBackgroundColor != 0;
+        Canvas canvas;
+        if (attachInfo != null) {
+            canvas = attachInfo.mCanvas;
+            if (canvas == null) {
+                canvas = new Canvas();
             }
+            canvas.setBitmap(bitmap);
+            // Temporarily clobber the cached Canvas in case one of our children
+            // is also using a drawing cache. Without this, the children would
+            // steal the canvas by attaching their own bitmap to it and bad, bad
+            // thing would happen (invisible views, corrupted drawings, etc.)
+            attachInfo.mCanvas = null;
+        } else {
+            // This case should hopefully never or seldom happen
+            canvas = new Canvas(bitmap);
+        }
 
-            Canvas canvas;
-            if (attachInfo != null) {
-                canvas = attachInfo.mCanvas;
-                if (canvas == null) {
-                    canvas = new Canvas();
-                }
-                canvas.setBitmap(bitmap);
-                // Temporarily clobber the cached Canvas in case one of our children
-                // is also using a drawing cache. Without this, the children would
-                // steal the canvas by attaching their own bitmap to it and bad, bad
-                // thing would happen (invisible views, corrupted drawings, etc.)
-                attachInfo.mCanvas = null;
-            } else {
-                // This case should hopefully never or seldom happen
-                canvas = new Canvas(bitmap);
+        if (clear) {
+            bitmap.eraseColor(drawingCacheBackgroundColor);
+        }
+
+        computeScroll();
+        final int restoreCount = canvas.save();
+
+        if (autoScale && scalingRequired) {
+            final float scale = attachInfo.mApplicationScale;
+            canvas.scale(scale, scale);
+        }
+
+        canvas.translate(-mScrollX, -mScrollY);
+
+        mPrivateFlags |= PFLAG_DRAWN;
+        if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated ||
+                mLayerType != LAYER_TYPE_NONE) {
+            mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID;
+        }
+
+        // Fast path for layouts with no backgrounds
+        if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
+            mPrivateFlags &= ~PFLAG_DIRTY_MASK;
+            dispatchDraw(canvas);
+            if (mOverlay != null && !mOverlay.isEmpty()) {
+                mOverlay.getOverlayView().draw(canvas);
             }
+        } else {
+            draw(canvas);
+        }
 
-            if (clear) {
-                bitmap.eraseColor(drawingCacheBackgroundColor);
-            }
+        canvas.restoreToCount(restoreCount);
+        canvas.setBitmap(null);
 
-            computeScroll();
-            final int restoreCount = canvas.save();
-
-            if (autoScale && scalingRequired) {
-                final float scale = attachInfo.mApplicationScale;
-                canvas.scale(scale, scale);
-            }
-
-            canvas.translate(-mScrollX, -mScrollY);
-
-            mPrivateFlags |= PFLAG_DRAWN;
-            if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated ||
-                    mLayerType != LAYER_TYPE_NONE) {
-                mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID;
-            }
-
-            // Fast path for layouts with no backgrounds
-            if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
-                mPrivateFlags &= ~PFLAG_DIRTY_MASK;
-                dispatchDraw(canvas);
-                if (mOverlay != null && !mOverlay.isEmpty()) {
-                    mOverlay.getOverlayView().draw(canvas);
-                }
-            } else {
-                draw(canvas);
-            }
-
-            canvas.restoreToCount(restoreCount);
-            canvas.setBitmap(null);
-
-            if (attachInfo != null) {
-                // Restore the cached Canvas for our siblings
-                attachInfo.mCanvas = canvas;
-            }
+        if (attachInfo != null) {
+            // Restore the cached Canvas for our siblings
+            attachInfo.mCanvas = canvas;
         }
     }
 
@@ -14774,27 +14784,21 @@
      * this view, to which future drawing operations will be clipped.
      */
     public void setClipBounds(Rect clipBounds) {
+        if (clipBounds == mClipBounds
+                || (clipBounds != null && clipBounds.equals(mClipBounds))) {
+            return;
+        }
         if (clipBounds != null) {
-            if (clipBounds.equals(mClipBounds)) {
-                return;
-            }
             if (mClipBounds == null) {
-                invalidate();
                 mClipBounds = new Rect(clipBounds);
             } else {
-                invalidate(Math.min(mClipBounds.left, clipBounds.left),
-                        Math.min(mClipBounds.top, clipBounds.top),
-                        Math.max(mClipBounds.right, clipBounds.right),
-                        Math.max(mClipBounds.bottom, clipBounds.bottom));
                 mClipBounds.set(clipBounds);
             }
         } else {
-            if (mClipBounds != null) {
-                invalidate();
-                mClipBounds = null;
-            }
+            mClipBounds = null;
         }
         mRenderNode.setClipBounds(mClipBounds);
+        invalidateViewProperty(false, false);
     }
 
     /**
@@ -14873,10 +14877,6 @@
      */
     void setDisplayListProperties(RenderNode renderNode) {
         if (renderNode != null) {
-            if ((mPrivateFlags3 & PFLAG3_OUTLINE_INVALID) != 0) {
-                rebuildOutline();
-                mPrivateFlags3 &= ~PFLAG3_OUTLINE_INVALID;
-            }
             renderNode.setHasOverlappingRendering(hasOverlappingRendering());
             if (mParent instanceof ViewGroup) {
                 renderNode.setClipToBounds(
@@ -15478,7 +15478,7 @@
         if (mBackgroundSizeChanged) {
             background.setBounds(0, 0,  mRight - mLeft, mBottom - mTop);
             mBackgroundSizeChanged = false;
-            mPrivateFlags3 |= PFLAG3_OUTLINE_INVALID;
+            rebuildOutline();
         }
 
         // Attempt to use a display list if requested.
@@ -15486,10 +15486,10 @@
                 && mAttachInfo.mHardwareRenderer != null) {
             mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode);
 
-            final RenderNode displayList = mBackgroundRenderNode;
-            if (displayList != null && displayList.isValid()) {
-                setBackgroundDisplayListProperties(displayList);
-                ((HardwareCanvas) canvas).drawRenderNode(displayList);
+            final RenderNode renderNode = mBackgroundRenderNode;
+            if (renderNode != null && renderNode.isValid()) {
+                setBackgroundRenderNodeProperties(renderNode);
+                ((HardwareCanvas) canvas).drawRenderNode(renderNode);
                 return;
             }
         }
@@ -15505,14 +15505,9 @@
         }
     }
 
-    /**
-     * Set up background drawable display list properties.
-     *
-     * @param displayList Valid display list for the background drawable
-     */
-    private void setBackgroundDisplayListProperties(RenderNode displayList) {
-        displayList.setTranslationX(mScrollX);
-        displayList.setTranslationY(mScrollY);
+    private void setBackgroundRenderNodeProperties(RenderNode renderNode) {
+        renderNode.setTranslationX(mScrollX);
+        renderNode.setTranslationY(mScrollY);
     }
 
     /**
@@ -15861,7 +15856,7 @@
             mOverlay.getOverlayView().setRight(newWidth);
             mOverlay.getOverlayView().setBottom(newHeight);
         }
-        mPrivateFlags3 |= PFLAG3_OUTLINE_INVALID;
+        rebuildOutline();
     }
 
     /**
@@ -15897,8 +15892,7 @@
 
             invalidate(dirty.left + scrollX, dirty.top + scrollY,
                     dirty.right + scrollX, dirty.bottom + scrollY);
-
-            mPrivateFlags3 |= PFLAG3_OUTLINE_INVALID;
+            rebuildOutline();
         }
     }
 
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index bae0b12..1a5ff26 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3534,8 +3534,11 @@
     }
 
     /**
-     * By default, children are clipped to the padding of the ViewGroup. This
-     * allows view groups to override this behavior
+     * Sets whether this ViewGroup will clip its children to its padding, if
+     * padding is present.
+     * <p>
+     * By default, children are clipped to the padding of their parent
+     * Viewgroup. This clipping behavior is only enabled if padding is non-zero.
      *
      * @param clipToPadding true to clip children to the padding of the
      *        group, false otherwise
@@ -3549,7 +3552,11 @@
     }
 
     /**
-     * Check if this ViewGroup is configured to clip child views to its padding.
+     * Returns whether this ViewGroup will clip its children to its padding, if
+     * padding is present.
+     * <p>
+     * By default, children are clipped to the padding of their parent
+     * Viewgroup. This clipping behavior is only enabled if padding is non-zero.
      *
      * @return true if this ViewGroup clips children to its padding, false otherwise
      *
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 82b1073..8e27834 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -124,6 +124,10 @@
     private WindowManagerGlobal() {
     }
 
+    public static void initialize() {
+        getWindowManagerService();
+    }
+
     public static WindowManagerGlobal getInstance() {
         synchronized (WindowManagerGlobal.class) {
             if (sDefaultWindowManager == null) {
@@ -138,6 +142,12 @@
             if (sWindowManagerService == null) {
                 sWindowManagerService = IWindowManager.Stub.asInterface(
                         ServiceManager.getService("window"));
+                try {
+                    sWindowManagerService = getWindowManagerService();
+                    ValueAnimator.setDurationScale(sWindowManagerService.getCurrentAnimatorScale());
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Failed to get WindowManagerService, cannot set animator scale", e);
+                }
             }
             return sWindowManagerService;
         }
@@ -157,7 +167,6 @@
                                 }
                             },
                             imm.getClient(), imm.getInputContext());
-                    ValueAnimator.setDurationScale(windowManager.getCurrentAnimatorScale());
                 } catch (RemoteException e) {
                     Log.e(TAG, "Failed to open window session", e);
                 }
diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java
index f380d68..ed59ea6 100644
--- a/core/java/android/widget/CalendarView.java
+++ b/core/java/android/widget/CalendarView.java
@@ -17,42 +17,24 @@
 package android.widget;
 
 import android.annotation.Widget;
-import android.app.Service;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
-import android.database.DataSetObserver;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Paint.Align;
-import android.graphics.Paint.Style;
-import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.text.TextUtils;
-import android.text.format.DateUtils;
 import android.util.AttributeSet;
-import android.util.DisplayMetrics;
 import android.util.Log;
-import android.util.TypedValue;
-import android.view.GestureDetector;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
-import android.widget.AbsListView.OnScrollListener;
 
 import com.android.internal.R;
 
+import java.text.DateFormat;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.Calendar;
 import java.util.Locale;
 import java.util.TimeZone;
 
-import libcore.icu.LocaleData;
-
 /**
  * This class is a calendar widget for displaying and selecting dates. The range
  * of dates supported by this calendar is configurable. A user can select a date
@@ -74,13 +56,12 @@
  */
 @Widget
 public class CalendarView extends FrameLayout {
+    private static final String LOG_TAG = "CalendarView";
 
-    /**
-     * Tag for logging.
-     */
-    private static final String LOG_TAG = CalendarView.class.getSimpleName();
+    private static final int MODE_HOLO = 0;
+    private static final int MODE_MATERIAL = 1;
 
-    private CalendarViewDelegate mDelegate;
+    private final CalendarViewDelegate mDelegate;
 
     /**
      * The callback used to indicate the user changes the date.
@@ -113,7 +94,23 @@
     public CalendarView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
 
-        mDelegate = new LegacyCalendarViewDelegate(this, context, attrs, defStyleAttr, defStyleRes);
+        final TypedArray a = context.obtainStyledAttributes(
+                attrs, R.styleable.CalendarView, defStyleAttr, defStyleRes);
+        final int mode = a.getInt(R.styleable.CalendarView_calendarViewMode, MODE_HOLO);
+        a.recycle();
+
+        switch (mode) {
+            case MODE_HOLO:
+                mDelegate = new CalendarViewLegacyDelegate(
+                        this, context, attrs, defStyleAttr, defStyleRes);
+                break;
+            case MODE_MATERIAL:
+                mDelegate = new CalendarViewMaterialDelegate(
+                        this, context, attrs, defStyleAttr, defStyleRes);
+                break;
+            default:
+                throw new IllegalArgumentException("invalid calendarViewMode attribute");
+        }
     }
 
     /**
@@ -326,16 +323,6 @@
         return mDelegate.getDateTextAppearance();
     }
 
-    @Override
-    public void setEnabled(boolean enabled) {
-        mDelegate.setEnabled(enabled);
-    }
-
-    @Override
-    public boolean isEnabled() {
-        return mDelegate.isEnabled();
-    }
-
     /**
      * Gets the minimal date supported by this {@link CalendarView} in milliseconds
      * since January 1, 1970 00:00:00 in {@link TimeZone#getDefault()} time
@@ -516,14 +503,12 @@
 
     @Override
     public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        mDelegate.onInitializeAccessibilityEvent(event);
+        event.setClassName(CalendarView.class.getName());
     }
 
     @Override
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        mDelegate.onInitializeAccessibilityNodeInfo(info);
+        info.setClassName(CalendarView.class.getName());
     }
 
     /**
@@ -560,9 +545,6 @@
         void setDateTextAppearance(int resourceId);
         int getDateTextAppearance();
 
-        void setEnabled(boolean enabled);
-        boolean isEnabled();
-
         void setMinDate(long minDate);
         long getMinDate();
 
@@ -582,21 +564,26 @@
         void setOnDateChangeListener(OnDateChangeListener listener);
 
         void onConfigurationChanged(Configuration newConfig);
-        void onInitializeAccessibilityEvent(AccessibilityEvent event);
-        void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info);
     }
 
     /**
      * An abstract class which can be used as a start for CalendarView implementations
      */
     abstract static class AbstractCalendarViewDelegate implements CalendarViewDelegate {
-        // The delegator
+        /** String for parsing dates. */
+        private static final String DATE_FORMAT = "MM/dd/yyyy";
+
+        /** The default minimal date. */
+        protected static final String DEFAULT_MIN_DATE = "01/01/1900";
+
+        /** The default maximal date. */
+        protected static final String DEFAULT_MAX_DATE = "01/01/2100";
+
+        /** Date format for parsing dates. */
+        protected static final DateFormat DATE_FORMATTER = new SimpleDateFormat(DATE_FORMAT);
+
         protected CalendarView mDelegator;
-
-        // The context
         protected Context mContext;
-
-        // The current locale
         protected Locale mCurrentLocale;
 
         AbstractCalendarViewDelegate(CalendarView delegator, Context context) {
@@ -613,830 +600,6 @@
             }
             mCurrentLocale = locale;
         }
-    }
-
-    /**
-     * A delegate implementing the legacy CalendarView
-     */
-    private static class LegacyCalendarViewDelegate extends AbstractCalendarViewDelegate {
-
-        /**
-         * Default value whether to show week number.
-         */
-        private static final boolean DEFAULT_SHOW_WEEK_NUMBER = true;
-
-        /**
-         * The number of milliseconds in a day.e
-         */
-        private static final long MILLIS_IN_DAY = 86400000L;
-
-        /**
-         * The number of day in a week.
-         */
-        private static final int DAYS_PER_WEEK = 7;
-
-        /**
-         * The number of milliseconds in a week.
-         */
-        private static final long MILLIS_IN_WEEK = DAYS_PER_WEEK * MILLIS_IN_DAY;
-
-        /**
-         * Affects when the month selection will change while scrolling upe
-         */
-        private static final int SCROLL_HYST_WEEKS = 2;
-
-        /**
-         * How long the GoTo fling animation should last.
-         */
-        private static final int GOTO_SCROLL_DURATION = 1000;
-
-        /**
-         * The duration of the adjustment upon a user scroll in milliseconds.
-         */
-        private static final int ADJUSTMENT_SCROLL_DURATION = 500;
-
-        /**
-         * How long to wait after receiving an onScrollStateChanged notification
-         * before acting on it.
-         */
-        private static final int SCROLL_CHANGE_DELAY = 40;
-
-        /**
-         * String for parsing dates.
-         */
-        private static final String DATE_FORMAT = "MM/dd/yyyy";
-
-        /**
-         * The default minimal date.
-         */
-        private static final String DEFAULT_MIN_DATE = "01/01/1900";
-
-        /**
-         * The default maximal date.
-         */
-        private static final String DEFAULT_MAX_DATE = "01/01/2100";
-
-        private static final int DEFAULT_SHOWN_WEEK_COUNT = 6;
-
-        private static final int DEFAULT_DATE_TEXT_SIZE = 14;
-
-        private static final int UNSCALED_SELECTED_DATE_VERTICAL_BAR_WIDTH = 6;
-
-        private static final int UNSCALED_WEEK_MIN_VISIBLE_HEIGHT = 12;
-
-        private static final int UNSCALED_LIST_SCROLL_TOP_OFFSET = 2;
-
-        private static final int UNSCALED_BOTTOM_BUFFER = 20;
-
-        private static final int UNSCALED_WEEK_SEPARATOR_LINE_WIDTH = 1;
-
-        private static final int DEFAULT_WEEK_DAY_TEXT_APPEARANCE_RES_ID = -1;
-
-        private final int mWeekSeperatorLineWidth;
-
-        private int mDateTextSize;
-
-        private Drawable mSelectedDateVerticalBar;
-
-        private final int mSelectedDateVerticalBarWidth;
-
-        private int mSelectedWeekBackgroundColor;
-
-        private int mFocusedMonthDateColor;
-
-        private int mUnfocusedMonthDateColor;
-
-        private int mWeekSeparatorLineColor;
-
-        private int mWeekNumberColor;
-
-        private int mWeekDayTextAppearanceResId;
-
-        private int mDateTextAppearanceResId;
-
-        /**
-         * The top offset of the weeks list.
-         */
-        private int mListScrollTopOffset = 2;
-
-        /**
-         * The visible height of a week view.
-         */
-        private int mWeekMinVisibleHeight = 12;
-
-        /**
-         * The visible height of a week view.
-         */
-        private int mBottomBuffer = 20;
-
-        /**
-         * The number of shown weeks.
-         */
-        private int mShownWeekCount;
-
-        /**
-         * Flag whether to show the week number.
-         */
-        private boolean mShowWeekNumber;
-
-        /**
-         * The number of day per week to be shown.
-         */
-        private int mDaysPerWeek = 7;
-
-        /**
-         * The friction of the week list while flinging.
-         */
-        private float mFriction = .05f;
-
-        /**
-         * Scale for adjusting velocity of the week list while flinging.
-         */
-        private float mVelocityScale = 0.333f;
-
-        /**
-         * The adapter for the weeks list.
-         */
-        private WeeksAdapter mAdapter;
-
-        /**
-         * The weeks list.
-         */
-        private ListView mListView;
-
-        /**
-         * The name of the month to display.
-         */
-        private TextView mMonthName;
-
-        /**
-         * The header with week day names.
-         */
-        private ViewGroup mDayNamesHeader;
-
-        /**
-         * Cached abbreviations for day of week names.
-         */
-        private String[] mDayNamesShort;
-
-        /**
-         * Cached full-length day of week names.
-         */
-        private String[] mDayNamesLong;
-
-        /**
-         * The first day of the week.
-         */
-        private int mFirstDayOfWeek;
-
-        /**
-         * Which month should be displayed/highlighted [0-11].
-         */
-        private int mCurrentMonthDisplayed = -1;
-
-        /**
-         * Used for tracking during a scroll.
-         */
-        private long mPreviousScrollPosition;
-
-        /**
-         * Used for tracking which direction the view is scrolling.
-         */
-        private boolean mIsScrollingUp = false;
-
-        /**
-         * The previous scroll state of the weeks ListView.
-         */
-        private int mPreviousScrollState = OnScrollListener.SCROLL_STATE_IDLE;
-
-        /**
-         * The current scroll state of the weeks ListView.
-         */
-        private int mCurrentScrollState = OnScrollListener.SCROLL_STATE_IDLE;
-
-        /**
-         * Listener for changes in the selected day.
-         */
-        private OnDateChangeListener mOnDateChangeListener;
-
-        /**
-         * Command for adjusting the position after a scroll/fling.
-         */
-        private ScrollStateRunnable mScrollStateChangedRunnable = new ScrollStateRunnable();
-
-        /**
-         * Temporary instance to avoid multiple instantiations.
-         */
-        private Calendar mTempDate;
-
-        /**
-         * The first day of the focused month.
-         */
-        private Calendar mFirstDayOfMonth;
-
-        /**
-         * The start date of the range supported by this picker.
-         */
-        private Calendar mMinDate;
-
-        /**
-         * The end date of the range supported by this picker.
-         */
-        private Calendar mMaxDate;
-
-        /**
-         * Date format for parsing dates.
-         */
-        private final java.text.DateFormat mDateFormat = new SimpleDateFormat(DATE_FORMAT);
-
-        LegacyCalendarViewDelegate(CalendarView delegator, Context context, AttributeSet attrs,
-                                   int defStyleAttr, int defStyleRes) {
-            super(delegator, context);
-
-            // initialization based on locale
-            setCurrentLocale(Locale.getDefault());
-
-            TypedArray attributesArray = context.obtainStyledAttributes(attrs,
-                    R.styleable.CalendarView, defStyleAttr, defStyleRes);
-            mShowWeekNumber = attributesArray.getBoolean(R.styleable.CalendarView_showWeekNumber,
-                    DEFAULT_SHOW_WEEK_NUMBER);
-            mFirstDayOfWeek = attributesArray.getInt(R.styleable.CalendarView_firstDayOfWeek,
-                    LocaleData.get(Locale.getDefault()).firstDayOfWeek);
-            String minDate = attributesArray.getString(R.styleable.CalendarView_minDate);
-            if (TextUtils.isEmpty(minDate) || !parseDate(minDate, mMinDate)) {
-                parseDate(DEFAULT_MIN_DATE, mMinDate);
-            }
-            String maxDate = attributesArray.getString(R.styleable.CalendarView_maxDate);
-            if (TextUtils.isEmpty(maxDate) || !parseDate(maxDate, mMaxDate)) {
-                parseDate(DEFAULT_MAX_DATE, mMaxDate);
-            }
-            if (mMaxDate.before(mMinDate)) {
-                throw new IllegalArgumentException("Max date cannot be before min date.");
-            }
-            mShownWeekCount = attributesArray.getInt(R.styleable.CalendarView_shownWeekCount,
-                    DEFAULT_SHOWN_WEEK_COUNT);
-            mSelectedWeekBackgroundColor = attributesArray.getColor(
-                    R.styleable.CalendarView_selectedWeekBackgroundColor, 0);
-            mFocusedMonthDateColor = attributesArray.getColor(
-                    R.styleable.CalendarView_focusedMonthDateColor, 0);
-            mUnfocusedMonthDateColor = attributesArray.getColor(
-                    R.styleable.CalendarView_unfocusedMonthDateColor, 0);
-            mWeekSeparatorLineColor = attributesArray.getColor(
-                    R.styleable.CalendarView_weekSeparatorLineColor, 0);
-            mWeekNumberColor = attributesArray.getColor(R.styleable.CalendarView_weekNumberColor, 0);
-            mSelectedDateVerticalBar = attributesArray.getDrawable(
-                    R.styleable.CalendarView_selectedDateVerticalBar);
-
-            mDateTextAppearanceResId = attributesArray.getResourceId(
-                    R.styleable.CalendarView_dateTextAppearance, R.style.TextAppearance_Small);
-            updateDateTextSize();
-
-            mWeekDayTextAppearanceResId = attributesArray.getResourceId(
-                    R.styleable.CalendarView_weekDayTextAppearance,
-                    DEFAULT_WEEK_DAY_TEXT_APPEARANCE_RES_ID);
-            attributesArray.recycle();
-
-            DisplayMetrics displayMetrics = mDelegator.getResources().getDisplayMetrics();
-            mWeekMinVisibleHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
-                    UNSCALED_WEEK_MIN_VISIBLE_HEIGHT, displayMetrics);
-            mListScrollTopOffset = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
-                    UNSCALED_LIST_SCROLL_TOP_OFFSET, displayMetrics);
-            mBottomBuffer = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
-                    UNSCALED_BOTTOM_BUFFER, displayMetrics);
-            mSelectedDateVerticalBarWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
-                    UNSCALED_SELECTED_DATE_VERTICAL_BAR_WIDTH, displayMetrics);
-            mWeekSeperatorLineWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
-                    UNSCALED_WEEK_SEPARATOR_LINE_WIDTH, displayMetrics);
-
-            LayoutInflater layoutInflater = (LayoutInflater) mContext
-                    .getSystemService(Service.LAYOUT_INFLATER_SERVICE);
-            View content = layoutInflater.inflate(R.layout.calendar_view, null, false);
-            mDelegator.addView(content);
-
-            mListView = (ListView) mDelegator.findViewById(R.id.list);
-            mDayNamesHeader = (ViewGroup) content.findViewById(com.android.internal.R.id.day_names);
-            mMonthName = (TextView) content.findViewById(com.android.internal.R.id.month_name);
-
-            setUpHeader();
-            setUpListView();
-            setUpAdapter();
-
-            // go to today or whichever is close to today min or max date
-            mTempDate.setTimeInMillis(System.currentTimeMillis());
-            if (mTempDate.before(mMinDate)) {
-                goTo(mMinDate, false, true, true);
-            } else if (mMaxDate.before(mTempDate)) {
-                goTo(mMaxDate, false, true, true);
-            } else {
-                goTo(mTempDate, false, true, true);
-            }
-
-            mDelegator.invalidate();
-        }
-
-        @Override
-        public void setShownWeekCount(int count) {
-            if (mShownWeekCount != count) {
-                mShownWeekCount = count;
-                mDelegator.invalidate();
-            }
-        }
-
-        @Override
-        public int getShownWeekCount() {
-            return mShownWeekCount;
-        }
-
-        @Override
-        public void setSelectedWeekBackgroundColor(int color) {
-            if (mSelectedWeekBackgroundColor != color) {
-                mSelectedWeekBackgroundColor = color;
-                final int childCount = mListView.getChildCount();
-                for (int i = 0; i < childCount; i++) {
-                    WeekView weekView = (WeekView) mListView.getChildAt(i);
-                    if (weekView.mHasSelectedDay) {
-                        weekView.invalidate();
-                    }
-                }
-            }
-        }
-
-        @Override
-        public int getSelectedWeekBackgroundColor() {
-            return mSelectedWeekBackgroundColor;
-        }
-
-        @Override
-        public void setFocusedMonthDateColor(int color) {
-            if (mFocusedMonthDateColor != color) {
-                mFocusedMonthDateColor = color;
-                final int childCount = mListView.getChildCount();
-                for (int i = 0; i < childCount; i++) {
-                    WeekView weekView = (WeekView) mListView.getChildAt(i);
-                    if (weekView.mHasFocusedDay) {
-                        weekView.invalidate();
-                    }
-                }
-            }
-        }
-
-        @Override
-        public int getFocusedMonthDateColor() {
-            return mFocusedMonthDateColor;
-        }
-
-        @Override
-        public void setUnfocusedMonthDateColor(int color) {
-            if (mUnfocusedMonthDateColor != color) {
-                mUnfocusedMonthDateColor = color;
-                final int childCount = mListView.getChildCount();
-                for (int i = 0; i < childCount; i++) {
-                    WeekView weekView = (WeekView) mListView.getChildAt(i);
-                    if (weekView.mHasUnfocusedDay) {
-                        weekView.invalidate();
-                    }
-                }
-            }
-        }
-
-        @Override
-        public int getUnfocusedMonthDateColor() {
-            return mFocusedMonthDateColor;
-        }
-
-        @Override
-        public void setWeekNumberColor(int color) {
-            if (mWeekNumberColor != color) {
-                mWeekNumberColor = color;
-                if (mShowWeekNumber) {
-                    invalidateAllWeekViews();
-                }
-            }
-        }
-
-        @Override
-        public int getWeekNumberColor() {
-            return mWeekNumberColor;
-        }
-
-        @Override
-        public void setWeekSeparatorLineColor(int color) {
-            if (mWeekSeparatorLineColor != color) {
-                mWeekSeparatorLineColor = color;
-                invalidateAllWeekViews();
-            }
-        }
-
-        @Override
-        public int getWeekSeparatorLineColor() {
-            return mWeekSeparatorLineColor;
-        }
-
-        @Override
-        public void setSelectedDateVerticalBar(int resourceId) {
-            Drawable drawable = mDelegator.getContext().getDrawable(resourceId);
-            setSelectedDateVerticalBar(drawable);
-        }
-
-        @Override
-        public void setSelectedDateVerticalBar(Drawable drawable) {
-            if (mSelectedDateVerticalBar != drawable) {
-                mSelectedDateVerticalBar = drawable;
-                final int childCount = mListView.getChildCount();
-                for (int i = 0; i < childCount; i++) {
-                    WeekView weekView = (WeekView) mListView.getChildAt(i);
-                    if (weekView.mHasSelectedDay) {
-                        weekView.invalidate();
-                    }
-                }
-            }
-        }
-
-        @Override
-        public Drawable getSelectedDateVerticalBar() {
-            return mSelectedDateVerticalBar;
-        }
-
-        @Override
-        public void setWeekDayTextAppearance(int resourceId) {
-            if (mWeekDayTextAppearanceResId != resourceId) {
-                mWeekDayTextAppearanceResId = resourceId;
-                setUpHeader();
-            }
-        }
-
-        @Override
-        public int getWeekDayTextAppearance() {
-            return mWeekDayTextAppearanceResId;
-        }
-
-        @Override
-        public void setDateTextAppearance(int resourceId) {
-            if (mDateTextAppearanceResId != resourceId) {
-                mDateTextAppearanceResId = resourceId;
-                updateDateTextSize();
-                invalidateAllWeekViews();
-            }
-        }
-
-        @Override
-        public int getDateTextAppearance() {
-            return mDateTextAppearanceResId;
-        }
-
-        @Override
-        public void setEnabled(boolean enabled) {
-            mListView.setEnabled(enabled);
-        }
-
-        @Override
-        public boolean isEnabled() {
-            return mListView.isEnabled();
-        }
-
-        @Override
-        public void setMinDate(long minDate) {
-            mTempDate.setTimeInMillis(minDate);
-            if (isSameDate(mTempDate, mMinDate)) {
-                return;
-            }
-            mMinDate.setTimeInMillis(minDate);
-            // make sure the current date is not earlier than
-            // the new min date since the latter is used for
-            // calculating the indices in the adapter thus
-            // avoiding out of bounds error
-            Calendar date = mAdapter.mSelectedDate;
-            if (date.before(mMinDate)) {
-                mAdapter.setSelectedDay(mMinDate);
-            }
-            // reinitialize the adapter since its range depends on min date
-            mAdapter.init();
-            if (date.before(mMinDate)) {
-                setDate(mTempDate.getTimeInMillis());
-            } else {
-                // we go to the current date to force the ListView to query its
-                // adapter for the shown views since we have changed the adapter
-                // range and the base from which the later calculates item indices
-                // note that calling setDate will not work since the date is the same
-                goTo(date, false, true, false);
-            }
-        }
-
-        @Override
-        public long getMinDate() {
-            return mMinDate.getTimeInMillis();
-        }
-
-        @Override
-        public void setMaxDate(long maxDate) {
-            mTempDate.setTimeInMillis(maxDate);
-            if (isSameDate(mTempDate, mMaxDate)) {
-                return;
-            }
-            mMaxDate.setTimeInMillis(maxDate);
-            // reinitialize the adapter since its range depends on max date
-            mAdapter.init();
-            Calendar date = mAdapter.mSelectedDate;
-            if (date.after(mMaxDate)) {
-                setDate(mMaxDate.getTimeInMillis());
-            } else {
-                // we go to the current date to force the ListView to query its
-                // adapter for the shown views since we have changed the adapter
-                // range and the base from which the later calculates item indices
-                // note that calling setDate will not work since the date is the same
-                goTo(date, false, true, false);
-            }
-        }
-
-        @Override
-        public long getMaxDate() {
-            return mMaxDate.getTimeInMillis();
-        }
-
-        @Override
-        public void setShowWeekNumber(boolean showWeekNumber) {
-            if (mShowWeekNumber == showWeekNumber) {
-                return;
-            }
-            mShowWeekNumber = showWeekNumber;
-            mAdapter.notifyDataSetChanged();
-            setUpHeader();
-        }
-
-        @Override
-        public boolean getShowWeekNumber() {
-            return mShowWeekNumber;
-        }
-
-        @Override
-        public void setFirstDayOfWeek(int firstDayOfWeek) {
-            if (mFirstDayOfWeek == firstDayOfWeek) {
-                return;
-            }
-            mFirstDayOfWeek = firstDayOfWeek;
-            mAdapter.init();
-            mAdapter.notifyDataSetChanged();
-            setUpHeader();
-        }
-
-        @Override
-        public int getFirstDayOfWeek() {
-            return mFirstDayOfWeek;
-        }
-
-        @Override
-        public void setDate(long date) {
-            setDate(date, false, false);
-        }
-
-        @Override
-        public void setDate(long date, boolean animate, boolean center) {
-            mTempDate.setTimeInMillis(date);
-            if (isSameDate(mTempDate, mAdapter.mSelectedDate)) {
-                return;
-            }
-            goTo(mTempDate, animate, true, center);
-        }
-
-        @Override
-        public long getDate() {
-            return mAdapter.mSelectedDate.getTimeInMillis();
-        }
-
-        @Override
-        public void setOnDateChangeListener(OnDateChangeListener listener) {
-            mOnDateChangeListener = listener;
-        }
-
-        @Override
-        public void onConfigurationChanged(Configuration newConfig) {
-            setCurrentLocale(newConfig.locale);
-        }
-
-        @Override
-        public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-            event.setClassName(CalendarView.class.getName());
-        }
-
-        @Override
-        public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-            info.setClassName(CalendarView.class.getName());
-        }
-
-        /**
-         * Sets the current locale.
-         *
-         * @param locale The current locale.
-         */
-        @Override
-        protected void setCurrentLocale(Locale locale) {
-            super.setCurrentLocale(locale);
-
-            mTempDate = getCalendarForLocale(mTempDate, locale);
-            mFirstDayOfMonth = getCalendarForLocale(mFirstDayOfMonth, locale);
-            mMinDate = getCalendarForLocale(mMinDate, locale);
-            mMaxDate = getCalendarForLocale(mMaxDate, locale);
-        }
-        private void updateDateTextSize() {
-            TypedArray dateTextAppearance = mDelegator.getContext().obtainStyledAttributes(
-                    mDateTextAppearanceResId, R.styleable.TextAppearance);
-            mDateTextSize = dateTextAppearance.getDimensionPixelSize(
-                    R.styleable.TextAppearance_textSize, DEFAULT_DATE_TEXT_SIZE);
-            dateTextAppearance.recycle();
-        }
-
-        /**
-         * Invalidates all week views.
-         */
-        private void invalidateAllWeekViews() {
-            final int childCount = mListView.getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                View view = mListView.getChildAt(i);
-                view.invalidate();
-            }
-        }
-
-        /**
-         * Gets a calendar for locale bootstrapped with the value of a given calendar.
-         *
-         * @param oldCalendar The old calendar.
-         * @param locale The locale.
-         */
-        private static Calendar getCalendarForLocale(Calendar oldCalendar, Locale locale) {
-            if (oldCalendar == null) {
-                return Calendar.getInstance(locale);
-            } else {
-                final long currentTimeMillis = oldCalendar.getTimeInMillis();
-                Calendar newCalendar = Calendar.getInstance(locale);
-                newCalendar.setTimeInMillis(currentTimeMillis);
-                return newCalendar;
-            }
-        }
-
-        /**
-         * @return True if the <code>firstDate</code> is the same as the <code>
-         * secondDate</code>.
-         */
-        private static boolean isSameDate(Calendar firstDate, Calendar secondDate) {
-            return (firstDate.get(Calendar.DAY_OF_YEAR) == secondDate.get(Calendar.DAY_OF_YEAR)
-                    && firstDate.get(Calendar.YEAR) == secondDate.get(Calendar.YEAR));
-        }
-
-        /**
-         * Creates a new adapter if necessary and sets up its parameters.
-         */
-        private void setUpAdapter() {
-            if (mAdapter == null) {
-                mAdapter = new WeeksAdapter(mContext);
-                mAdapter.registerDataSetObserver(new DataSetObserver() {
-                    @Override
-                    public void onChanged() {
-                        if (mOnDateChangeListener != null) {
-                            Calendar selectedDay = mAdapter.getSelectedDay();
-                            mOnDateChangeListener.onSelectedDayChange(mDelegator,
-                                    selectedDay.get(Calendar.YEAR),
-                                    selectedDay.get(Calendar.MONTH),
-                                    selectedDay.get(Calendar.DAY_OF_MONTH));
-                        }
-                    }
-                });
-                mListView.setAdapter(mAdapter);
-            }
-
-            // refresh the view with the new parameters
-            mAdapter.notifyDataSetChanged();
-        }
-
-        /**
-         * Sets up the strings to be used by the header.
-         */
-        private void setUpHeader() {
-            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;
-                mDayNamesShort[i - mFirstDayOfWeek] = DateUtils.getDayOfWeekString(calendarDay,
-                        DateUtils.LENGTH_SHORTEST);
-                mDayNamesLong[i - mFirstDayOfWeek] = DateUtils.getDayOfWeekString(calendarDay,
-                        DateUtils.LENGTH_LONG);
-            }
-
-            TextView label = (TextView) mDayNamesHeader.getChildAt(0);
-            if (mShowWeekNumber) {
-                label.setVisibility(View.VISIBLE);
-            } else {
-                label.setVisibility(View.GONE);
-            }
-            for (int i = 1, count = mDayNamesHeader.getChildCount(); i < count; i++) {
-                label = (TextView) mDayNamesHeader.getChildAt(i);
-                if (mWeekDayTextAppearanceResId > -1) {
-                    label.setTextAppearance(mContext, mWeekDayTextAppearanceResId);
-                }
-                if (i < mDaysPerWeek + 1) {
-                    label.setText(mDayNamesShort[i - 1]);
-                    label.setContentDescription(mDayNamesLong[i - 1]);
-                    label.setVisibility(View.VISIBLE);
-                } else {
-                    label.setVisibility(View.GONE);
-                }
-            }
-            mDayNamesHeader.invalidate();
-        }
-
-        /**
-         * Sets all the required fields for the list view.
-         */
-        private void setUpListView() {
-            // Configure the listview
-            mListView.setDivider(null);
-            mListView.setItemsCanFocus(true);
-            mListView.setVerticalScrollBarEnabled(false);
-            mListView.setOnScrollListener(new OnScrollListener() {
-                public void onScrollStateChanged(AbsListView view, int scrollState) {
-                    LegacyCalendarViewDelegate.this.onScrollStateChanged(view, scrollState);
-                }
-
-                public void onScroll(
-                        AbsListView view, int firstVisibleItem, int visibleItemCount,
-                        int totalItemCount) {
-                    LegacyCalendarViewDelegate.this.onScroll(view, firstVisibleItem,
-                            visibleItemCount, totalItemCount);
-                }
-            });
-            // Make the scrolling behavior nicer
-            mListView.setFriction(mFriction);
-            mListView.setVelocityScale(mVelocityScale);
-        }
-
-        /**
-         * This moves to the specified time in the view. If the time is not already
-         * in range it will move the list so that the first of the month containing
-         * the time is at the top of the view. If the new time is already in view
-         * the list will not be scrolled unless forceScroll is true. This time may
-         * optionally be highlighted as selected as well.
-         *
-         * @param date The time to move to.
-         * @param animate Whether to scroll to the given time or just redraw at the
-         *            new location.
-         * @param setSelected Whether to set the given time as selected.
-         * @param forceScroll Whether to recenter even if the time is already
-         *            visible.
-         *
-         * @throws IllegalArgumentException of the provided date is before the
-         *        range start of after the range end.
-         */
-        private void goTo(Calendar date, boolean animate, boolean setSelected,
-                boolean forceScroll) {
-            if (date.before(mMinDate) || date.after(mMaxDate)) {
-                throw new IllegalArgumentException("Time not between " + mMinDate.getTime()
-                        + " and " + mMaxDate.getTime());
-            }
-            // Find the first and last entirely visible weeks
-            int firstFullyVisiblePosition = mListView.getFirstVisiblePosition();
-            View firstChild = mListView.getChildAt(0);
-            if (firstChild != null && firstChild.getTop() < 0) {
-                firstFullyVisiblePosition++;
-            }
-            int lastFullyVisiblePosition = firstFullyVisiblePosition + mShownWeekCount - 1;
-            if (firstChild != null && firstChild.getTop() > mBottomBuffer) {
-                lastFullyVisiblePosition--;
-            }
-            if (setSelected) {
-                mAdapter.setSelectedDay(date);
-            }
-            // Get the week we're going to
-            int position = getWeeksSinceMinDate(date);
-
-            // Check if the selected day is now outside of our visible range
-            // and if so scroll to the month that contains it
-            if (position < firstFullyVisiblePosition || position > lastFullyVisiblePosition
-                    || forceScroll) {
-                mFirstDayOfMonth.setTimeInMillis(date.getTimeInMillis());
-                mFirstDayOfMonth.set(Calendar.DAY_OF_MONTH, 1);
-
-                setMonthDisplayed(mFirstDayOfMonth);
-
-                // the earliest time we can scroll to is the min date
-                if (mFirstDayOfMonth.before(mMinDate)) {
-                    position = 0;
-                } else {
-                    position = getWeeksSinceMinDate(mFirstDayOfMonth);
-                }
-
-                mPreviousScrollState = OnScrollListener.SCROLL_STATE_FLING;
-                if (animate) {
-                    mListView.smoothScrollToPositionFromTop(position, mListScrollTopOffset,
-                            GOTO_SCROLL_DURATION);
-                } else {
-                    mListView.setSelectionFromTop(position, mListScrollTopOffset);
-                    // Perform any after scroll operations that are needed
-                    onScrollStateChanged(mListView, OnScrollListener.SCROLL_STATE_IDLE);
-                }
-            } else if (setSelected) {
-                // Otherwise just set the selection
-                setMonthDisplayed(date);
-            }
-        }
 
         /**
          * Parses the given <code>date</code> and in case of success sets
@@ -1444,718 +607,15 @@
          *
          * @return True if the date was parsed.
          */
-        private boolean parseDate(String date, Calendar outDate) {
+        protected boolean parseDate(String date, Calendar outDate) {
             try {
-                outDate.setTime(mDateFormat.parse(date));
+                outDate.setTime(DATE_FORMATTER.parse(date));
                 return true;
             } catch (ParseException e) {
                 Log.w(LOG_TAG, "Date: " + date + " not in format: " + DATE_FORMAT);
                 return false;
             }
         }
-
-        /**
-         * Called when a <code>view</code> transitions to a new <code>scrollState
-         * </code>.
-         */
-        private void onScrollStateChanged(AbsListView view, int scrollState) {
-            mScrollStateChangedRunnable.doScrollStateChange(view, scrollState);
-        }
-
-        /**
-         * Updates the title and selected month if the <code>view</code> has moved to a new
-         * month.
-         */
-        private void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
-                              int totalItemCount) {
-            WeekView child = (WeekView) view.getChildAt(0);
-            if (child == null) {
-                return;
-            }
-
-            // Figure out where we are
-            long currScroll =
-                    view.getFirstVisiblePosition() * child.getHeight() - child.getBottom();
-
-            // If we have moved since our last call update the direction
-            if (currScroll < mPreviousScrollPosition) {
-                mIsScrollingUp = true;
-            } else if (currScroll > mPreviousScrollPosition) {
-                mIsScrollingUp = false;
-            } else {
-                return;
-            }
-
-            // Use some hysteresis for checking which month to highlight. This
-            // causes the month to transition when two full weeks of a month are
-            // visible when scrolling up, and when the first day in a month reaches
-            // the top of the screen when scrolling down.
-            int offset = child.getBottom() < mWeekMinVisibleHeight ? 1 : 0;
-            if (mIsScrollingUp) {
-                child = (WeekView) view.getChildAt(SCROLL_HYST_WEEKS + offset);
-            } else if (offset != 0) {
-                child = (WeekView) view.getChildAt(offset);
-            }
-
-            if (child != null) {
-                // Find out which month we're moving into
-                int month;
-                if (mIsScrollingUp) {
-                    month = child.getMonthOfFirstWeekDay();
-                } else {
-                    month = child.getMonthOfLastWeekDay();
-                }
-
-                // And how it relates to our current highlighted month
-                int monthDiff;
-                if (mCurrentMonthDisplayed == 11 && month == 0) {
-                    monthDiff = 1;
-                } else if (mCurrentMonthDisplayed == 0 && month == 11) {
-                    monthDiff = -1;
-                } else {
-                    monthDiff = month - mCurrentMonthDisplayed;
-                }
-
-                // Only switch months if we're scrolling away from the currently
-                // selected month
-                if ((!mIsScrollingUp && monthDiff > 0) || (mIsScrollingUp && monthDiff < 0)) {
-                    Calendar firstDay = child.getFirstDay();
-                    if (mIsScrollingUp) {
-                        firstDay.add(Calendar.DAY_OF_MONTH, -DAYS_PER_WEEK);
-                    } else {
-                        firstDay.add(Calendar.DAY_OF_MONTH, DAYS_PER_WEEK);
-                    }
-                    setMonthDisplayed(firstDay);
-                }
-            }
-            mPreviousScrollPosition = currScroll;
-            mPreviousScrollState = mCurrentScrollState;
-        }
-
-        /**
-         * Sets the month displayed at the top of this view based on time. Override
-         * to add custom events when the title is changed.
-         *
-         * @param calendar A day in the new focus month.
-         */
-        private void setMonthDisplayed(Calendar calendar) {
-            mCurrentMonthDisplayed = calendar.get(Calendar.MONTH);
-            mAdapter.setFocusMonth(mCurrentMonthDisplayed);
-            final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NO_MONTH_DAY
-                    | DateUtils.FORMAT_SHOW_YEAR;
-            final long millis = calendar.getTimeInMillis();
-            String newMonthName = DateUtils.formatDateRange(mContext, millis, millis, flags);
-            mMonthName.setText(newMonthName);
-            mMonthName.invalidate();
-        }
-
-        /**
-         * @return Returns the number of weeks between the current <code>date</code>
-         *         and the <code>mMinDate</code>.
-         */
-        private int getWeeksSinceMinDate(Calendar date) {
-            if (date.before(mMinDate)) {
-                throw new IllegalArgumentException("fromDate: " + mMinDate.getTime()
-                        + " does not precede toDate: " + date.getTime());
-            }
-            long endTimeMillis = date.getTimeInMillis()
-                    + date.getTimeZone().getOffset(date.getTimeInMillis());
-            long startTimeMillis = mMinDate.getTimeInMillis()
-                    + mMinDate.getTimeZone().getOffset(mMinDate.getTimeInMillis());
-            long dayOffsetMillis = (mMinDate.get(Calendar.DAY_OF_WEEK) - mFirstDayOfWeek)
-                    * MILLIS_IN_DAY;
-            return (int) ((endTimeMillis - startTimeMillis + dayOffsetMillis) / MILLIS_IN_WEEK);
-        }
-
-        /**
-         * Command responsible for acting upon scroll state changes.
-         */
-        private class ScrollStateRunnable implements Runnable {
-            private AbsListView mView;
-
-            private int mNewState;
-
-            /**
-             * Sets up the runnable with a short delay in case the scroll state
-             * immediately changes again.
-             *
-             * @param view The list view that changed state
-             * @param scrollState The new state it changed to
-             */
-            public void doScrollStateChange(AbsListView view, int scrollState) {
-                mView = view;
-                mNewState = scrollState;
-                mDelegator.removeCallbacks(this);
-                mDelegator.postDelayed(this, SCROLL_CHANGE_DELAY);
-            }
-
-            public void run() {
-                mCurrentScrollState = mNewState;
-                // Fix the position after a scroll or a fling ends
-                if (mNewState == OnScrollListener.SCROLL_STATE_IDLE
-                        && mPreviousScrollState != OnScrollListener.SCROLL_STATE_IDLE) {
-                    View child = mView.getChildAt(0);
-                    if (child == null) {
-                        // The view is no longer visible, just return
-                        return;
-                    }
-                    int dist = child.getBottom() - mListScrollTopOffset;
-                    if (dist > mListScrollTopOffset) {
-                        if (mIsScrollingUp) {
-                            mView.smoothScrollBy(dist - child.getHeight(),
-                                    ADJUSTMENT_SCROLL_DURATION);
-                        } else {
-                            mView.smoothScrollBy(dist, ADJUSTMENT_SCROLL_DURATION);
-                        }
-                    }
-                }
-                mPreviousScrollState = mNewState;
-            }
-        }
-
-        /**
-         * <p>
-         * This is a specialized adapter for creating a list of weeks with
-         * selectable days. It can be configured to display the week number, start
-         * the week on a given day, show a reduced number of days, or display an
-         * arbitrary number of weeks at a time.
-         * </p>
-         */
-        private class WeeksAdapter extends BaseAdapter implements OnTouchListener {
-
-            private int mSelectedWeek;
-
-            private GestureDetector mGestureDetector;
-
-            private int mFocusedMonth;
-
-            private final Calendar mSelectedDate = Calendar.getInstance();
-
-            private int mTotalWeekCount;
-
-            public WeeksAdapter(Context context) {
-                mContext = context;
-                mGestureDetector = new GestureDetector(mContext, new CalendarGestureListener());
-                init();
-            }
-
-            /**
-             * Set up the gesture detector and selected time
-             */
-            private void init() {
-                mSelectedWeek = getWeeksSinceMinDate(mSelectedDate);
-                mTotalWeekCount = getWeeksSinceMinDate(mMaxDate);
-                if (mMinDate.get(Calendar.DAY_OF_WEEK) != mFirstDayOfWeek
-                        || mMaxDate.get(Calendar.DAY_OF_WEEK) != mFirstDayOfWeek) {
-                    mTotalWeekCount++;
-                }
-                notifyDataSetChanged();
-            }
-
-            /**
-             * Updates the selected day and related parameters.
-             *
-             * @param selectedDay The time to highlight
-             */
-            public void setSelectedDay(Calendar selectedDay) {
-                if (selectedDay.get(Calendar.DAY_OF_YEAR) == mSelectedDate.get(Calendar.DAY_OF_YEAR)
-                        && selectedDay.get(Calendar.YEAR) == mSelectedDate.get(Calendar.YEAR)) {
-                    return;
-                }
-                mSelectedDate.setTimeInMillis(selectedDay.getTimeInMillis());
-                mSelectedWeek = getWeeksSinceMinDate(mSelectedDate);
-                mFocusedMonth = mSelectedDate.get(Calendar.MONTH);
-                notifyDataSetChanged();
-            }
-
-            /**
-             * @return The selected day of month.
-             */
-            public Calendar getSelectedDay() {
-                return mSelectedDate;
-            }
-
-            @Override
-            public int getCount() {
-                return mTotalWeekCount;
-            }
-
-            @Override
-            public Object getItem(int position) {
-                return null;
-            }
-
-            @Override
-            public long getItemId(int position) {
-                return position;
-            }
-
-            @Override
-            public View getView(int position, View convertView, ViewGroup parent) {
-                WeekView weekView = null;
-                if (convertView != null) {
-                    weekView = (WeekView) convertView;
-                } else {
-                    weekView = new WeekView(mContext);
-                    android.widget.AbsListView.LayoutParams params =
-                            new android.widget.AbsListView.LayoutParams(LayoutParams.WRAP_CONTENT,
-                                    LayoutParams.WRAP_CONTENT);
-                    weekView.setLayoutParams(params);
-                    weekView.setClickable(true);
-                    weekView.setOnTouchListener(this);
-                }
-
-                int selectedWeekDay = (mSelectedWeek == position) ? mSelectedDate.get(
-                        Calendar.DAY_OF_WEEK) : -1;
-                weekView.init(position, selectedWeekDay, mFocusedMonth);
-
-                return weekView;
-            }
-
-            /**
-             * Changes which month is in focus and updates the view.
-             *
-             * @param month The month to show as in focus [0-11]
-             */
-            public void setFocusMonth(int month) {
-                if (mFocusedMonth == month) {
-                    return;
-                }
-                mFocusedMonth = month;
-                notifyDataSetChanged();
-            }
-
-            @Override
-            public boolean onTouch(View v, MotionEvent event) {
-                if (mListView.isEnabled() && mGestureDetector.onTouchEvent(event)) {
-                    WeekView weekView = (WeekView) v;
-                    // if we cannot find a day for the given location we are done
-                    if (!weekView.getDayFromLocation(event.getX(), mTempDate)) {
-                        return true;
-                    }
-                    // it is possible that the touched day is outside the valid range
-                    // we draw whole weeks but range end can fall not on the week end
-                    if (mTempDate.before(mMinDate) || mTempDate.after(mMaxDate)) {
-                        return true;
-                    }
-                    onDateTapped(mTempDate);
-                    return true;
-                }
-                return false;
-            }
-
-            /**
-             * Maintains the same hour/min/sec but moves the day to the tapped day.
-             *
-             * @param day The day that was tapped
-             */
-            private void onDateTapped(Calendar day) {
-                setSelectedDay(day);
-                setMonthDisplayed(day);
-            }
-
-            /**
-             * This is here so we can identify single tap events and set the
-             * selected day correctly
-             */
-            class CalendarGestureListener extends GestureDetector.SimpleOnGestureListener {
-                @Override
-                public boolean onSingleTapUp(MotionEvent e) {
-                    return true;
-                }
-            }
-        }
-
-        /**
-         * <p>
-         * This is a dynamic view for drawing a single week. It can be configured to
-         * display the week number, start the week on a given day, or show a reduced
-         * number of days. It is intended for use as a single view within a
-         * ListView. See {@link WeeksAdapter} for usage.
-         * </p>
-         */
-        private class WeekView extends View {
-
-            private final Rect mTempRect = new Rect();
-
-            private final Paint mDrawPaint = new Paint();
-
-            private final Paint mMonthNumDrawPaint = new Paint();
-
-            // Cache the number strings so we don't have to recompute them each time
-            private String[] mDayNumbers;
-
-            // Quick lookup for checking which days are in the focus month
-            private boolean[] mFocusDay;
-
-            // Whether this view has a focused day.
-            private boolean mHasFocusedDay;
-
-            // Whether this view has only focused days.
-            private boolean mHasUnfocusedDay;
-
-            // The first day displayed by this item
-            private Calendar mFirstDay;
-
-            // The month of the first day in this week
-            private int mMonthOfFirstWeekDay = -1;
-
-            // The month of the last day in this week
-            private int mLastWeekDayMonth = -1;
-
-            // The position of this week, equivalent to weeks since the week of Jan
-            // 1st, 1900
-            private int mWeek = -1;
-
-            // Quick reference to the width of this view, matches parent
-            private int mWidth;
-
-            // The height this view should draw at in pixels, set by height param
-            private int mHeight;
-
-            // If this view contains the selected day
-            private boolean mHasSelectedDay = false;
-
-            // Which day is selected [0-6] or -1 if no day is selected
-            private int mSelectedDay = -1;
-
-            // The number of days + a spot for week number if it is displayed
-            private int mNumCells;
-
-            // The left edge of the selected day
-            private int mSelectedLeft = -1;
-
-            // The right edge of the selected day
-            private int mSelectedRight = -1;
-
-            public WeekView(Context context) {
-                super(context);
-
-                // Sets up any standard paints that will be used
-                initilaizePaints();
-            }
-
-            /**
-             * Initializes this week view.
-             *
-             * @param weekNumber The number of the week this view represents. The
-             *            week number is a zero based index of the weeks since
-             *            {@link CalendarView#getMinDate()}.
-             * @param selectedWeekDay The selected day of the week from 0 to 6, -1 if no
-             *            selected day.
-             * @param focusedMonth The month that is currently in focus i.e.
-             *            highlighted.
-             */
-            public void init(int weekNumber, int selectedWeekDay, int focusedMonth) {
-                mSelectedDay = selectedWeekDay;
-                mHasSelectedDay = mSelectedDay != -1;
-                mNumCells = mShowWeekNumber ? mDaysPerWeek + 1 : mDaysPerWeek;
-                mWeek = weekNumber;
-                mTempDate.setTimeInMillis(mMinDate.getTimeInMillis());
-
-                mTempDate.add(Calendar.WEEK_OF_YEAR, mWeek);
-                mTempDate.setFirstDayOfWeek(mFirstDayOfWeek);
-
-                // Allocate space for caching the day numbers and focus values
-                mDayNumbers = new String[mNumCells];
-                mFocusDay = new boolean[mNumCells];
-
-                // If we're showing the week number calculate it based on Monday
-                int i = 0;
-                if (mShowWeekNumber) {
-                    mDayNumbers[0] = String.format(Locale.getDefault(), "%d",
-                            mTempDate.get(Calendar.WEEK_OF_YEAR));
-                    i++;
-                }
-
-                // Now adjust our starting day based on the start day of the week
-                int diff = mFirstDayOfWeek - mTempDate.get(Calendar.DAY_OF_WEEK);
-                mTempDate.add(Calendar.DAY_OF_MONTH, diff);
-
-                mFirstDay = (Calendar) mTempDate.clone();
-                mMonthOfFirstWeekDay = mTempDate.get(Calendar.MONTH);
-
-                mHasUnfocusedDay = true;
-                for (; i < mNumCells; i++) {
-                    final boolean isFocusedDay = (mTempDate.get(Calendar.MONTH) == focusedMonth);
-                    mFocusDay[i] = isFocusedDay;
-                    mHasFocusedDay |= isFocusedDay;
-                    mHasUnfocusedDay &= !isFocusedDay;
-                    // do not draw dates outside the valid range to avoid user confusion
-                    if (mTempDate.before(mMinDate) || mTempDate.after(mMaxDate)) {
-                        mDayNumbers[i] = "";
-                    } else {
-                        mDayNumbers[i] = String.format(Locale.getDefault(), "%d",
-                                mTempDate.get(Calendar.DAY_OF_MONTH));
-                    }
-                    mTempDate.add(Calendar.DAY_OF_MONTH, 1);
-                }
-                // We do one extra add at the end of the loop, if that pushed us to
-                // new month undo it
-                if (mTempDate.get(Calendar.DAY_OF_MONTH) == 1) {
-                    mTempDate.add(Calendar.DAY_OF_MONTH, -1);
-                }
-                mLastWeekDayMonth = mTempDate.get(Calendar.MONTH);
-
-                updateSelectionPositions();
-            }
-
-            /**
-             * Initialize the paint instances.
-             */
-            private void initilaizePaints() {
-                mDrawPaint.setFakeBoldText(false);
-                mDrawPaint.setAntiAlias(true);
-                mDrawPaint.setStyle(Style.FILL);
-
-                mMonthNumDrawPaint.setFakeBoldText(true);
-                mMonthNumDrawPaint.setAntiAlias(true);
-                mMonthNumDrawPaint.setStyle(Style.FILL);
-                mMonthNumDrawPaint.setTextAlign(Align.CENTER);
-                mMonthNumDrawPaint.setTextSize(mDateTextSize);
-            }
-
-            /**
-             * Returns the month of the first day in this week.
-             *
-             * @return The month the first day of this view is in.
-             */
-            public int getMonthOfFirstWeekDay() {
-                return mMonthOfFirstWeekDay;
-            }
-
-            /**
-             * Returns the month of the last day in this week
-             *
-             * @return The month the last day of this view is in
-             */
-            public int getMonthOfLastWeekDay() {
-                return mLastWeekDayMonth;
-            }
-
-            /**
-             * Returns the first day in this view.
-             *
-             * @return The first day in the view.
-             */
-            public Calendar getFirstDay() {
-                return mFirstDay;
-            }
-
-            /**
-             * Calculates the day that the given x position is in, accounting for
-             * week number.
-             *
-             * @param x The x position of the touch event.
-             * @return True if a day was found for the given location.
-             */
-            public boolean getDayFromLocation(float x, Calendar outCalendar) {
-                final boolean isLayoutRtl = isLayoutRtl();
-
-                int start;
-                int end;
-
-                if (isLayoutRtl) {
-                    start = 0;
-                    end = mShowWeekNumber ? mWidth - mWidth / mNumCells : mWidth;
-                } else {
-                    start = mShowWeekNumber ? mWidth / mNumCells : 0;
-                    end = mWidth;
-                }
-
-                if (x < start || x > end) {
-                    outCalendar.clear();
-                    return false;
-                }
-
-                // Selection is (x - start) / (pixels/day) which is (x - start) * day / pixels
-                int dayPosition = (int) ((x - start) * mDaysPerWeek / (end - start));
-
-                if (isLayoutRtl) {
-                    dayPosition = mDaysPerWeek - 1 - dayPosition;
-                }
-
-                outCalendar.setTimeInMillis(mFirstDay.getTimeInMillis());
-                outCalendar.add(Calendar.DAY_OF_MONTH, dayPosition);
-
-                return true;
-            }
-
-            @Override
-            protected void onDraw(Canvas canvas) {
-                drawBackground(canvas);
-                drawWeekNumbersAndDates(canvas);
-                drawWeekSeparators(canvas);
-                drawSelectedDateVerticalBars(canvas);
-            }
-
-            /**
-             * This draws the selection highlight if a day is selected in this week.
-             *
-             * @param canvas The canvas to draw on
-             */
-            private void drawBackground(Canvas canvas) {
-                if (!mHasSelectedDay) {
-                    return;
-                }
-                mDrawPaint.setColor(mSelectedWeekBackgroundColor);
-
-                mTempRect.top = mWeekSeperatorLineWidth;
-                mTempRect.bottom = mHeight;
-
-                final boolean isLayoutRtl = isLayoutRtl();
-
-                if (isLayoutRtl) {
-                    mTempRect.left = 0;
-                    mTempRect.right = mSelectedLeft - 2;
-                } else {
-                    mTempRect.left = mShowWeekNumber ? mWidth / mNumCells : 0;
-                    mTempRect.right = mSelectedLeft - 2;
-                }
-                canvas.drawRect(mTempRect, mDrawPaint);
-
-                if (isLayoutRtl) {
-                    mTempRect.left = mSelectedRight + 3;
-                    mTempRect.right = mShowWeekNumber ? mWidth - mWidth / mNumCells : mWidth;
-                } else {
-                    mTempRect.left = mSelectedRight + 3;
-                    mTempRect.right = mWidth;
-                }
-                canvas.drawRect(mTempRect, mDrawPaint);
-            }
-
-            /**
-             * Draws the week and month day numbers for this week.
-             *
-             * @param canvas The canvas to draw on
-             */
-            private void drawWeekNumbersAndDates(Canvas canvas) {
-                final float textHeight = mDrawPaint.getTextSize();
-                final int y = (int) ((mHeight + textHeight) / 2) - mWeekSeperatorLineWidth;
-                final int nDays = mNumCells;
-                final int divisor = 2 * nDays;
-
-                mDrawPaint.setTextAlign(Align.CENTER);
-                mDrawPaint.setTextSize(mDateTextSize);
-
-                int i = 0;
-
-                if (isLayoutRtl()) {
-                    for (; i < nDays - 1; i++) {
-                        mMonthNumDrawPaint.setColor(mFocusDay[i] ? mFocusedMonthDateColor
-                                : mUnfocusedMonthDateColor);
-                        int x = (2 * i + 1) * mWidth / divisor;
-                        canvas.drawText(mDayNumbers[nDays - 1 - i], x, y, mMonthNumDrawPaint);
-                    }
-                    if (mShowWeekNumber) {
-                        mDrawPaint.setColor(mWeekNumberColor);
-                        int x = mWidth - mWidth / divisor;
-                        canvas.drawText(mDayNumbers[0], x, y, mDrawPaint);
-                    }
-                } else {
-                    if (mShowWeekNumber) {
-                        mDrawPaint.setColor(mWeekNumberColor);
-                        int x = mWidth / divisor;
-                        canvas.drawText(mDayNumbers[0], x, y, mDrawPaint);
-                        i++;
-                    }
-                    for (; i < nDays; i++) {
-                        mMonthNumDrawPaint.setColor(mFocusDay[i] ? mFocusedMonthDateColor
-                                : mUnfocusedMonthDateColor);
-                        int x = (2 * i + 1) * mWidth / divisor;
-                        canvas.drawText(mDayNumbers[i], x, y, mMonthNumDrawPaint);
-                    }
-                }
-            }
-
-            /**
-             * Draws a horizontal line for separating the weeks.
-             *
-             * @param canvas The canvas to draw on.
-             */
-            private void drawWeekSeparators(Canvas canvas) {
-                // If it is the topmost fully visible child do not draw separator line
-                int firstFullyVisiblePosition = mListView.getFirstVisiblePosition();
-                if (mListView.getChildAt(0).getTop() < 0) {
-                    firstFullyVisiblePosition++;
-                }
-                if (firstFullyVisiblePosition == mWeek) {
-                    return;
-                }
-                mDrawPaint.setColor(mWeekSeparatorLineColor);
-                mDrawPaint.setStrokeWidth(mWeekSeperatorLineWidth);
-                float startX;
-                float stopX;
-                if (isLayoutRtl()) {
-                    startX = 0;
-                    stopX = mShowWeekNumber ? mWidth - mWidth / mNumCells : mWidth;
-                } else {
-                    startX = mShowWeekNumber ? mWidth / mNumCells : 0;
-                    stopX = mWidth;
-                }
-                canvas.drawLine(startX, 0, stopX, 0, mDrawPaint);
-            }
-
-            /**
-             * Draws the selected date bars if this week has a selected day.
-             *
-             * @param canvas The canvas to draw on
-             */
-            private void drawSelectedDateVerticalBars(Canvas canvas) {
-                if (!mHasSelectedDay) {
-                    return;
-                }
-                mSelectedDateVerticalBar.setBounds(
-                        mSelectedLeft - mSelectedDateVerticalBarWidth / 2,
-                        mWeekSeperatorLineWidth,
-                        mSelectedLeft + mSelectedDateVerticalBarWidth / 2,
-                        mHeight);
-                mSelectedDateVerticalBar.draw(canvas);
-                mSelectedDateVerticalBar.setBounds(
-                        mSelectedRight - mSelectedDateVerticalBarWidth / 2,
-                        mWeekSeperatorLineWidth,
-                        mSelectedRight + mSelectedDateVerticalBarWidth / 2,
-                        mHeight);
-                mSelectedDateVerticalBar.draw(canvas);
-            }
-
-            @Override
-            protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-                mWidth = w;
-                updateSelectionPositions();
-            }
-
-            /**
-             * This calculates the positions for the selected day lines.
-             */
-            private void updateSelectionPositions() {
-                if (mHasSelectedDay) {
-                    final boolean isLayoutRtl = isLayoutRtl();
-                    int selectedPosition = mSelectedDay - mFirstDayOfWeek;
-                    if (selectedPosition < 0) {
-                        selectedPosition += 7;
-                    }
-                    if (mShowWeekNumber && !isLayoutRtl) {
-                        selectedPosition++;
-                    }
-                    if (isLayoutRtl) {
-                        mSelectedLeft = (mDaysPerWeek - 1 - selectedPosition) * mWidth / mNumCells;
-
-                    } else {
-                        mSelectedLeft = selectedPosition * mWidth / mNumCells;
-                    }
-                    mSelectedRight = mSelectedLeft + mWidth / mNumCells;
-                }
-            }
-
-            @Override
-            protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-                mHeight = (mListView.getHeight() - mListView.getPaddingTop() - mListView
-                        .getPaddingBottom()) / mShownWeekCount;
-                setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), mHeight);
-            }
-        }
-
     }
 
 }
diff --git a/core/java/android/widget/CalendarViewLegacyDelegate.java b/core/java/android/widget/CalendarViewLegacyDelegate.java
new file mode 100644
index 0000000..2ab3548
--- /dev/null
+++ b/core/java/android/widget/CalendarViewLegacyDelegate.java
@@ -0,0 +1,1527 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+import com.android.internal.R;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.TypedArray;
+import android.database.DataSetObserver;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.GestureDetector;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.Calendar;
+import java.util.Locale;
+
+import libcore.icu.LocaleData;
+
+/**
+ * A delegate implementing the legacy CalendarView
+ */
+class CalendarViewLegacyDelegate extends CalendarView.AbstractCalendarViewDelegate {
+    /**
+     * Default value whether to show week number.
+     */
+    private static final boolean DEFAULT_SHOW_WEEK_NUMBER = true;
+
+    /**
+     * The number of milliseconds in a day.e
+     */
+    private static final long MILLIS_IN_DAY = 86400000L;
+
+    /**
+     * The number of day in a week.
+     */
+    private static final int DAYS_PER_WEEK = 7;
+
+    /**
+     * The number of milliseconds in a week.
+     */
+    private static final long MILLIS_IN_WEEK = DAYS_PER_WEEK * MILLIS_IN_DAY;
+
+    /**
+     * Affects when the month selection will change while scrolling upe
+     */
+    private static final int SCROLL_HYST_WEEKS = 2;
+
+    /**
+     * How long the GoTo fling animation should last.
+     */
+    private static final int GOTO_SCROLL_DURATION = 1000;
+
+    /**
+     * The duration of the adjustment upon a user scroll in milliseconds.
+     */
+    private static final int ADJUSTMENT_SCROLL_DURATION = 500;
+
+    /**
+     * How long to wait after receiving an onScrollStateChanged notification
+     * before acting on it.
+     */
+    private static final int SCROLL_CHANGE_DELAY = 40;
+
+    private static final int DEFAULT_SHOWN_WEEK_COUNT = 6;
+
+    private static final int DEFAULT_DATE_TEXT_SIZE = 14;
+
+    private static final int UNSCALED_SELECTED_DATE_VERTICAL_BAR_WIDTH = 6;
+
+    private static final int UNSCALED_WEEK_MIN_VISIBLE_HEIGHT = 12;
+
+    private static final int UNSCALED_LIST_SCROLL_TOP_OFFSET = 2;
+
+    private static final int UNSCALED_BOTTOM_BUFFER = 20;
+
+    private static final int UNSCALED_WEEK_SEPARATOR_LINE_WIDTH = 1;
+
+    private static final int DEFAULT_WEEK_DAY_TEXT_APPEARANCE_RES_ID = -1;
+
+    private final int mWeekSeperatorLineWidth;
+
+    private int mDateTextSize;
+
+    private Drawable mSelectedDateVerticalBar;
+
+    private final int mSelectedDateVerticalBarWidth;
+
+    private int mSelectedWeekBackgroundColor;
+
+    private int mFocusedMonthDateColor;
+
+    private int mUnfocusedMonthDateColor;
+
+    private int mWeekSeparatorLineColor;
+
+    private int mWeekNumberColor;
+
+    private int mWeekDayTextAppearanceResId;
+
+    private int mDateTextAppearanceResId;
+
+    /**
+     * The top offset of the weeks list.
+     */
+    private int mListScrollTopOffset = 2;
+
+    /**
+     * The visible height of a week view.
+     */
+    private int mWeekMinVisibleHeight = 12;
+
+    /**
+     * The visible height of a week view.
+     */
+    private int mBottomBuffer = 20;
+
+    /**
+     * The number of shown weeks.
+     */
+    private int mShownWeekCount;
+
+    /**
+     * Flag whether to show the week number.
+     */
+    private boolean mShowWeekNumber;
+
+    /**
+     * The number of day per week to be shown.
+     */
+    private int mDaysPerWeek = 7;
+
+    /**
+     * The friction of the week list while flinging.
+     */
+    private float mFriction = .05f;
+
+    /**
+     * Scale for adjusting velocity of the week list while flinging.
+     */
+    private float mVelocityScale = 0.333f;
+
+    /**
+     * The adapter for the weeks list.
+     */
+    private WeeksAdapter mAdapter;
+
+    /**
+     * The weeks list.
+     */
+    private ListView mListView;
+
+    /**
+     * The name of the month to display.
+     */
+    private TextView mMonthName;
+
+    /**
+     * The header with week day names.
+     */
+    private ViewGroup mDayNamesHeader;
+
+    /**
+     * Cached abbreviations for day of week names.
+     */
+    private String[] mDayNamesShort;
+
+    /**
+     * Cached full-length day of week names.
+     */
+    private String[] mDayNamesLong;
+
+    /**
+     * The first day of the week.
+     */
+    private int mFirstDayOfWeek;
+
+    /**
+     * Which month should be displayed/highlighted [0-11].
+     */
+    private int mCurrentMonthDisplayed = -1;
+
+    /**
+     * Used for tracking during a scroll.
+     */
+    private long mPreviousScrollPosition;
+
+    /**
+     * Used for tracking which direction the view is scrolling.
+     */
+    private boolean mIsScrollingUp = false;
+
+    /**
+     * The previous scroll state of the weeks ListView.
+     */
+    private int mPreviousScrollState = AbsListView.OnScrollListener.SCROLL_STATE_IDLE;
+
+    /**
+     * The current scroll state of the weeks ListView.
+     */
+    private int mCurrentScrollState = AbsListView.OnScrollListener.SCROLL_STATE_IDLE;
+
+    /**
+     * Listener for changes in the selected day.
+     */
+    private CalendarView.OnDateChangeListener mOnDateChangeListener;
+
+    /**
+     * Command for adjusting the position after a scroll/fling.
+     */
+    private ScrollStateRunnable mScrollStateChangedRunnable = new ScrollStateRunnable();
+
+    /**
+     * Temporary instance to avoid multiple instantiations.
+     */
+    private Calendar mTempDate;
+
+    /**
+     * The first day of the focused month.
+     */
+    private Calendar mFirstDayOfMonth;
+
+    /**
+     * The start date of the range supported by this picker.
+     */
+    private Calendar mMinDate;
+
+    /**
+     * The end date of the range supported by this picker.
+     */
+    private Calendar mMaxDate;
+
+    CalendarViewLegacyDelegate(CalendarView delegator, Context context, AttributeSet attrs,
+            int defStyleAttr, int defStyleRes) {
+        super(delegator, context);
+
+        final TypedArray a = context.obtainStyledAttributes(attrs,
+                R.styleable.CalendarView, defStyleAttr, defStyleRes);
+        mShowWeekNumber = a.getBoolean(R.styleable.CalendarView_showWeekNumber,
+                DEFAULT_SHOW_WEEK_NUMBER);
+        mFirstDayOfWeek = a.getInt(R.styleable.CalendarView_firstDayOfWeek,
+                LocaleData.get(Locale.getDefault()).firstDayOfWeek);
+        final String minDate = a.getString(R.styleable.CalendarView_minDate);
+        if (TextUtils.isEmpty(minDate) || !parseDate(minDate, mMinDate)) {
+            parseDate(DEFAULT_MIN_DATE, mMinDate);
+        }
+        final String maxDate = a.getString(R.styleable.CalendarView_maxDate);
+        if (TextUtils.isEmpty(maxDate) || !parseDate(maxDate, mMaxDate)) {
+            parseDate(DEFAULT_MAX_DATE, mMaxDate);
+        }
+        if (mMaxDate.before(mMinDate)) {
+            throw new IllegalArgumentException("Max date cannot be before min date.");
+        }
+        mShownWeekCount = a.getInt(R.styleable.CalendarView_shownWeekCount,
+                DEFAULT_SHOWN_WEEK_COUNT);
+        mSelectedWeekBackgroundColor = a.getColor(
+                R.styleable.CalendarView_selectedWeekBackgroundColor, 0);
+        mFocusedMonthDateColor = a.getColor(
+                R.styleable.CalendarView_focusedMonthDateColor, 0);
+        mUnfocusedMonthDateColor = a.getColor(
+                R.styleable.CalendarView_unfocusedMonthDateColor, 0);
+        mWeekSeparatorLineColor = a.getColor(
+                R.styleable.CalendarView_weekSeparatorLineColor, 0);
+        mWeekNumberColor = a.getColor(R.styleable.CalendarView_weekNumberColor, 0);
+        mSelectedDateVerticalBar = a.getDrawable(
+                R.styleable.CalendarView_selectedDateVerticalBar);
+
+        mDateTextAppearanceResId = a.getResourceId(
+                R.styleable.CalendarView_dateTextAppearance, R.style.TextAppearance_Small);
+        updateDateTextSize();
+
+        mWeekDayTextAppearanceResId = a.getResourceId(
+                R.styleable.CalendarView_weekDayTextAppearance,
+                DEFAULT_WEEK_DAY_TEXT_APPEARANCE_RES_ID);
+        a.recycle();
+
+        DisplayMetrics displayMetrics = mDelegator.getResources().getDisplayMetrics();
+        mWeekMinVisibleHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                UNSCALED_WEEK_MIN_VISIBLE_HEIGHT, displayMetrics);
+        mListScrollTopOffset = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                UNSCALED_LIST_SCROLL_TOP_OFFSET, displayMetrics);
+        mBottomBuffer = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                UNSCALED_BOTTOM_BUFFER, displayMetrics);
+        mSelectedDateVerticalBarWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                UNSCALED_SELECTED_DATE_VERTICAL_BAR_WIDTH, displayMetrics);
+        mWeekSeperatorLineWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                UNSCALED_WEEK_SEPARATOR_LINE_WIDTH, displayMetrics);
+
+        LayoutInflater layoutInflater = (LayoutInflater) mContext
+                .getSystemService(Service.LAYOUT_INFLATER_SERVICE);
+        View content = layoutInflater.inflate(R.layout.calendar_view, null, false);
+        mDelegator.addView(content);
+
+        mListView = (ListView) mDelegator.findViewById(R.id.list);
+        mDayNamesHeader = (ViewGroup) content.findViewById(R.id.day_names);
+        mMonthName = (TextView) content.findViewById(R.id.month_name);
+
+        setUpHeader();
+        setUpListView();
+        setUpAdapter();
+
+        // go to today or whichever is close to today min or max date
+        mTempDate.setTimeInMillis(System.currentTimeMillis());
+        if (mTempDate.before(mMinDate)) {
+            goTo(mMinDate, false, true, true);
+        } else if (mMaxDate.before(mTempDate)) {
+            goTo(mMaxDate, false, true, true);
+        } else {
+            goTo(mTempDate, false, true, true);
+        }
+
+        mDelegator.invalidate();
+    }
+
+    @Override
+    public void setShownWeekCount(int count) {
+        if (mShownWeekCount != count) {
+            mShownWeekCount = count;
+            mDelegator.invalidate();
+        }
+    }
+
+    @Override
+    public int getShownWeekCount() {
+        return mShownWeekCount;
+    }
+
+    @Override
+    public void setSelectedWeekBackgroundColor(int color) {
+        if (mSelectedWeekBackgroundColor != color) {
+            mSelectedWeekBackgroundColor = color;
+            final int childCount = mListView.getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                WeekView weekView = (WeekView) mListView.getChildAt(i);
+                if (weekView.mHasSelectedDay) {
+                    weekView.invalidate();
+                }
+            }
+        }
+    }
+
+    @Override
+    public int getSelectedWeekBackgroundColor() {
+        return mSelectedWeekBackgroundColor;
+    }
+
+    @Override
+    public void setFocusedMonthDateColor(int color) {
+        if (mFocusedMonthDateColor != color) {
+            mFocusedMonthDateColor = color;
+            final int childCount = mListView.getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                WeekView weekView = (WeekView) mListView.getChildAt(i);
+                if (weekView.mHasFocusedDay) {
+                    weekView.invalidate();
+                }
+            }
+        }
+    }
+
+    @Override
+    public int getFocusedMonthDateColor() {
+        return mFocusedMonthDateColor;
+    }
+
+    @Override
+    public void setUnfocusedMonthDateColor(int color) {
+        if (mUnfocusedMonthDateColor != color) {
+            mUnfocusedMonthDateColor = color;
+            final int childCount = mListView.getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                WeekView weekView = (WeekView) mListView.getChildAt(i);
+                if (weekView.mHasUnfocusedDay) {
+                    weekView.invalidate();
+                }
+            }
+        }
+    }
+
+    @Override
+    public int getUnfocusedMonthDateColor() {
+        return mFocusedMonthDateColor;
+    }
+
+    @Override
+    public void setWeekNumberColor(int color) {
+        if (mWeekNumberColor != color) {
+            mWeekNumberColor = color;
+            if (mShowWeekNumber) {
+                invalidateAllWeekViews();
+            }
+        }
+    }
+
+    @Override
+    public int getWeekNumberColor() {
+        return mWeekNumberColor;
+    }
+
+    @Override
+    public void setWeekSeparatorLineColor(int color) {
+        if (mWeekSeparatorLineColor != color) {
+            mWeekSeparatorLineColor = color;
+            invalidateAllWeekViews();
+        }
+    }
+
+    @Override
+    public int getWeekSeparatorLineColor() {
+        return mWeekSeparatorLineColor;
+    }
+
+    @Override
+    public void setSelectedDateVerticalBar(int resourceId) {
+        Drawable drawable = mDelegator.getContext().getDrawable(resourceId);
+        setSelectedDateVerticalBar(drawable);
+    }
+
+    @Override
+    public void setSelectedDateVerticalBar(Drawable drawable) {
+        if (mSelectedDateVerticalBar != drawable) {
+            mSelectedDateVerticalBar = drawable;
+            final int childCount = mListView.getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                WeekView weekView = (WeekView) mListView.getChildAt(i);
+                if (weekView.mHasSelectedDay) {
+                    weekView.invalidate();
+                }
+            }
+        }
+    }
+
+    @Override
+    public Drawable getSelectedDateVerticalBar() {
+        return mSelectedDateVerticalBar;
+    }
+
+    @Override
+    public void setWeekDayTextAppearance(int resourceId) {
+        if (mWeekDayTextAppearanceResId != resourceId) {
+            mWeekDayTextAppearanceResId = resourceId;
+            setUpHeader();
+        }
+    }
+
+    @Override
+    public int getWeekDayTextAppearance() {
+        return mWeekDayTextAppearanceResId;
+    }
+
+    @Override
+    public void setDateTextAppearance(int resourceId) {
+        if (mDateTextAppearanceResId != resourceId) {
+            mDateTextAppearanceResId = resourceId;
+            updateDateTextSize();
+            invalidateAllWeekViews();
+        }
+    }
+
+    @Override
+    public int getDateTextAppearance() {
+        return mDateTextAppearanceResId;
+    }
+
+    @Override
+    public void setMinDate(long minDate) {
+        mTempDate.setTimeInMillis(minDate);
+        if (isSameDate(mTempDate, mMinDate)) {
+            return;
+        }
+        mMinDate.setTimeInMillis(minDate);
+        // make sure the current date is not earlier than
+        // the new min date since the latter is used for
+        // calculating the indices in the adapter thus
+        // avoiding out of bounds error
+        Calendar date = mAdapter.mSelectedDate;
+        if (date.before(mMinDate)) {
+            mAdapter.setSelectedDay(mMinDate);
+        }
+        // reinitialize the adapter since its range depends on min date
+        mAdapter.init();
+        if (date.before(mMinDate)) {
+            setDate(mTempDate.getTimeInMillis());
+        } else {
+            // we go to the current date to force the ListView to query its
+            // adapter for the shown views since we have changed the adapter
+            // range and the base from which the later calculates item indices
+            // note that calling setDate will not work since the date is the same
+            goTo(date, false, true, false);
+        }
+    }
+
+    @Override
+    public long getMinDate() {
+        return mMinDate.getTimeInMillis();
+    }
+
+    @Override
+    public void setMaxDate(long maxDate) {
+        mTempDate.setTimeInMillis(maxDate);
+        if (isSameDate(mTempDate, mMaxDate)) {
+            return;
+        }
+        mMaxDate.setTimeInMillis(maxDate);
+        // reinitialize the adapter since its range depends on max date
+        mAdapter.init();
+        Calendar date = mAdapter.mSelectedDate;
+        if (date.after(mMaxDate)) {
+            setDate(mMaxDate.getTimeInMillis());
+        } else {
+            // we go to the current date to force the ListView to query its
+            // adapter for the shown views since we have changed the adapter
+            // range and the base from which the later calculates item indices
+            // note that calling setDate will not work since the date is the same
+            goTo(date, false, true, false);
+        }
+    }
+
+    @Override
+    public long getMaxDate() {
+        return mMaxDate.getTimeInMillis();
+    }
+
+    @Override
+    public void setShowWeekNumber(boolean showWeekNumber) {
+        if (mShowWeekNumber == showWeekNumber) {
+            return;
+        }
+        mShowWeekNumber = showWeekNumber;
+        mAdapter.notifyDataSetChanged();
+        setUpHeader();
+    }
+
+    @Override
+    public boolean getShowWeekNumber() {
+        return mShowWeekNumber;
+    }
+
+    @Override
+    public void setFirstDayOfWeek(int firstDayOfWeek) {
+        if (mFirstDayOfWeek == firstDayOfWeek) {
+            return;
+        }
+        mFirstDayOfWeek = firstDayOfWeek;
+        mAdapter.init();
+        mAdapter.notifyDataSetChanged();
+        setUpHeader();
+    }
+
+    @Override
+    public int getFirstDayOfWeek() {
+        return mFirstDayOfWeek;
+    }
+
+    @Override
+    public void setDate(long date) {
+        setDate(date, false, false);
+    }
+
+    @Override
+    public void setDate(long date, boolean animate, boolean center) {
+        mTempDate.setTimeInMillis(date);
+        if (isSameDate(mTempDate, mAdapter.mSelectedDate)) {
+            return;
+        }
+        goTo(mTempDate, animate, true, center);
+    }
+
+    @Override
+    public long getDate() {
+        return mAdapter.mSelectedDate.getTimeInMillis();
+    }
+
+    @Override
+    public void setOnDateChangeListener(CalendarView.OnDateChangeListener listener) {
+        mOnDateChangeListener = listener;
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        setCurrentLocale(newConfig.locale);
+    }
+
+    /**
+     * Sets the current locale.
+     *
+     * @param locale The current locale.
+     */
+    @Override
+    protected void setCurrentLocale(Locale locale) {
+        super.setCurrentLocale(locale);
+
+        mTempDate = getCalendarForLocale(mTempDate, locale);
+        mFirstDayOfMonth = getCalendarForLocale(mFirstDayOfMonth, locale);
+        mMinDate = getCalendarForLocale(mMinDate, locale);
+        mMaxDate = getCalendarForLocale(mMaxDate, locale);
+    }
+    private void updateDateTextSize() {
+        TypedArray dateTextAppearance = mDelegator.getContext().obtainStyledAttributes(
+                mDateTextAppearanceResId, R.styleable.TextAppearance);
+        mDateTextSize = dateTextAppearance.getDimensionPixelSize(
+                R.styleable.TextAppearance_textSize, DEFAULT_DATE_TEXT_SIZE);
+        dateTextAppearance.recycle();
+    }
+
+    /**
+     * Invalidates all week views.
+     */
+    private void invalidateAllWeekViews() {
+        final int childCount = mListView.getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View view = mListView.getChildAt(i);
+            view.invalidate();
+        }
+    }
+
+    /**
+     * Gets a calendar for locale bootstrapped with the value of a given calendar.
+     *
+     * @param oldCalendar The old calendar.
+     * @param locale The locale.
+     */
+    private static Calendar getCalendarForLocale(Calendar oldCalendar, Locale locale) {
+        if (oldCalendar == null) {
+            return Calendar.getInstance(locale);
+        } else {
+            final long currentTimeMillis = oldCalendar.getTimeInMillis();
+            Calendar newCalendar = Calendar.getInstance(locale);
+            newCalendar.setTimeInMillis(currentTimeMillis);
+            return newCalendar;
+        }
+    }
+
+    /**
+     * @return True if the <code>firstDate</code> is the same as the <code>
+     * secondDate</code>.
+     */
+    private static boolean isSameDate(Calendar firstDate, Calendar secondDate) {
+        return (firstDate.get(Calendar.DAY_OF_YEAR) == secondDate.get(Calendar.DAY_OF_YEAR)
+                && firstDate.get(Calendar.YEAR) == secondDate.get(Calendar.YEAR));
+    }
+
+    /**
+     * Creates a new adapter if necessary and sets up its parameters.
+     */
+    private void setUpAdapter() {
+        if (mAdapter == null) {
+            mAdapter = new WeeksAdapter(mContext);
+            mAdapter.registerDataSetObserver(new DataSetObserver() {
+                @Override
+                public void onChanged() {
+                    if (mOnDateChangeListener != null) {
+                        Calendar selectedDay = mAdapter.getSelectedDay();
+                        mOnDateChangeListener.onSelectedDayChange(mDelegator,
+                                selectedDay.get(Calendar.YEAR),
+                                selectedDay.get(Calendar.MONTH),
+                                selectedDay.get(Calendar.DAY_OF_MONTH));
+                    }
+                }
+            });
+            mListView.setAdapter(mAdapter);
+        }
+
+        // refresh the view with the new parameters
+        mAdapter.notifyDataSetChanged();
+    }
+
+    /**
+     * Sets up the strings to be used by the header.
+     */
+    private void setUpHeader() {
+        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;
+            mDayNamesShort[i - mFirstDayOfWeek] = DateUtils.getDayOfWeekString(calendarDay,
+                    DateUtils.LENGTH_SHORTEST);
+            mDayNamesLong[i - mFirstDayOfWeek] = DateUtils.getDayOfWeekString(calendarDay,
+                    DateUtils.LENGTH_LONG);
+        }
+
+        TextView label = (TextView) mDayNamesHeader.getChildAt(0);
+        if (mShowWeekNumber) {
+            label.setVisibility(View.VISIBLE);
+        } else {
+            label.setVisibility(View.GONE);
+        }
+        for (int i = 1, count = mDayNamesHeader.getChildCount(); i < count; i++) {
+            label = (TextView) mDayNamesHeader.getChildAt(i);
+            if (mWeekDayTextAppearanceResId > -1) {
+                label.setTextAppearance(mContext, mWeekDayTextAppearanceResId);
+            }
+            if (i < mDaysPerWeek + 1) {
+                label.setText(mDayNamesShort[i - 1]);
+                label.setContentDescription(mDayNamesLong[i - 1]);
+                label.setVisibility(View.VISIBLE);
+            } else {
+                label.setVisibility(View.GONE);
+            }
+        }
+        mDayNamesHeader.invalidate();
+    }
+
+    /**
+     * Sets all the required fields for the list view.
+     */
+    private void setUpListView() {
+        // Configure the listview
+        mListView.setDivider(null);
+        mListView.setItemsCanFocus(true);
+        mListView.setVerticalScrollBarEnabled(false);
+        mListView.setOnScrollListener(new AbsListView.OnScrollListener() {
+            public void onScrollStateChanged(AbsListView view, int scrollState) {
+                CalendarViewLegacyDelegate.this.onScrollStateChanged(view, scrollState);
+            }
+
+            public void onScroll(
+                    AbsListView view, int firstVisibleItem, int visibleItemCount,
+                    int totalItemCount) {
+                CalendarViewLegacyDelegate.this.onScroll(view, firstVisibleItem,
+                        visibleItemCount, totalItemCount);
+            }
+        });
+        // Make the scrolling behavior nicer
+        mListView.setFriction(mFriction);
+        mListView.setVelocityScale(mVelocityScale);
+    }
+
+    /**
+     * This moves to the specified time in the view. If the time is not already
+     * in range it will move the list so that the first of the month containing
+     * the time is at the top of the view. If the new time is already in view
+     * the list will not be scrolled unless forceScroll is true. This time may
+     * optionally be highlighted as selected as well.
+     *
+     * @param date The time to move to.
+     * @param animate Whether to scroll to the given time or just redraw at the
+     *            new location.
+     * @param setSelected Whether to set the given time as selected.
+     * @param forceScroll Whether to recenter even if the time is already
+     *            visible.
+     *
+     * @throws IllegalArgumentException of the provided date is before the
+     *        range start of after the range end.
+     */
+    private void goTo(Calendar date, boolean animate, boolean setSelected,
+            boolean forceScroll) {
+        if (date.before(mMinDate) || date.after(mMaxDate)) {
+            throw new IllegalArgumentException("Time not between " + mMinDate.getTime()
+                    + " and " + mMaxDate.getTime());
+        }
+        // Find the first and last entirely visible weeks
+        int firstFullyVisiblePosition = mListView.getFirstVisiblePosition();
+        View firstChild = mListView.getChildAt(0);
+        if (firstChild != null && firstChild.getTop() < 0) {
+            firstFullyVisiblePosition++;
+        }
+        int lastFullyVisiblePosition = firstFullyVisiblePosition + mShownWeekCount - 1;
+        if (firstChild != null && firstChild.getTop() > mBottomBuffer) {
+            lastFullyVisiblePosition--;
+        }
+        if (setSelected) {
+            mAdapter.setSelectedDay(date);
+        }
+        // Get the week we're going to
+        int position = getWeeksSinceMinDate(date);
+
+        // Check if the selected day is now outside of our visible range
+        // and if so scroll to the month that contains it
+        if (position < firstFullyVisiblePosition || position > lastFullyVisiblePosition
+                || forceScroll) {
+            mFirstDayOfMonth.setTimeInMillis(date.getTimeInMillis());
+            mFirstDayOfMonth.set(Calendar.DAY_OF_MONTH, 1);
+
+            setMonthDisplayed(mFirstDayOfMonth);
+
+            // the earliest time we can scroll to is the min date
+            if (mFirstDayOfMonth.before(mMinDate)) {
+                position = 0;
+            } else {
+                position = getWeeksSinceMinDate(mFirstDayOfMonth);
+            }
+
+            mPreviousScrollState = AbsListView.OnScrollListener.SCROLL_STATE_FLING;
+            if (animate) {
+                mListView.smoothScrollToPositionFromTop(position, mListScrollTopOffset,
+                        GOTO_SCROLL_DURATION);
+            } else {
+                mListView.setSelectionFromTop(position, mListScrollTopOffset);
+                // Perform any after scroll operations that are needed
+                onScrollStateChanged(mListView, AbsListView.OnScrollListener.SCROLL_STATE_IDLE);
+            }
+        } else if (setSelected) {
+            // Otherwise just set the selection
+            setMonthDisplayed(date);
+        }
+    }
+
+    /**
+     * Called when a <code>view</code> transitions to a new <code>scrollState
+     * </code>.
+     */
+    private void onScrollStateChanged(AbsListView view, int scrollState) {
+        mScrollStateChangedRunnable.doScrollStateChange(view, scrollState);
+    }
+
+    /**
+     * Updates the title and selected month if the <code>view</code> has moved to a new
+     * month.
+     */
+    private void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
+                          int totalItemCount) {
+        WeekView child = (WeekView) view.getChildAt(0);
+        if (child == null) {
+            return;
+        }
+
+        // Figure out where we are
+        long currScroll =
+                view.getFirstVisiblePosition() * child.getHeight() - child.getBottom();
+
+        // If we have moved since our last call update the direction
+        if (currScroll < mPreviousScrollPosition) {
+            mIsScrollingUp = true;
+        } else if (currScroll > mPreviousScrollPosition) {
+            mIsScrollingUp = false;
+        } else {
+            return;
+        }
+
+        // Use some hysteresis for checking which month to highlight. This
+        // causes the month to transition when two full weeks of a month are
+        // visible when scrolling up, and when the first day in a month reaches
+        // the top of the screen when scrolling down.
+        int offset = child.getBottom() < mWeekMinVisibleHeight ? 1 : 0;
+        if (mIsScrollingUp) {
+            child = (WeekView) view.getChildAt(SCROLL_HYST_WEEKS + offset);
+        } else if (offset != 0) {
+            child = (WeekView) view.getChildAt(offset);
+        }
+
+        if (child != null) {
+            // Find out which month we're moving into
+            int month;
+            if (mIsScrollingUp) {
+                month = child.getMonthOfFirstWeekDay();
+            } else {
+                month = child.getMonthOfLastWeekDay();
+            }
+
+            // And how it relates to our current highlighted month
+            int monthDiff;
+            if (mCurrentMonthDisplayed == 11 && month == 0) {
+                monthDiff = 1;
+            } else if (mCurrentMonthDisplayed == 0 && month == 11) {
+                monthDiff = -1;
+            } else {
+                monthDiff = month - mCurrentMonthDisplayed;
+            }
+
+            // Only switch months if we're scrolling away from the currently
+            // selected month
+            if ((!mIsScrollingUp && monthDiff > 0) || (mIsScrollingUp && monthDiff < 0)) {
+                Calendar firstDay = child.getFirstDay();
+                if (mIsScrollingUp) {
+                    firstDay.add(Calendar.DAY_OF_MONTH, -DAYS_PER_WEEK);
+                } else {
+                    firstDay.add(Calendar.DAY_OF_MONTH, DAYS_PER_WEEK);
+                }
+                setMonthDisplayed(firstDay);
+            }
+        }
+        mPreviousScrollPosition = currScroll;
+        mPreviousScrollState = mCurrentScrollState;
+    }
+
+    /**
+     * Sets the month displayed at the top of this view based on time. Override
+     * to add custom events when the title is changed.
+     *
+     * @param calendar A day in the new focus month.
+     */
+    private void setMonthDisplayed(Calendar calendar) {
+        mCurrentMonthDisplayed = calendar.get(Calendar.MONTH);
+        mAdapter.setFocusMonth(mCurrentMonthDisplayed);
+        final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NO_MONTH_DAY
+                | DateUtils.FORMAT_SHOW_YEAR;
+        final long millis = calendar.getTimeInMillis();
+        String newMonthName = DateUtils.formatDateRange(mContext, millis, millis, flags);
+        mMonthName.setText(newMonthName);
+        mMonthName.invalidate();
+    }
+
+    /**
+     * @return Returns the number of weeks between the current <code>date</code>
+     *         and the <code>mMinDate</code>.
+     */
+    private int getWeeksSinceMinDate(Calendar date) {
+        if (date.before(mMinDate)) {
+            throw new IllegalArgumentException("fromDate: " + mMinDate.getTime()
+                    + " does not precede toDate: " + date.getTime());
+        }
+        long endTimeMillis = date.getTimeInMillis()
+                + date.getTimeZone().getOffset(date.getTimeInMillis());
+        long startTimeMillis = mMinDate.getTimeInMillis()
+                + mMinDate.getTimeZone().getOffset(mMinDate.getTimeInMillis());
+        long dayOffsetMillis = (mMinDate.get(Calendar.DAY_OF_WEEK) - mFirstDayOfWeek)
+                * MILLIS_IN_DAY;
+        return (int) ((endTimeMillis - startTimeMillis + dayOffsetMillis) / MILLIS_IN_WEEK);
+    }
+
+    /**
+     * Command responsible for acting upon scroll state changes.
+     */
+    private class ScrollStateRunnable implements Runnable {
+        private AbsListView mView;
+
+        private int mNewState;
+
+        /**
+         * Sets up the runnable with a short delay in case the scroll state
+         * immediately changes again.
+         *
+         * @param view The list view that changed state
+         * @param scrollState The new state it changed to
+         */
+        public void doScrollStateChange(AbsListView view, int scrollState) {
+            mView = view;
+            mNewState = scrollState;
+            mDelegator.removeCallbacks(this);
+            mDelegator.postDelayed(this, SCROLL_CHANGE_DELAY);
+        }
+
+        public void run() {
+            mCurrentScrollState = mNewState;
+            // Fix the position after a scroll or a fling ends
+            if (mNewState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE
+                    && mPreviousScrollState != AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {
+                View child = mView.getChildAt(0);
+                if (child == null) {
+                    // The view is no longer visible, just return
+                    return;
+                }
+                int dist = child.getBottom() - mListScrollTopOffset;
+                if (dist > mListScrollTopOffset) {
+                    if (mIsScrollingUp) {
+                        mView.smoothScrollBy(dist - child.getHeight(),
+                                ADJUSTMENT_SCROLL_DURATION);
+                    } else {
+                        mView.smoothScrollBy(dist, ADJUSTMENT_SCROLL_DURATION);
+                    }
+                }
+            }
+            mPreviousScrollState = mNewState;
+        }
+    }
+
+    /**
+     * <p>
+     * This is a specialized adapter for creating a list of weeks with
+     * selectable days. It can be configured to display the week number, start
+     * the week on a given day, show a reduced number of days, or display an
+     * arbitrary number of weeks at a time.
+     * </p>
+     */
+    private class WeeksAdapter extends BaseAdapter implements View.OnTouchListener {
+
+        private int mSelectedWeek;
+
+        private GestureDetector mGestureDetector;
+
+        private int mFocusedMonth;
+
+        private final Calendar mSelectedDate = Calendar.getInstance();
+
+        private int mTotalWeekCount;
+
+        public WeeksAdapter(Context context) {
+            mContext = context;
+            mGestureDetector = new GestureDetector(mContext, new WeeksAdapter.CalendarGestureListener());
+            init();
+        }
+
+        /**
+         * Set up the gesture detector and selected time
+         */
+        private void init() {
+            mSelectedWeek = getWeeksSinceMinDate(mSelectedDate);
+            mTotalWeekCount = getWeeksSinceMinDate(mMaxDate);
+            if (mMinDate.get(Calendar.DAY_OF_WEEK) != mFirstDayOfWeek
+                    || mMaxDate.get(Calendar.DAY_OF_WEEK) != mFirstDayOfWeek) {
+                mTotalWeekCount++;
+            }
+            notifyDataSetChanged();
+        }
+
+        /**
+         * Updates the selected day and related parameters.
+         *
+         * @param selectedDay The time to highlight
+         */
+        public void setSelectedDay(Calendar selectedDay) {
+            if (selectedDay.get(Calendar.DAY_OF_YEAR) == mSelectedDate.get(Calendar.DAY_OF_YEAR)
+                    && selectedDay.get(Calendar.YEAR) == mSelectedDate.get(Calendar.YEAR)) {
+                return;
+            }
+            mSelectedDate.setTimeInMillis(selectedDay.getTimeInMillis());
+            mSelectedWeek = getWeeksSinceMinDate(mSelectedDate);
+            mFocusedMonth = mSelectedDate.get(Calendar.MONTH);
+            notifyDataSetChanged();
+        }
+
+        /**
+         * @return The selected day of month.
+         */
+        public Calendar getSelectedDay() {
+            return mSelectedDate;
+        }
+
+        @Override
+        public int getCount() {
+            return mTotalWeekCount;
+        }
+
+        @Override
+        public Object getItem(int position) {
+            return null;
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return position;
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            WeekView weekView = null;
+            if (convertView != null) {
+                weekView = (WeekView) convertView;
+            } else {
+                weekView = new WeekView(mContext);
+                AbsListView.LayoutParams params =
+                        new AbsListView.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT,
+                                FrameLayout.LayoutParams.WRAP_CONTENT);
+                weekView.setLayoutParams(params);
+                weekView.setClickable(true);
+                weekView.setOnTouchListener(this);
+            }
+
+            int selectedWeekDay = (mSelectedWeek == position) ? mSelectedDate.get(
+                    Calendar.DAY_OF_WEEK) : -1;
+            weekView.init(position, selectedWeekDay, mFocusedMonth);
+
+            return weekView;
+        }
+
+        /**
+         * Changes which month is in focus and updates the view.
+         *
+         * @param month The month to show as in focus [0-11]
+         */
+        public void setFocusMonth(int month) {
+            if (mFocusedMonth == month) {
+                return;
+            }
+            mFocusedMonth = month;
+            notifyDataSetChanged();
+        }
+
+        @Override
+        public boolean onTouch(View v, MotionEvent event) {
+            if (mListView.isEnabled() && mGestureDetector.onTouchEvent(event)) {
+                WeekView weekView = (WeekView) v;
+                // if we cannot find a day for the given location we are done
+                if (!weekView.getDayFromLocation(event.getX(), mTempDate)) {
+                    return true;
+                }
+                // it is possible that the touched day is outside the valid range
+                // we draw whole weeks but range end can fall not on the week end
+                if (mTempDate.before(mMinDate) || mTempDate.after(mMaxDate)) {
+                    return true;
+                }
+                onDateTapped(mTempDate);
+                return true;
+            }
+            return false;
+        }
+
+        /**
+         * Maintains the same hour/min/sec but moves the day to the tapped day.
+         *
+         * @param day The day that was tapped
+         */
+        private void onDateTapped(Calendar day) {
+            setSelectedDay(day);
+            setMonthDisplayed(day);
+        }
+
+        /**
+         * This is here so we can identify single tap events and set the
+         * selected day correctly
+         */
+        class CalendarGestureListener extends GestureDetector.SimpleOnGestureListener {
+            @Override
+            public boolean onSingleTapUp(MotionEvent e) {
+                return true;
+            }
+        }
+    }
+
+    /**
+     * <p>
+     * This is a dynamic view for drawing a single week. It can be configured to
+     * display the week number, start the week on a given day, or show a reduced
+     * number of days. It is intended for use as a single view within a
+     * ListView. See {@link WeeksAdapter} for usage.
+     * </p>
+     */
+    private class WeekView extends View {
+
+        private final Rect mTempRect = new Rect();
+
+        private final Paint mDrawPaint = new Paint();
+
+        private final Paint mMonthNumDrawPaint = new Paint();
+
+        // Cache the number strings so we don't have to recompute them each time
+        private String[] mDayNumbers;
+
+        // Quick lookup for checking which days are in the focus month
+        private boolean[] mFocusDay;
+
+        // Whether this view has a focused day.
+        private boolean mHasFocusedDay;
+
+        // Whether this view has only focused days.
+        private boolean mHasUnfocusedDay;
+
+        // The first day displayed by this item
+        private Calendar mFirstDay;
+
+        // The month of the first day in this week
+        private int mMonthOfFirstWeekDay = -1;
+
+        // The month of the last day in this week
+        private int mLastWeekDayMonth = -1;
+
+        // The position of this week, equivalent to weeks since the week of Jan
+        // 1st, 1900
+        private int mWeek = -1;
+
+        // Quick reference to the width of this view, matches parent
+        private int mWidth;
+
+        // The height this view should draw at in pixels, set by height param
+        private int mHeight;
+
+        // If this view contains the selected day
+        private boolean mHasSelectedDay = false;
+
+        // Which day is selected [0-6] or -1 if no day is selected
+        private int mSelectedDay = -1;
+
+        // The number of days + a spot for week number if it is displayed
+        private int mNumCells;
+
+        // The left edge of the selected day
+        private int mSelectedLeft = -1;
+
+        // The right edge of the selected day
+        private int mSelectedRight = -1;
+
+        public WeekView(Context context) {
+            super(context);
+
+            // Sets up any standard paints that will be used
+            initilaizePaints();
+        }
+
+        /**
+         * Initializes this week view.
+         *
+         * @param weekNumber The number of the week this view represents. The
+         *            week number is a zero based index of the weeks since
+         *            {@link android.widget.CalendarView#getMinDate()}.
+         * @param selectedWeekDay The selected day of the week from 0 to 6, -1 if no
+         *            selected day.
+         * @param focusedMonth The month that is currently in focus i.e.
+         *            highlighted.
+         */
+        public void init(int weekNumber, int selectedWeekDay, int focusedMonth) {
+            mSelectedDay = selectedWeekDay;
+            mHasSelectedDay = mSelectedDay != -1;
+            mNumCells = mShowWeekNumber ? mDaysPerWeek + 1 : mDaysPerWeek;
+            mWeek = weekNumber;
+            mTempDate.setTimeInMillis(mMinDate.getTimeInMillis());
+
+            mTempDate.add(Calendar.WEEK_OF_YEAR, mWeek);
+            mTempDate.setFirstDayOfWeek(mFirstDayOfWeek);
+
+            // Allocate space for caching the day numbers and focus values
+            mDayNumbers = new String[mNumCells];
+            mFocusDay = new boolean[mNumCells];
+
+            // If we're showing the week number calculate it based on Monday
+            int i = 0;
+            if (mShowWeekNumber) {
+                mDayNumbers[0] = String.format(Locale.getDefault(), "%d",
+                        mTempDate.get(Calendar.WEEK_OF_YEAR));
+                i++;
+            }
+
+            // Now adjust our starting day based on the start day of the week
+            int diff = mFirstDayOfWeek - mTempDate.get(Calendar.DAY_OF_WEEK);
+            mTempDate.add(Calendar.DAY_OF_MONTH, diff);
+
+            mFirstDay = (Calendar) mTempDate.clone();
+            mMonthOfFirstWeekDay = mTempDate.get(Calendar.MONTH);
+
+            mHasUnfocusedDay = true;
+            for (; i < mNumCells; i++) {
+                final boolean isFocusedDay = (mTempDate.get(Calendar.MONTH) == focusedMonth);
+                mFocusDay[i] = isFocusedDay;
+                mHasFocusedDay |= isFocusedDay;
+                mHasUnfocusedDay &= !isFocusedDay;
+                // do not draw dates outside the valid range to avoid user confusion
+                if (mTempDate.before(mMinDate) || mTempDate.after(mMaxDate)) {
+                    mDayNumbers[i] = "";
+                } else {
+                    mDayNumbers[i] = String.format(Locale.getDefault(), "%d",
+                            mTempDate.get(Calendar.DAY_OF_MONTH));
+                }
+                mTempDate.add(Calendar.DAY_OF_MONTH, 1);
+            }
+            // We do one extra add at the end of the loop, if that pushed us to
+            // new month undo it
+            if (mTempDate.get(Calendar.DAY_OF_MONTH) == 1) {
+                mTempDate.add(Calendar.DAY_OF_MONTH, -1);
+            }
+            mLastWeekDayMonth = mTempDate.get(Calendar.MONTH);
+
+            updateSelectionPositions();
+        }
+
+        /**
+         * Initialize the paint instances.
+         */
+        private void initilaizePaints() {
+            mDrawPaint.setFakeBoldText(false);
+            mDrawPaint.setAntiAlias(true);
+            mDrawPaint.setStyle(Paint.Style.FILL);
+
+            mMonthNumDrawPaint.setFakeBoldText(true);
+            mMonthNumDrawPaint.setAntiAlias(true);
+            mMonthNumDrawPaint.setStyle(Paint.Style.FILL);
+            mMonthNumDrawPaint.setTextAlign(Paint.Align.CENTER);
+            mMonthNumDrawPaint.setTextSize(mDateTextSize);
+        }
+
+        /**
+         * Returns the month of the first day in this week.
+         *
+         * @return The month the first day of this view is in.
+         */
+        public int getMonthOfFirstWeekDay() {
+            return mMonthOfFirstWeekDay;
+        }
+
+        /**
+         * Returns the month of the last day in this week
+         *
+         * @return The month the last day of this view is in
+         */
+        public int getMonthOfLastWeekDay() {
+            return mLastWeekDayMonth;
+        }
+
+        /**
+         * Returns the first day in this view.
+         *
+         * @return The first day in the view.
+         */
+        public Calendar getFirstDay() {
+            return mFirstDay;
+        }
+
+        /**
+         * Calculates the day that the given x position is in, accounting for
+         * week number.
+         *
+         * @param x The x position of the touch event.
+         * @return True if a day was found for the given location.
+         */
+        public boolean getDayFromLocation(float x, Calendar outCalendar) {
+            final boolean isLayoutRtl = isLayoutRtl();
+
+            int start;
+            int end;
+
+            if (isLayoutRtl) {
+                start = 0;
+                end = mShowWeekNumber ? mWidth - mWidth / mNumCells : mWidth;
+            } else {
+                start = mShowWeekNumber ? mWidth / mNumCells : 0;
+                end = mWidth;
+            }
+
+            if (x < start || x > end) {
+                outCalendar.clear();
+                return false;
+            }
+
+            // Selection is (x - start) / (pixels/day) which is (x - start) * day / pixels
+            int dayPosition = (int) ((x - start) * mDaysPerWeek / (end - start));
+
+            if (isLayoutRtl) {
+                dayPosition = mDaysPerWeek - 1 - dayPosition;
+            }
+
+            outCalendar.setTimeInMillis(mFirstDay.getTimeInMillis());
+            outCalendar.add(Calendar.DAY_OF_MONTH, dayPosition);
+
+            return true;
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            drawBackground(canvas);
+            drawWeekNumbersAndDates(canvas);
+            drawWeekSeparators(canvas);
+            drawSelectedDateVerticalBars(canvas);
+        }
+
+        /**
+         * This draws the selection highlight if a day is selected in this week.
+         *
+         * @param canvas The canvas to draw on
+         */
+        private void drawBackground(Canvas canvas) {
+            if (!mHasSelectedDay) {
+                return;
+            }
+            mDrawPaint.setColor(mSelectedWeekBackgroundColor);
+
+            mTempRect.top = mWeekSeperatorLineWidth;
+            mTempRect.bottom = mHeight;
+
+            final boolean isLayoutRtl = isLayoutRtl();
+
+            if (isLayoutRtl) {
+                mTempRect.left = 0;
+                mTempRect.right = mSelectedLeft - 2;
+            } else {
+                mTempRect.left = mShowWeekNumber ? mWidth / mNumCells : 0;
+                mTempRect.right = mSelectedLeft - 2;
+            }
+            canvas.drawRect(mTempRect, mDrawPaint);
+
+            if (isLayoutRtl) {
+                mTempRect.left = mSelectedRight + 3;
+                mTempRect.right = mShowWeekNumber ? mWidth - mWidth / mNumCells : mWidth;
+            } else {
+                mTempRect.left = mSelectedRight + 3;
+                mTempRect.right = mWidth;
+            }
+            canvas.drawRect(mTempRect, mDrawPaint);
+        }
+
+        /**
+         * Draws the week and month day numbers for this week.
+         *
+         * @param canvas The canvas to draw on
+         */
+        private void drawWeekNumbersAndDates(Canvas canvas) {
+            final float textHeight = mDrawPaint.getTextSize();
+            final int y = (int) ((mHeight + textHeight) / 2) - mWeekSeperatorLineWidth;
+            final int nDays = mNumCells;
+            final int divisor = 2 * nDays;
+
+            mDrawPaint.setTextAlign(Paint.Align.CENTER);
+            mDrawPaint.setTextSize(mDateTextSize);
+
+            int i = 0;
+
+            if (isLayoutRtl()) {
+                for (; i < nDays - 1; i++) {
+                    mMonthNumDrawPaint.setColor(mFocusDay[i] ? mFocusedMonthDateColor
+                            : mUnfocusedMonthDateColor);
+                    int x = (2 * i + 1) * mWidth / divisor;
+                    canvas.drawText(mDayNumbers[nDays - 1 - i], x, y, mMonthNumDrawPaint);
+                }
+                if (mShowWeekNumber) {
+                    mDrawPaint.setColor(mWeekNumberColor);
+                    int x = mWidth - mWidth / divisor;
+                    canvas.drawText(mDayNumbers[0], x, y, mDrawPaint);
+                }
+            } else {
+                if (mShowWeekNumber) {
+                    mDrawPaint.setColor(mWeekNumberColor);
+                    int x = mWidth / divisor;
+                    canvas.drawText(mDayNumbers[0], x, y, mDrawPaint);
+                    i++;
+                }
+                for (; i < nDays; i++) {
+                    mMonthNumDrawPaint.setColor(mFocusDay[i] ? mFocusedMonthDateColor
+                            : mUnfocusedMonthDateColor);
+                    int x = (2 * i + 1) * mWidth / divisor;
+                    canvas.drawText(mDayNumbers[i], x, y, mMonthNumDrawPaint);
+                }
+            }
+        }
+
+        /**
+         * Draws a horizontal line for separating the weeks.
+         *
+         * @param canvas The canvas to draw on.
+         */
+        private void drawWeekSeparators(Canvas canvas) {
+            // If it is the topmost fully visible child do not draw separator line
+            int firstFullyVisiblePosition = mListView.getFirstVisiblePosition();
+            if (mListView.getChildAt(0).getTop() < 0) {
+                firstFullyVisiblePosition++;
+            }
+            if (firstFullyVisiblePosition == mWeek) {
+                return;
+            }
+            mDrawPaint.setColor(mWeekSeparatorLineColor);
+            mDrawPaint.setStrokeWidth(mWeekSeperatorLineWidth);
+            float startX;
+            float stopX;
+            if (isLayoutRtl()) {
+                startX = 0;
+                stopX = mShowWeekNumber ? mWidth - mWidth / mNumCells : mWidth;
+            } else {
+                startX = mShowWeekNumber ? mWidth / mNumCells : 0;
+                stopX = mWidth;
+            }
+            canvas.drawLine(startX, 0, stopX, 0, mDrawPaint);
+        }
+
+        /**
+         * Draws the selected date bars if this week has a selected day.
+         *
+         * @param canvas The canvas to draw on
+         */
+        private void drawSelectedDateVerticalBars(Canvas canvas) {
+            if (!mHasSelectedDay) {
+                return;
+            }
+            mSelectedDateVerticalBar.setBounds(
+                    mSelectedLeft - mSelectedDateVerticalBarWidth / 2,
+                    mWeekSeperatorLineWidth,
+                    mSelectedLeft + mSelectedDateVerticalBarWidth / 2,
+                    mHeight);
+            mSelectedDateVerticalBar.draw(canvas);
+            mSelectedDateVerticalBar.setBounds(
+                    mSelectedRight - mSelectedDateVerticalBarWidth / 2,
+                    mWeekSeperatorLineWidth,
+                    mSelectedRight + mSelectedDateVerticalBarWidth / 2,
+                    mHeight);
+            mSelectedDateVerticalBar.draw(canvas);
+        }
+
+        @Override
+        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+            mWidth = w;
+            updateSelectionPositions();
+        }
+
+        /**
+         * This calculates the positions for the selected day lines.
+         */
+        private void updateSelectionPositions() {
+            if (mHasSelectedDay) {
+                final boolean isLayoutRtl = isLayoutRtl();
+                int selectedPosition = mSelectedDay - mFirstDayOfWeek;
+                if (selectedPosition < 0) {
+                    selectedPosition += 7;
+                }
+                if (mShowWeekNumber && !isLayoutRtl) {
+                    selectedPosition++;
+                }
+                if (isLayoutRtl) {
+                    mSelectedLeft = (mDaysPerWeek - 1 - selectedPosition) * mWidth / mNumCells;
+
+                } else {
+                    mSelectedLeft = selectedPosition * mWidth / mNumCells;
+                }
+                mSelectedRight = mSelectedLeft + mWidth / mNumCells;
+            }
+        }
+
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            mHeight = (mListView.getHeight() - mListView.getPaddingTop() - mListView
+                    .getPaddingBottom()) / mShownWeekCount;
+            setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), mHeight);
+        }
+    }
+
+}
diff --git a/core/java/android/widget/CalendarViewMaterialDelegate.java b/core/java/android/widget/CalendarViewMaterialDelegate.java
new file mode 100644
index 0000000..b0f3740
--- /dev/null
+++ b/core/java/android/widget/CalendarViewMaterialDelegate.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+import com.android.internal.R;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.MathUtils;
+
+import java.util.Calendar;
+import java.util.Locale;
+
+import libcore.icu.LocaleData;
+
+class CalendarViewMaterialDelegate extends CalendarView.AbstractCalendarViewDelegate {
+    private final DayPickerView mDayPickerView;
+
+    private CalendarView.OnDateChangeListener mOnDateChangeListener;
+
+    public CalendarViewMaterialDelegate(CalendarView delegator, Context context, AttributeSet attrs,
+            int defStyleAttr, int defStyleRes) {
+        super(delegator, context);
+
+        final TypedArray a = context.obtainStyledAttributes(attrs,
+                R.styleable.CalendarView, defStyleAttr, defStyleRes);
+        final int firstDayOfWeek = a.getInt(R.styleable.CalendarView_firstDayOfWeek,
+                LocaleData.get(Locale.getDefault()).firstDayOfWeek);
+
+        final long minDate = parseDateToMillis(a.getString(
+                R.styleable.CalendarView_minDate), DEFAULT_MIN_DATE);
+        final long maxDate = parseDateToMillis(a.getString(
+                R.styleable.CalendarView_maxDate), DEFAULT_MAX_DATE);
+        if (maxDate < minDate) {
+            throw new IllegalArgumentException("max date cannot be before min date");
+        }
+
+        final long setDate = MathUtils.constrain(System.currentTimeMillis(), minDate, maxDate);
+        final int dateTextAppearanceResId = a.getResourceId(
+                R.styleable.CalendarView_dateTextAppearance,
+                R.style.TextAppearance_DeviceDefault_Small);
+
+        a.recycle();
+
+        mDayPickerView = new DayPickerView(context);
+        mDayPickerView.setFirstDayOfWeek(firstDayOfWeek);
+        mDayPickerView.setCalendarTextAppearance(dateTextAppearanceResId);
+        mDayPickerView.setMinDate(minDate);
+        mDayPickerView.setMaxDate(maxDate);
+        mDayPickerView.setDate(setDate, false, true);
+        mDayPickerView.setOnDaySelectedListener(mOnDaySelectedListener);
+
+        delegator.addView(mDayPickerView);
+    }
+
+    private long parseDateToMillis(String dateStr, String defaultDateStr) {
+        final Calendar tempCalendar = Calendar.getInstance();
+        if (TextUtils.isEmpty(dateStr) || !parseDate(dateStr, tempCalendar)) {
+            parseDate(defaultDateStr, tempCalendar);
+        }
+        return tempCalendar.getTimeInMillis();
+    }
+
+    @Override
+    public void setShownWeekCount(int count) {
+        // Deprecated.
+    }
+
+    @Override
+    public int getShownWeekCount() {
+        // Deprecated.
+        return 0;
+    }
+
+    @Override
+    public void setSelectedWeekBackgroundColor(int color) {
+        // TODO: Should use a ColorStateList. Deprecate?
+    }
+
+    @Override
+    public int getSelectedWeekBackgroundColor() {
+        return 0;
+    }
+
+    @Override
+    public void setFocusedMonthDateColor(int color) {
+        // TODO: Should use a ColorStateList. Deprecate?
+    }
+
+    @Override
+    public int getFocusedMonthDateColor() {
+        return 0;
+    }
+
+    @Override
+    public void setUnfocusedMonthDateColor(int color) {
+        // TODO: Should use a ColorStateList. Deprecate?
+    }
+
+    @Override
+    public int getUnfocusedMonthDateColor() {
+        return 0;
+    }
+
+    @Override
+    public void setWeekDayTextAppearance(int resourceId) {
+
+    }
+
+    @Override
+    public int getWeekDayTextAppearance() {
+        return 0;
+    }
+
+    @Override
+    public void setDateTextAppearance(int resourceId) {
+
+    }
+
+    @Override
+    public int getDateTextAppearance() {
+        return 0;
+    }
+
+    @Override
+    public void setWeekNumberColor(int color) {
+        // Deprecated.
+    }
+
+    @Override
+    public int getWeekNumberColor() {
+        // Deprecated.
+        return 0;
+    }
+
+    @Override
+    public void setWeekSeparatorLineColor(int color) {
+        // Deprecated.
+    }
+
+    @Override
+    public int getWeekSeparatorLineColor() {
+        // Deprecated.
+        return 0;
+    }
+
+    @Override
+    public void setSelectedDateVerticalBar(int resourceId) {
+        // Deprecated.
+    }
+
+    @Override
+    public void setSelectedDateVerticalBar(Drawable drawable) {
+        // Deprecated.
+    }
+
+    @Override
+    public Drawable getSelectedDateVerticalBar() {
+        // Deprecated.
+        return null;
+    }
+
+    @Override
+    public void setMinDate(long minDate) {
+        mDayPickerView.setMinDate(minDate);
+    }
+
+    @Override
+    public long getMinDate() {
+        return mDayPickerView.getMinDate();
+    }
+
+    @Override
+    public void setMaxDate(long maxDate) {
+        mDayPickerView.setMaxDate(maxDate);
+    }
+
+    @Override
+    public long getMaxDate() {
+        return mDayPickerView.getMaxDate();
+    }
+
+    @Override
+    public void setShowWeekNumber(boolean showWeekNumber) {
+        // Deprecated.
+    }
+
+    @Override
+    public boolean getShowWeekNumber() {
+        // Deprecated.
+        return false;
+    }
+
+    @Override
+    public void setFirstDayOfWeek(int firstDayOfWeek) {
+        mDayPickerView.setFirstDayOfWeek(firstDayOfWeek);
+    }
+
+    @Override
+    public int getFirstDayOfWeek() {
+        return mDayPickerView.getFirstDayOfWeek();
+    }
+
+    @Override
+    public void setDate(long date) {
+        mDayPickerView.setDate(date, true, false);
+    }
+
+    @Override
+    public void setDate(long date, boolean animate, boolean center) {
+        mDayPickerView.setDate(date, animate, center);
+    }
+
+    @Override
+    public long getDate() {
+        return mDayPickerView.getDate();
+    }
+
+    @Override
+    public void setOnDateChangeListener(CalendarView.OnDateChangeListener listener) {
+        mOnDateChangeListener = listener;
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        // Nothing to do here, configuration changes are already propagated
+        // by ViewGroup.
+    }
+
+    private final DayPickerView.OnDaySelectedListener mOnDaySelectedListener =
+            new DayPickerView.OnDaySelectedListener() {
+        @Override
+        public void onDaySelected(DayPickerView view, Calendar day) {
+            if (mOnDateChangeListener != null) {
+                final int year = day.get(Calendar.YEAR);
+                final int month = day.get(Calendar.MONTH);
+                final int dayOfMonth = day.get(Calendar.DAY_OF_MONTH);
+                mOnDateChangeListener.onSelectedDayChange(mDelegator, year, month, dayOfMonth);
+            }
+        }
+    };
+}
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index cf3dbab..820bf78 100644
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -185,8 +185,9 @@
 
         mDayPickerView = new DayPickerView(mContext);
         mDayPickerView.setFirstDayOfWeek(mFirstDayOfWeek);
-        mDayPickerView.setRange(mMinDate, mMaxDate);
-        mDayPickerView.setDay(mCurrentDate);
+        mDayPickerView.setMinDate(mMinDate.getTimeInMillis());
+        mDayPickerView.setMaxDate(mMaxDate.getTimeInMillis());
+        mDayPickerView.setDate(mCurrentDate.getTimeInMillis());
         mDayPickerView.setOnDaySelectedListener(mOnDaySelectedListener);
 
         mYearPickerView = new YearPickerView(mContext);
@@ -336,7 +337,7 @@
 
         switch (viewIndex) {
             case MONTH_AND_DAY_VIEW:
-                mDayPickerView.setDay(getSelectedDay());
+                mDayPickerView.setDate(getSelectedDay().getTimeInMillis());
                 if (mCurrentView != viewIndex) {
                     mMonthAndDayLayout.setSelected(true);
                     mHeaderYearTextView.setSelected(false);
@@ -414,7 +415,7 @@
             updateDisplay(false);
         }
         mMinDate.setTimeInMillis(minDate);
-        mDayPickerView.setRange(mMinDate, mMaxDate);
+        mDayPickerView.setMinDate(minDate);
         mYearPickerView.setRange(mMinDate, mMaxDate);
     }
 
@@ -436,7 +437,7 @@
             updateDisplay(false);
         }
         mMaxDate.setTimeInMillis(maxDate);
-        mDayPickerView.setRange(mMinDate, mMaxDate);
+        mDayPickerView.setMaxDate(maxDate);
         mYearPickerView.setRange(mMinDate, mMaxDate);
     }
 
@@ -616,7 +617,7 @@
             listener.onDateChanged();
         }
 
-        mDayPickerView.setDay(getSelectedDay());
+        mDayPickerView.setDate(getSelectedDay().getTimeInMillis());
     }
 
     @Override
diff --git a/core/java/android/widget/DayPickerView.java b/core/java/android/widget/DayPickerView.java
index 6cb1c9d..7db3fb9 100644
--- a/core/java/android/widget/DayPickerView.java
+++ b/core/java/android/widget/DayPickerView.java
@@ -58,6 +58,8 @@
     private Calendar mMinDate = Calendar.getInstance();
     private Calendar mMaxDate = Calendar.getInstance();
 
+    private Calendar mTempCalendar;
+
     private OnDaySelectedListener mOnDaySelectedListener;
 
     // which month should be displayed/highlighted [0-11]
@@ -77,28 +79,65 @@
         setDrawSelectorOnTop(false);
         setUpListView();
 
-        goTo(mSelectedDay, false, true, true);
+        goTo(mSelectedDay.getTimeInMillis(), false, false, true);
 
         mAdapter.setOnDaySelectedListener(mProxyOnDaySelectedListener);
     }
 
-    public void setDay(Calendar day) {
-        goTo(day, false, true, true);
+    /**
+     * Sets the currently selected date to the specified timestamp. Jumps
+     * immediately to the new date. To animate to the new date, use
+     * {@link #setDate(long, boolean, boolean)}.
+     *
+     * @param timeInMillis
+     */
+    public void setDate(long timeInMillis) {
+        setDate(timeInMillis, false, true);
+    }
+
+    public void setDate(long timeInMillis, boolean animate, boolean forceScroll) {
+        goTo(timeInMillis, animate, true, forceScroll);
+    }
+
+    public long getDate() {
+        return mSelectedDay.getTimeInMillis();
     }
 
     public void setFirstDayOfWeek(int firstDayOfWeek) {
         mAdapter.setFirstDayOfWeek(firstDayOfWeek);
     }
 
-    public void setRange(Calendar minDate, Calendar maxDate) {
-        mMinDate.setTimeInMillis(minDate.getTimeInMillis());
-        mMaxDate.setTimeInMillis(maxDate.getTimeInMillis());
+    public int getFirstDayOfWeek() {
+        return mAdapter.getFirstDayOfWeek();
+    }
 
+    public void setMinDate(long timeInMillis) {
+        mMinDate.setTimeInMillis(timeInMillis);
+        onRangeChanged();
+    }
+
+    public long getMinDate() {
+        return mMinDate.getTimeInMillis();
+    }
+
+    public void setMaxDate(long timeInMillis) {
+        mMaxDate.setTimeInMillis(timeInMillis);
+        onRangeChanged();
+    }
+
+    public long getMaxDate() {
+        return mMaxDate.getTimeInMillis();
+    }
+
+    /**
+     * Handles changes to date range.
+     */
+    public void onRangeChanged() {
         mAdapter.setRange(mMinDate, mMaxDate);
 
         // Changing the min/max date changes the selection position since we
-        // don't really have stable IDs.
-        goTo(mSelectedDay, false, true, true);
+        // don't really have stable IDs. Jumps immediately to the new position.
+        goTo(mSelectedDay.getTimeInMillis(), false, false, true);
     }
 
     /**
@@ -136,12 +175,20 @@
         return diffMonths;
     }
 
-    private int getPositionFromDay(Calendar day) {
+    private int getPositionFromDay(long timeInMillis) {
         final int diffMonthMax = getDiffMonths(mMinDate, mMaxDate);
-        final int diffMonth = getDiffMonths(mMinDate, day);
+        final int diffMonth = getDiffMonths(mMinDate, getTempCalendarForTime(timeInMillis));
         return MathUtils.constrain(diffMonth, 0, diffMonthMax);
     }
 
+    private Calendar getTempCalendarForTime(long timeInMillis) {
+        if (mTempCalendar == null) {
+            mTempCalendar = Calendar.getInstance();
+        }
+        mTempCalendar.setTimeInMillis(timeInMillis);
+        return mTempCalendar;
+    }
+
     /**
      * This moves to the specified time in the view. If the time is not already
      * in range it will move the list so that the first of the month containing
@@ -157,14 +204,14 @@
      *            visible
      * @return Whether or not the view animated to the new location
      */
-    private boolean goTo(Calendar day, boolean animate, boolean setSelected, boolean forceScroll) {
+    private boolean goTo(long day, boolean animate, boolean setSelected, boolean forceScroll) {
 
         // Set the selected day
         if (setSelected) {
-            mSelectedDay.setTimeInMillis(day.getTimeInMillis());
+            mSelectedDay.setTimeInMillis(day);
         }
 
-        mTempDay.setTimeInMillis(day.getTimeInMillis());
+        mTempDay.setTimeInMillis(day);
         final int position = getPositionFromDay(day);
 
         View child;
@@ -258,6 +305,10 @@
         mAdapter.setCalendarTextColor(colors);
     }
 
+    void setCalendarTextAppearance(int resId) {
+        mAdapter.setCalendarTextAppearance(resId);
+    }
+
     protected class ScrollStateRunnable implements Runnable {
         private int mNewState;
         private View mParent;
@@ -415,7 +466,7 @@
     }
 
     private String getMonthAndYearString(Calendar day) {
-        StringBuffer sbuf = new StringBuffer();
+        final StringBuilder sbuf = new StringBuilder();
         sbuf.append(day.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault()));
         sbuf.append(" ");
         sbuf.append(mYearFormat.format(day.getTime()));
@@ -429,8 +480,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);
     }
 
     /**
@@ -474,7 +525,7 @@
 
         // Go to that month.
         announceForAccessibility(getMonthAndYearString(day));
-        goTo(day, true, false, true);
+        goTo(day.getTimeInMillis(), true, false, true);
         mPerformingScroll = true;
         return true;
     }
diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java
index 24fc2bb..8b01dde 100644
--- a/core/java/android/widget/RadialTimePickerView.java
+++ b/core/java/android/widget/RadialTimePickerView.java
@@ -452,7 +452,10 @@
     }
 
     public void initialize(int hour, int minute, boolean is24HourMode) {
-        mIs24HourMode = is24HourMode;
+        if (mIs24HourMode != is24HourMode) {
+            mIs24HourMode = is24HourMode;
+            initData();
+        }
 
         setCurrentHourInternal(hour, false, false);
         setCurrentMinuteInternal(minute, false);
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index dfdf606..4ee6418 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -45,7 +45,6 @@
 import android.text.style.ImageSpan;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.util.TypedValue;
 import android.view.CollapsibleActionView;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
@@ -99,17 +98,21 @@
      */
     private static final String IME_OPTION_NO_MICROPHONE = "nm";
 
-    private final SearchAutoComplete mQueryTextView;
+    private final SearchAutoComplete mSearchSrcTextView;
     private final View mSearchEditFrame;
     private final View mSearchPlate;
     private final View mSubmitArea;
     private final ImageView mSearchButton;
-    private final ImageView mSubmitButton;
+    private final ImageView mGoButton;
     private final ImageView mCloseButton;
     private final ImageView mVoiceButton;
-    private final ImageView mSearchHintIcon;
     private final View mDropDownAnchor;
-    private final int mSearchIconResId;
+
+    /** Icon optionally displayed when the SearchView is collapsed. */
+    private final ImageView mCollapsedIcon;
+
+    /** Drawable used as an EditText hint. */
+    private final Drawable mSearchHintIcon;
 
     // Resources used by SuggestionsAdapter to display suggestions.
     private final int mSuggestionRowLayout;
@@ -262,30 +265,38 @@
                 attrs, R.styleable.SearchView, defStyleAttr, defStyleRes);
         final LayoutInflater inflater = (LayoutInflater) context.getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
-        final int layoutResId = a.getResourceId(R.styleable.SearchView_layout, R.layout.search_view);
+        final int layoutResId = a.getResourceId(
+                R.styleable.SearchView_layout, R.layout.search_view);
         inflater.inflate(layoutResId, this, true);
 
-        mQueryTextView = (SearchAutoComplete) findViewById(R.id.search_src_text);
-        mQueryTextView.setSearchView(this);
+        mSearchSrcTextView = (SearchAutoComplete) findViewById(R.id.search_src_text);
+        mSearchSrcTextView.setSearchView(this);
 
         mSearchEditFrame = findViewById(R.id.search_edit_frame);
         mSearchPlate = findViewById(R.id.search_plate);
         mSubmitArea = findViewById(R.id.submit_area);
         mSearchButton = (ImageView) findViewById(R.id.search_button);
-        mSubmitButton = (ImageView) findViewById(R.id.search_go_btn);
+        mGoButton = (ImageView) findViewById(R.id.search_go_btn);
         mCloseButton = (ImageView) findViewById(R.id.search_close_btn);
         mVoiceButton = (ImageView) findViewById(R.id.search_voice_btn);
-        mSearchHintIcon = (ImageView) findViewById(R.id.search_mag_icon);
+        mCollapsedIcon = (ImageView) findViewById(R.id.search_mag_icon);
 
         // Set up icons and backgrounds.
         mSearchPlate.setBackground(a.getDrawable(R.styleable.SearchView_queryBackground));
         mSubmitArea.setBackground(a.getDrawable(R.styleable.SearchView_submitBackground));
-        mSearchIconResId = a.getResourceId(R.styleable.SearchView_searchIcon, 0);
-        mSearchButton.setImageResource(mSearchIconResId);
-        mSubmitButton.setImageDrawable(a.getDrawable(R.styleable.SearchView_goIcon));
+        mSearchButton.setImageDrawable(a.getDrawable(R.styleable.SearchView_searchIcon));
+        mGoButton.setImageDrawable(a.getDrawable(R.styleable.SearchView_goIcon));
         mCloseButton.setImageDrawable(a.getDrawable(R.styleable.SearchView_closeIcon));
         mVoiceButton.setImageDrawable(a.getDrawable(R.styleable.SearchView_voiceIcon));
-        mSearchHintIcon.setImageDrawable(a.getDrawable(R.styleable.SearchView_searchIcon));
+        mCollapsedIcon.setImageDrawable(a.getDrawable(R.styleable.SearchView_searchIcon));
+
+        // Prior to L MR1, the search hint icon defaulted to searchIcon. If the
+        // style does not have an explicit value set, fall back to that.
+        if (a.hasValueOrEmpty(R.styleable.SearchView_searchHintIcon)) {
+            mSearchHintIcon = a.getDrawable(R.styleable.SearchView_searchHintIcon);
+        } else {
+            mSearchHintIcon = a.getDrawable(R.styleable.SearchView_searchIcon);
+        }
 
         // Extract dropdown layout resource IDs for later use.
         mSuggestionRowLayout = a.getResourceId(R.styleable.SearchView_suggestionRowLayout,
@@ -294,18 +305,18 @@
 
         mSearchButton.setOnClickListener(mOnClickListener);
         mCloseButton.setOnClickListener(mOnClickListener);
-        mSubmitButton.setOnClickListener(mOnClickListener);
+        mGoButton.setOnClickListener(mOnClickListener);
         mVoiceButton.setOnClickListener(mOnClickListener);
-        mQueryTextView.setOnClickListener(mOnClickListener);
+        mSearchSrcTextView.setOnClickListener(mOnClickListener);
 
-        mQueryTextView.addTextChangedListener(mTextWatcher);
-        mQueryTextView.setOnEditorActionListener(mOnEditorActionListener);
-        mQueryTextView.setOnItemClickListener(mOnItemClickListener);
-        mQueryTextView.setOnItemSelectedListener(mOnItemSelectedListener);
-        mQueryTextView.setOnKeyListener(mTextKeyListener);
+        mSearchSrcTextView.addTextChangedListener(mTextWatcher);
+        mSearchSrcTextView.setOnEditorActionListener(mOnEditorActionListener);
+        mSearchSrcTextView.setOnItemClickListener(mOnItemClickListener);
+        mSearchSrcTextView.setOnItemSelectedListener(mOnItemSelectedListener);
+        mSearchSrcTextView.setOnKeyListener(mTextKeyListener);
 
         // Inform any listener of focus changes
-        mQueryTextView.setOnFocusChangeListener(new OnFocusChangeListener() {
+        mSearchSrcTextView.setOnFocusChangeListener(new OnFocusChangeListener() {
 
             public void onFocusChange(View v, boolean hasFocus) {
                 if (mOnQueryTextFocusChangeListener != null) {
@@ -350,7 +361,7 @@
         mVoiceAppSearchIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
         mVoiceAppSearchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 
-        mDropDownAnchor = findViewById(mQueryTextView.getDropDownAnchor());
+        mDropDownAnchor = findViewById(mSearchSrcTextView.getDropDownAnchor());
         if (mDropDownAnchor != null) {
             mDropDownAnchor.addOnLayoutChangeListener(new OnLayoutChangeListener() {
                 @Override
@@ -393,7 +404,7 @@
         if (mVoiceButtonEnabled) {
             // Disable the microphone on the keyboard, as a mic is displayed near the text box
             // TODO: use imeOptions to disable voice input when the new API will be available
-            mQueryTextView.setPrivateImeOptions(IME_OPTION_NO_MICROPHONE);
+            mSearchSrcTextView.setPrivateImeOptions(IME_OPTION_NO_MICROPHONE);
         }
         updateViewsVisibility(isIconified());
     }
@@ -416,7 +427,7 @@
      * @attr ref android.R.styleable#SearchView_imeOptions
      */
     public void setImeOptions(int imeOptions) {
-        mQueryTextView.setImeOptions(imeOptions);
+        mSearchSrcTextView.setImeOptions(imeOptions);
     }
 
     /**
@@ -427,7 +438,7 @@
      * @attr ref android.R.styleable#SearchView_imeOptions
      */
     public int getImeOptions() {
-        return mQueryTextView.getImeOptions();
+        return mSearchSrcTextView.getImeOptions();
     }
 
     /**
@@ -439,7 +450,7 @@
      * @attr ref android.R.styleable#SearchView_inputType
      */
     public void setInputType(int inputType) {
-        mQueryTextView.setInputType(inputType);
+        mSearchSrcTextView.setInputType(inputType);
     }
 
     /**
@@ -449,7 +460,7 @@
      * @attr ref android.R.styleable#SearchView_inputType
      */
     public int getInputType() {
-        return mQueryTextView.getInputType();
+        return mSearchSrcTextView.getInputType();
     }
 
     /** @hide */
@@ -461,7 +472,7 @@
         if (!isFocusable()) return false;
         // If it is not iconified, then give the focus to the text field
         if (!isIconified()) {
-            boolean result = mQueryTextView.requestFocus(direction, previouslyFocusedRect);
+            boolean result = mSearchSrcTextView.requestFocus(direction, previouslyFocusedRect);
             if (result) {
                 updateViewsVisibility(false);
             }
@@ -477,7 +488,7 @@
         mClearingFocus = true;
         setImeVisibility(false);
         super.clearFocus();
-        mQueryTextView.clearFocus();
+        mSearchSrcTextView.clearFocus();
         mClearingFocus = false;
     }
 
@@ -536,7 +547,7 @@
      * @return the query string
      */
     public CharSequence getQuery() {
-        return mQueryTextView.getText();
+        return mSearchSrcTextView.getText();
     }
 
     /**
@@ -548,9 +559,9 @@
      * text field.
      */
     public void setQuery(CharSequence query, boolean submit) {
-        mQueryTextView.setText(query);
+        mSearchSrcTextView.setText(query);
         if (query != null) {
-            mQueryTextView.setSelection(mQueryTextView.length());
+            mSearchSrcTextView.setSelection(mSearchSrcTextView.length());
             mUserQuery = query;
         }
 
@@ -711,7 +722,7 @@
     public void setSuggestionsAdapter(CursorAdapter adapter) {
         mSuggestionsAdapter = adapter;
 
-        mQueryTextView.setAdapter(mSuggestionsAdapter);
+        mSearchSrcTextView.setAdapter(mSuggestionsAdapter);
     }
 
     /**
@@ -789,12 +800,12 @@
         // Visibility of views that are visible when collapsed
         final int visCollapsed = collapsed ? VISIBLE : GONE;
         // Is there text in the query
-        final boolean hasText = !TextUtils.isEmpty(mQueryTextView.getText());
+        final boolean hasText = !TextUtils.isEmpty(mSearchSrcTextView.getText());
 
         mSearchButton.setVisibility(visCollapsed);
         updateSubmitButton(hasText);
         mSearchEditFrame.setVisibility(collapsed ? GONE : VISIBLE);
-        mSearchHintIcon.setVisibility(mIconifiedByDefault ? GONE : VISIBLE);
+        mCollapsedIcon.setVisibility(mIconifiedByDefault ? GONE : VISIBLE);
         updateCloseButton();
         updateVoiceButton(!hasText);
         updateSubmitArea();
@@ -827,13 +838,13 @@
                 && (hasText || !mVoiceButtonEnabled)) {
             visibility = VISIBLE;
         }
-        mSubmitButton.setVisibility(visibility);
+        mGoButton.setVisibility(visibility);
     }
 
     private void updateSubmitArea() {
         int visibility = GONE;
         if (isSubmitAreaEnabled()
-                && (mSubmitButton.getVisibility() == VISIBLE
+                && (mGoButton.getVisibility() == VISIBLE
                         || mVoiceButton.getVisibility() == VISIBLE)) {
             visibility = VISIBLE;
         }
@@ -841,12 +852,15 @@
     }
 
     private void updateCloseButton() {
-        final boolean hasText = !TextUtils.isEmpty(mQueryTextView.getText());
+        final boolean hasText = !TextUtils.isEmpty(mSearchSrcTextView.getText());
         // Should we show the close button? It is not shown if there's no focus,
         // field is not iconified by default and there is no text in it.
         final boolean showClose = hasText || (mIconifiedByDefault && !mExpandedInActionView);
         mCloseButton.setVisibility(showClose ? VISIBLE : GONE);
-        mCloseButton.getDrawable().setState(hasText ? ENABLED_STATE_SET : EMPTY_STATE_SET);
+        final Drawable closeButtonImg = mCloseButton.getDrawable();
+        if (closeButtonImg != null){
+            closeButtonImg.setState(hasText ? ENABLED_STATE_SET : EMPTY_STATE_SET);
+        }
     }
 
     private void postUpdateFocusedState() {
@@ -854,9 +868,16 @@
     }
 
     private void updateFocusedState() {
-        boolean focused = mQueryTextView.hasFocus();
-        mSearchPlate.getBackground().setState(focused ? FOCUSED_STATE_SET : EMPTY_STATE_SET);
-        mSubmitArea.getBackground().setState(focused ? FOCUSED_STATE_SET : EMPTY_STATE_SET);
+        final boolean focused = mSearchSrcTextView.hasFocus();
+        final int[] stateSet = focused ? FOCUSED_STATE_SET : EMPTY_STATE_SET;
+        final Drawable searchPlateBg = mSearchPlate.getBackground();
+        if (searchPlateBg != null) {
+            searchPlateBg.setState(stateSet);
+        }
+        final Drawable submitAreaBg = mSubmitArea.getBackground();
+        if (submitAreaBg != null) {
+            submitAreaBg.setState(stateSet);
+        }
         invalidate();
     }
 
@@ -896,11 +917,11 @@
                 onSearchClicked();
             } else if (v == mCloseButton) {
                 onCloseClicked();
-            } else if (v == mSubmitButton) {
+            } else if (v == mGoButton) {
                 onSubmitQuery();
             } else if (v == mVoiceButton) {
                 onVoiceClicked();
-            } else if (v == mQueryTextView) {
+            } else if (v == mSearchSrcTextView) {
                 forceSuggestionQuery();
             }
         }
@@ -925,7 +946,7 @@
         // entered query with the action key
         SearchableInfo.ActionKeyInfo actionKey = mSearchable.findActionKey(keyCode);
         if ((actionKey != null) && (actionKey.getQueryActionMsg() != null)) {
-            launchQuerySearch(keyCode, actionKey.getQueryActionMsg(), mQueryTextView.getText()
+            launchQuerySearch(keyCode, actionKey.getQueryActionMsg(), mSearchSrcTextView.getText()
                     .toString());
             return true;
         }
@@ -947,25 +968,25 @@
 
             if (DBG) {
                 Log.d(LOG_TAG, "mTextListener.onKey(" + keyCode + "," + event + "), selection: "
-                        + mQueryTextView.getListSelection());
+                        + mSearchSrcTextView.getListSelection());
             }
 
             // If a suggestion is selected, handle enter, search key, and action keys
             // as presses on the selected suggestion
-            if (mQueryTextView.isPopupShowing()
-                    && mQueryTextView.getListSelection() != ListView.INVALID_POSITION) {
+            if (mSearchSrcTextView.isPopupShowing()
+                    && mSearchSrcTextView.getListSelection() != ListView.INVALID_POSITION) {
                 return onSuggestionsKey(v, keyCode, event);
             }
 
             // If there is text in the query box, handle enter, and action keys
             // The search key is handled by the dialog's onKeyDown().
-            if (!mQueryTextView.isEmpty() && event.hasNoModifiers()) {
+            if (!mSearchSrcTextView.isEmpty() && event.hasNoModifiers()) {
                 if (event.getAction() == KeyEvent.ACTION_UP) {
                     if (keyCode == KeyEvent.KEYCODE_ENTER) {
                         v.cancelLongPress();
 
                         // Launch as a regular search.
-                        launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null, mQueryTextView.getText()
+                        launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null, mSearchSrcTextView.getText()
                                 .toString());
                         return true;
                     }
@@ -973,7 +994,7 @@
                 if (event.getAction() == KeyEvent.ACTION_DOWN) {
                     SearchableInfo.ActionKeyInfo actionKey = mSearchable.findActionKey(keyCode);
                     if ((actionKey != null) && (actionKey.getQueryActionMsg() != null)) {
-                        launchQuerySearch(keyCode, actionKey.getQueryActionMsg(), mQueryTextView
+                        launchQuerySearch(keyCode, actionKey.getQueryActionMsg(), mSearchSrcTextView
                                 .getText().toString());
                         return true;
                     }
@@ -1001,7 +1022,7 @@
             // "click")
             if (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_SEARCH
                     || keyCode == KeyEvent.KEYCODE_TAB) {
-                int position = mQueryTextView.getListSelection();
+                int position = mSearchSrcTextView.getListSelection();
                 return onItemClicked(position, KeyEvent.KEYCODE_UNKNOWN, null);
             }
 
@@ -1012,18 +1033,18 @@
                 // left key, at end if right key
                 // TODO: Reverse left/right for right-to-left languages, e.g.
                 // Arabic
-                int selPoint = (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) ? 0 : mQueryTextView
+                int selPoint = (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) ? 0 : mSearchSrcTextView
                         .length();
-                mQueryTextView.setSelection(selPoint);
-                mQueryTextView.setListSelection(0);
-                mQueryTextView.clearListSelection();
-                mQueryTextView.ensureImeVisible(true);
+                mSearchSrcTextView.setSelection(selPoint);
+                mSearchSrcTextView.setListSelection(0);
+                mSearchSrcTextView.clearListSelection();
+                mSearchSrcTextView.ensureImeVisible(true);
 
                 return true;
             }
 
             // Next, check for an "up and out" move
-            if (keyCode == KeyEvent.KEYCODE_DPAD_UP && 0 == mQueryTextView.getListSelection()) {
+            if (keyCode == KeyEvent.KEYCODE_DPAD_UP && 0 == mSearchSrcTextView.getListSelection()) {
                 // TODO: restoreUserQuery();
                 // let ACTV complete the move
                 return false;
@@ -1035,7 +1056,7 @@
                     && ((actionKey.getSuggestActionMsg() != null) || (actionKey
                             .getSuggestActionMsgColumn() != null))) {
                 // launch suggestion using action key column
-                int position = mQueryTextView.getListSelection();
+                int position = mSearchSrcTextView.getListSelection();
                 if (position != ListView.INVALID_POSITION) {
                     Cursor c = mSuggestionsAdapter.getCursor();
                     if (c.moveToPosition(position)) {
@@ -1078,24 +1099,24 @@
     }
 
     private CharSequence getDecoratedHint(CharSequence hintText) {
-        // If the field is always expanded, then don't add the search icon to the hint
-        if (!mIconifiedByDefault) {
+        // If the field is always expanded or we don't have a search hint icon,
+        // then don't add the search icon to the hint.
+        if (!mIconifiedByDefault || mSearchHintIcon == null) {
             return hintText;
         }
 
-        final Drawable searchIcon = getContext().getDrawable(mSearchIconResId);
-        final int textSize = (int) (mQueryTextView.getTextSize() * 1.25);
-        searchIcon.setBounds(0, 0, textSize, textSize);
+        final int textSize = (int) (mSearchSrcTextView.getTextSize() * 1.25);
+        mSearchHintIcon.setBounds(0, 0, textSize, textSize);
 
-        final SpannableStringBuilder ssb = new SpannableStringBuilder("   "); // for the icon
+        final SpannableStringBuilder ssb = new SpannableStringBuilder("   ");
+        ssb.setSpan(new ImageSpan(mSearchHintIcon), 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
         ssb.append(hintText);
-        ssb.setSpan(new ImageSpan(searchIcon), 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
         return ssb;
     }
 
     private void updateQueryHint() {
         if (mQueryHint != null) {
-            mQueryTextView.setHint(getDecoratedHint(mQueryHint));
+            mSearchSrcTextView.setHint(getDecoratedHint(mQueryHint));
         } else if (mSearchable != null) {
             CharSequence hint = null;
             int hintId = mSearchable.getHintId();
@@ -1103,10 +1124,10 @@
                 hint = getContext().getString(hintId);
             }
             if (hint != null) {
-                mQueryTextView.setHint(getDecoratedHint(hint));
+                mSearchSrcTextView.setHint(getDecoratedHint(hint));
             }
         } else {
-            mQueryTextView.setHint(getDecoratedHint(""));
+            mSearchSrcTextView.setHint(getDecoratedHint(""));
         }
     }
 
@@ -1114,9 +1135,9 @@
      * Updates the auto-complete text view.
      */
     private void updateSearchAutoComplete() {
-        mQueryTextView.setDropDownAnimationStyle(0); // no animation
-        mQueryTextView.setThreshold(mSearchable.getSuggestThreshold());
-        mQueryTextView.setImeOptions(mSearchable.getImeOptions());
+        mSearchSrcTextView.setDropDownAnimationStyle(0); // no animation
+        mSearchSrcTextView.setThreshold(mSearchable.getSuggestThreshold());
+        mSearchSrcTextView.setImeOptions(mSearchable.getImeOptions());
         int inputType = mSearchable.getInputType();
         // We only touch this if the input type is set up for text (which it almost certainly
         // should be, in the case of search!)
@@ -1135,7 +1156,7 @@
                 inputType |= InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
             }
         }
-        mQueryTextView.setInputType(inputType);
+        mSearchSrcTextView.setInputType(inputType);
         if (mSuggestionsAdapter != null) {
             mSuggestionsAdapter.changeCursor(null);
         }
@@ -1144,7 +1165,7 @@
         if (mSearchable.getSuggestAuthority() != null) {
             mSuggestionsAdapter = new SuggestionsAdapter(getContext(),
                     this, mSearchable, mOutsideDrawablesCache);
-            mQueryTextView.setAdapter(mSuggestionsAdapter);
+            mSearchSrcTextView.setAdapter(mSuggestionsAdapter);
             ((SuggestionsAdapter) mSuggestionsAdapter).setQueryRefinement(
                     mQueryRefinement ? SuggestionsAdapter.REFINE_ALL
                     : SuggestionsAdapter.REFINE_BY_ENTRY);
@@ -1161,7 +1182,7 @@
         int visibility = GONE;
         if (mVoiceButtonEnabled && !isIconified() && empty) {
             visibility = VISIBLE;
-            mSubmitButton.setVisibility(GONE);
+            mGoButton.setVisibility(GONE);
         }
         mVoiceButton.setVisibility(visibility);
     }
@@ -1178,7 +1199,7 @@
     };
 
     private void onTextChanged(CharSequence newText) {
-        CharSequence text = mQueryTextView.getText();
+        CharSequence text = mSearchSrcTextView.getText();
         mUserQuery = text;
         boolean hasText = !TextUtils.isEmpty(text);
         updateSubmitButton(hasText);
@@ -1192,7 +1213,7 @@
     }
 
     private void onSubmitQuery() {
-        CharSequence query = mQueryTextView.getText();
+        CharSequence query = mSearchSrcTextView.getText();
         if (query != null && TextUtils.getTrimmedLength(query) > 0) {
             if (mOnQueryChangeListener == null
                     || !mOnQueryChangeListener.onQueryTextSubmit(query.toString())) {
@@ -1206,11 +1227,11 @@
     }
 
     private void dismissSuggestions() {
-        mQueryTextView.dismissDropDown();
+        mSearchSrcTextView.dismissDropDown();
     }
 
     private void onCloseClicked() {
-        CharSequence text = mQueryTextView.getText();
+        CharSequence text = mSearchSrcTextView.getText();
         if (TextUtils.isEmpty(text)) {
             if (mIconifiedByDefault) {
                 // If the app doesn't override the close behavior
@@ -1222,8 +1243,8 @@
                 }
             }
         } else {
-            mQueryTextView.setText("");
-            mQueryTextView.requestFocus();
+            mSearchSrcTextView.setText("");
+            mSearchSrcTextView.requestFocus();
             setImeVisibility(true);
         }
 
@@ -1231,7 +1252,7 @@
 
     private void onSearchClicked() {
         updateViewsVisibility(false);
-        mQueryTextView.requestFocus();
+        mSearchSrcTextView.requestFocus();
         setImeVisibility(true);
         if (mOnSearchClickListener != null) {
             mOnSearchClickListener.onClick(this);
@@ -1266,7 +1287,7 @@
         // Delayed update to make sure that the focus has settled down and window focus changes
         // don't affect it. A synchronous update was not working.
         postUpdateFocusedState();
-        if (mQueryTextView.hasFocus()) {
+        if (mSearchSrcTextView.hasFocus()) {
             forceSuggestionQuery();
         }
     }
@@ -1286,7 +1307,7 @@
         setQuery("", false);
         clearFocus();
         updateViewsVisibility(true);
-        mQueryTextView.setImeOptions(mCollapsedImeOptions);
+        mSearchSrcTextView.setImeOptions(mCollapsedImeOptions);
         mExpandedInActionView = false;
     }
 
@@ -1298,9 +1319,9 @@
         if (mExpandedInActionView) return;
 
         mExpandedInActionView = true;
-        mCollapsedImeOptions = mQueryTextView.getImeOptions();
-        mQueryTextView.setImeOptions(mCollapsedImeOptions | EditorInfo.IME_FLAG_NO_FULLSCREEN);
-        mQueryTextView.setText("");
+        mCollapsedImeOptions = mSearchSrcTextView.getImeOptions();
+        mSearchSrcTextView.setImeOptions(mCollapsedImeOptions | EditorInfo.IME_FLAG_NO_FULLSCREEN);
+        mSearchSrcTextView.setText("");
         setIconified(false);
     }
 
@@ -1326,17 +1347,17 @@
                     ? res.getDimensionPixelSize(R.dimen.dropdownitem_icon_width)
                     + res.getDimensionPixelSize(R.dimen.dropdownitem_text_padding_left)
                     : 0;
-            mQueryTextView.getDropDownBackground().getPadding(dropDownPadding);
+            mSearchSrcTextView.getDropDownBackground().getPadding(dropDownPadding);
             int offset;
             if (isLayoutRtl) {
                 offset = - dropDownPadding.left;
             } else {
                 offset = anchorPadding - (dropDownPadding.left + iconOffset);
             }
-            mQueryTextView.setDropDownHorizontalOffset(offset);
+            mSearchSrcTextView.setDropDownHorizontalOffset(offset);
             final int width = mDropDownAnchor.getWidth() + dropDownPadding.left
                     + dropDownPadding.right + iconOffset - anchorPadding;
-            mQueryTextView.setDropDownWidth(width);
+            mSearchSrcTextView.setDropDownWidth(width);
         }
     }
 
@@ -1394,7 +1415,7 @@
      * Query rewriting.
      */
     private void rewriteQueryFromSuggestion(int position) {
-        CharSequence oldQuery = mQueryTextView.getText();
+        CharSequence oldQuery = mSearchSrcTextView.getText();
         Cursor c = mSuggestionsAdapter.getCursor();
         if (c == null) {
             return;
@@ -1460,9 +1481,9 @@
      * Sets the text in the query box, without updating the suggestions.
      */
     private void setQuery(CharSequence query) {
-        mQueryTextView.setText(query, true);
+        mSearchSrcTextView.setText(query, true);
         // Move the cursor to the end
-        mQueryTextView.setSelection(TextUtils.isEmpty(query) ? 0 : query.length());
+        mSearchSrcTextView.setSelection(TextUtils.isEmpty(query) ? 0 : query.length());
     }
 
     private void launchQuerySearch(int actionKey, String actionMsg, String query) {
@@ -1648,8 +1669,8 @@
     }
 
     private void forceSuggestionQuery() {
-        mQueryTextView.doBeforeTextChanged();
-        mQueryTextView.doAfterTextChanged();
+        mSearchSrcTextView.doBeforeTextChanged();
+        mSearchSrcTextView.doAfterTextChanged();
     }
 
     static boolean isLandscapeMode(Context context) {
diff --git a/core/java/android/widget/SimpleMonthAdapter.java b/core/java/android/widget/SimpleMonthAdapter.java
index ecd2912..24ebb2c 100644
--- a/core/java/android/widget/SimpleMonthAdapter.java
+++ b/core/java/android/widget/SimpleMonthAdapter.java
@@ -16,8 +16,12 @@
 
 package android.widget;
 
+import com.android.internal.R;
+
 import android.content.Context;
 import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
+import android.graphics.Color;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.SimpleMonthView.OnDayClickListener;
@@ -33,15 +37,14 @@
 
     private final Context mContext;
 
-    private Calendar mSelectedDay;
-    private ColorStateList mCalendarTextColors;
+    private Calendar mSelectedDay = Calendar.getInstance();
+    private ColorStateList mCalendarTextColors = ColorStateList.valueOf(Color.BLACK);
     private OnDaySelectedListener mOnDaySelectedListener;
 
     private int mFirstDayOfWeek;
 
     public SimpleMonthAdapter(Context context) {
         mContext = context;
-        mSelectedDay = Calendar.getInstance();
     }
 
     public void setRange(Calendar min, Calendar max) {
@@ -57,6 +60,10 @@
         notifyDataSetInvalidated();
     }
 
+    public int getFirstDayOfWeek() {
+        return mFirstDayOfWeek;
+    }
+
     /**
      * Updates the selected day and related parameters.
      *
@@ -81,6 +88,24 @@
         mCalendarTextColors = colors;
     }
 
+    /**
+     * Sets the text color, size, style, hint color, and highlight color from
+     * the specified TextAppearance resource. This is mostly copied from
+     * {@link TextView#setTextAppearance(Context, int)}.
+     */
+    void setCalendarTextAppearance(int resId) {
+        final TypedArray a = mContext.obtainStyledAttributes(resId, R.styleable.TextAppearance);
+
+        final ColorStateList textColor = a.getColorStateList(R.styleable.TextAppearance_textColor);
+        if (textColor != null) {
+            mCalendarTextColors = textColor;
+        }
+
+        // TODO: Support font size, etc.
+
+        a.recycle();
+    }
+
     @Override
     public int getCount() {
         final int diffYear = mMaxDate.get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR);
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index c5f1d88..1fbd4a1 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -787,6 +787,12 @@
         addOption("-Ximage-compiler-option");
         addOption("--image-classes=/system/etc/preloaded-classes");
 
+        // If there is a compiled-classes file, push it.
+        if (hasFile("/system/etc/compiled-classes")) {
+            addOption("-Ximage-compiler-option");
+            addOption("--compiled-classes=/system/etc/compiled-classes");
+        }
+
         property_get("dalvik.vm.image-dex2oat-flags", dex2oatImageFlagsBuf, "");
         parseExtraOpts(dex2oatImageFlagsBuf, "-Ximage-compiler-option");
 
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 4b4b367..cabe200 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -484,7 +484,8 @@
 
 static jint convertAudioPortConfigToNative(JNIEnv *env,
                                                struct audio_port_config *nAudioPortConfig,
-                                               const jobject jAudioPortConfig)
+                                               const jobject jAudioPortConfig,
+                                               bool useConfigMask)
 {
     jobject jAudioPort = env->GetObjectField(jAudioPortConfig, gAudioPortConfigFields.mPort);
     jobject jHandle = env->GetObjectField(jAudioPort, gAudioPortFields.mHandle);
@@ -503,8 +504,13 @@
     ALOGV("convertAudioPortConfigToNative handle %d role %d type %d",
           nAudioPortConfig->id, nAudioPortConfig->role, nAudioPortConfig->type);
 
+    unsigned int configMask = 0;
+
     nAudioPortConfig->sample_rate = env->GetIntField(jAudioPortConfig,
                                                      gAudioPortConfigFields.mSamplingRate);
+    if (nAudioPortConfig->sample_rate != 0) {
+        configMask |= AUDIO_PORT_CONFIG_SAMPLE_RATE;
+    }
 
     bool useInMask = useInChannelMask(nAudioPortConfig->type, nAudioPortConfig->role);
     audio_channel_mask_t nMask;
@@ -518,22 +524,34 @@
         ALOGV("convertAudioPortConfigToNative OUT mask java %x native %x", jMask, nMask);
     }
     nAudioPortConfig->channel_mask = nMask;
+    if (nAudioPortConfig->channel_mask != AUDIO_CHANNEL_NONE) {
+        configMask |= AUDIO_PORT_CONFIG_CHANNEL_MASK;
+    }
 
     jint jFormat = env->GetIntField(jAudioPortConfig, gAudioPortConfigFields.mFormat);
     audio_format_t nFormat = audioFormatToNative(jFormat);
     ALOGV("convertAudioPortConfigToNative format %d native %d", jFormat, nFormat);
     nAudioPortConfig->format = nFormat;
+    if (nAudioPortConfig->format != AUDIO_FORMAT_DEFAULT &&
+            nAudioPortConfig->format != AUDIO_FORMAT_INVALID) {
+        configMask |= AUDIO_PORT_CONFIG_FORMAT;
+    }
+
     jobject jGain = env->GetObjectField(jAudioPortConfig, gAudioPortConfigFields.mGain);
     if (jGain != NULL) {
         convertAudioGainConfigToNative(env, &nAudioPortConfig->gain, jGain, useInMask);
         env->DeleteLocalRef(jGain);
+        configMask |= AUDIO_PORT_CONFIG_GAIN;
     } else {
         ALOGV("convertAudioPortConfigToNative no gain");
         nAudioPortConfig->gain.index = -1;
     }
-    nAudioPortConfig->config_mask = env->GetIntField(jAudioPortConfig,
-                                                     gAudioPortConfigFields.mConfigMask);
-
+    if (useConfigMask) {
+        nAudioPortConfig->config_mask = env->GetIntField(jAudioPortConfig,
+                                                         gAudioPortConfigFields.mConfigMask);
+    } else {
+        nAudioPortConfig->config_mask = configMask;
+    }
     env->DeleteLocalRef(jAudioPort);
     env->DeleteLocalRef(jHandle);
     return (jint)AUDIO_JAVA_SUCCESS;
@@ -998,7 +1016,7 @@
             jStatus = (jint)AUDIO_JAVA_BAD_VALUE;
             goto exit;
         }
-        jStatus = convertAudioPortConfigToNative(env, &nPatch.sources[i], jSource);
+        jStatus = convertAudioPortConfigToNative(env, &nPatch.sources[i], jSource, false);
         env->DeleteLocalRef(jSource);
         jSource = NULL;
         if (jStatus != AUDIO_JAVA_SUCCESS) {
@@ -1013,7 +1031,7 @@
             jStatus = (jint)AUDIO_JAVA_BAD_VALUE;
             goto exit;
         }
-        jStatus = convertAudioPortConfigToNative(env, &nPatch.sinks[i], jSink);
+        jStatus = convertAudioPortConfigToNative(env, &nPatch.sinks[i], jSink, false);
         env->DeleteLocalRef(jSink);
         jSink = NULL;
         if (jStatus != AUDIO_JAVA_SUCCESS) {
@@ -1268,7 +1286,7 @@
         return AUDIO_JAVA_BAD_VALUE;
     }
     struct audio_port_config nAudioPortConfig;
-    jint jStatus = convertAudioPortConfigToNative(env, &nAudioPortConfig, jAudioPortConfig);
+    jint jStatus = convertAudioPortConfigToNative(env, &nAudioPortConfig, jAudioPortConfig, true);
     if (jStatus != AUDIO_JAVA_SUCCESS) {
         return jStatus;
     }
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 178bab6..e572d22 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -275,6 +275,7 @@
                         subHeap = HEAP_DALVIK_LINEARALLOC;
                     } else if ((strstr(name, "/dev/ashmem/dalvik-alloc space") == name) ||
                                (strstr(name, "/dev/ashmem/dalvik-main space") == name) ||
+                               (strstr(name, "/dev/ashmem/dalvik-zygote space") == name) ||
                                (strstr(name, "/dev/ashmem/dalvik-non moving space") == name)) {
                         // This is the regular Dalvik heap.
                         whichHeap = HEAP_DALVIK;
diff --git a/core/res/res/anim/dock_bottom_enter.xml b/core/res/res/anim/dock_bottom_enter.xml
index 4f2f753..bfb97b6 100644
--- a/core/res/res/anim/dock_bottom_enter.xml
+++ b/core/res/res/anim/dock_bottom_enter.xml
@@ -20,5 +20,5 @@
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:interpolator="@android:interpolator/decelerate_cubic">
     <translate android:fromYDelta="100%" android:toYDelta="0"
-        android:duration="250"/>
+        android:duration="@integer/dock_enter_exit_duration"/>
 </set>
diff --git a/core/res/res/anim/dock_bottom_exit.xml b/core/res/res/anim/dock_bottom_exit.xml
index afbe24b..4e15448 100644
--- a/core/res/res/anim/dock_bottom_exit.xml
+++ b/core/res/res/anim/dock_bottom_exit.xml
@@ -20,5 +20,5 @@
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:interpolator="@android:interpolator/accelerate_cubic">
     <translate android:fromYDelta="0" android:toYDelta="100%"
-        android:startOffset="100" android:duration="250"/>
+        android:startOffset="100" android:duration="@integer/dock_enter_exit_duration"/>
 </set>
diff --git a/core/res/res/anim/dock_top_enter.xml b/core/res/res/anim/dock_top_enter.xml
index 1f74e48..f763fb5 100644
--- a/core/res/res/anim/dock_top_enter.xml
+++ b/core/res/res/anim/dock_top_enter.xml
@@ -20,5 +20,5 @@
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:interpolator="@android:interpolator/decelerate_cubic">
     <translate android:fromYDelta="-100%" android:toYDelta="0"
-        android:duration="250"/>
+        android:duration="@integer/dock_enter_exit_duration"/>
 </set>
diff --git a/core/res/res/anim/dock_top_exit.xml b/core/res/res/anim/dock_top_exit.xml
index 4d2fea9..995b7d0 100644
--- a/core/res/res/anim/dock_top_exit.xml
+++ b/core/res/res/anim/dock_top_exit.xml
@@ -20,5 +20,5 @@
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:interpolator="@android:interpolator/accelerate_cubic">
     <translate android:fromYDelta="0" android:toYDelta="-100%"
-        android:startOffset="100" android:duration="250"/>
+        android:startOffset="100" android:duration="@integer/dock_enter_exit_duration"/>
 </set>
diff --git a/core/res/res/drawable-hdpi/switch_track_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/switch_track_mtrl_alpha.9.png
index 0ebe65e..9415bc0 100644
--- a/core/res/res/drawable-hdpi/switch_track_mtrl_alpha.9.png
+++ b/core/res/res/drawable-hdpi/switch_track_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/switch_track_mtrl_alpha.9.png b/core/res/res/drawable-ldpi/switch_track_mtrl_alpha.9.png
deleted file mode 100644
index a58128f..0000000
--- a/core/res/res/drawable-ldpi/switch_track_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/edit_text_material.xml b/core/res/res/drawable/edit_text_material.xml
index bbc7301..38ac567 100644
--- a/core/res/res/drawable/edit_text_material.xml
+++ b/core/res/res/drawable/edit_text_material.xml
@@ -15,21 +15,23 @@
 -->
 
 <inset xmlns:android="http://schemas.android.com/apk/res/android"
-        android:inset="@dimen/control_inset_material">
-    <ripple android:color="?attr/colorControlActivated">
-        <item>
-            <selector>
-                <item android:state_enabled="false">
-                    <nine-patch android:src="@drawable/textfield_default_mtrl_alpha"
-                        android:tint="?attr/colorControlNormal"
-                        android:alpha="?attr/disabledAlpha" />
-                </item>
-                <item>
-                    <nine-patch android:src="@drawable/textfield_default_mtrl_alpha"
-                        android:tint="?attr/colorControlNormal" />
-                </item>
-            </selector>
+       android:insetLeft="@dimen/edit_text_inset_horizontal_material"
+       android:insetRight="@dimen/edit_text_inset_horizontal_material"
+       android:insetTop="@dimen/edit_text_inset_top_material"
+       android:insetBottom="@dimen/edit_text_inset_bottom_material">
+    <selector>
+        <item android:state_enabled="false">
+            <nine-patch android:src="@drawable/textfield_default_mtrl_alpha"
+                android:tint="?attr/colorControlNormal"
+                android:alpha="?attr/disabledAlpha" />
         </item>
-        <item android:id="@+id/mask" android:drawable="@drawable/textfield_activated_mtrl_alpha" />
-    </ripple>
+        <item android:state_pressed="false" android:state_focused="false">
+            <nine-patch android:src="@drawable/textfield_default_mtrl_alpha"
+                android:tint="?attr/colorControlNormal" />
+        </item>
+        <item>
+            <nine-patch android:src="@drawable/textfield_activated_mtrl_alpha"
+                android:tint="?attr/colorControlActivated" />
+        </item>
+    </selector>
 </inset>
diff --git a/core/res/res/layout/notification_template_material_base.xml b/core/res/res/layout/notification_template_material_base.xml
index 674d7b8..3fdcaf7 100644
--- a/core/res/res/layout/notification_template_material_base.xml
+++ b/core/res/res/layout/notification_template_material_base.xml
@@ -28,6 +28,7 @@
         android:layout_height="@dimen/notification_large_icon_height"
         />
     <LinearLayout
+        android:id="@+id/notification_main_column"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_gravity="top"
diff --git a/core/res/res/layout/notification_template_material_big_base.xml b/core/res/res/layout/notification_template_material_big_base.xml
index ef916ed..935424a 100644
--- a/core/res/res/layout/notification_template_material_big_base.xml
+++ b/core/res/res/layout/notification_template_material_big_base.xml
@@ -28,6 +28,7 @@
         android:layout_height="@dimen/notification_large_icon_height"
         />
     <LinearLayout
+        android:id="@+id/notification_main_column"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_gravity="top"
diff --git a/core/res/res/layout/notification_template_material_big_text.xml b/core/res/res/layout/notification_template_material_big_text.xml
index 3415814..d0c10b2 100644
--- a/core/res/res/layout/notification_template_material_big_text.xml
+++ b/core/res/res/layout/notification_template_material_big_text.xml
@@ -28,6 +28,7 @@
         android:layout_height="@dimen/notification_large_icon_height"
         />
     <LinearLayout
+        android:id="@+id/notification_main_column"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_gravity="top"
diff --git a/core/res/res/layout/notification_template_material_inbox.xml b/core/res/res/layout/notification_template_material_inbox.xml
index 8a66c3f..ac448ee 100644
--- a/core/res/res/layout/notification_template_material_inbox.xml
+++ b/core/res/res/layout/notification_template_material_inbox.xml
@@ -28,6 +28,7 @@
         android:layout_height="@dimen/notification_large_icon_height"
         />
     <LinearLayout
+        android:id="@+id/notification_main_column"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_gravity="top"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index f0a05ea..522af95 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Laat die program toe om Wi-Fi-skerms op te stel en daaraan te koppel."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"beheer Wi-Fi-skerms"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Laat die program toe om laevlak-kenmerke van Wi-Fi-skerms te beheer."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"beheer virtuele private netwerke"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Laat die program toe om laevlak-kenmerke van virtuele private netwerke te beheer."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"vang oudio-uitset vas"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Laat die program oudio-uitset vasvang en herlei."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Aktiveerwoord-opsporing"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Tot die volgende wekker om <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Tot die volgende wekker"</string>
     <string name="muted_by" msgid="6147073845094180001">"Gedemp deur <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Daar is \'n interne probleem met jou toestel en dit sal dalk onstabiel wees totdat jy \'n fabriekterugstelling doen."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Daar is \'n interne probleem met jou toestel. Kontak jou vervaardiger vir besonderhede."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 7c90290..4efa564 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"መተግበሪያው የWifi ማሳያዎችን እንዲያዋቅርና ከእነሱ ጋር እንዲገናኝ ይፈቅድለታል።"</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"የWifi ማሳያዎችን ተቆጣጠር"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"መተግበሪያው በዝቅተኛ ደረጃ ላይ ያሉ የWifi ማሳያዎችን እንዲቆጣጠር ይፈቅድለታል።"</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"ምናባዊ የግል አውታረ መረቦችን ይቆጣጠሩ"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"መተግበሪያው የምናባዊ ግል አውታረ መረቦች ዝቅተኛ ደረጃ ባህሪያትን እንዲቆጣጠር ያስችለዋል።"</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"የድምጽ ውጽዓት ይቅረጹ"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"መተግበሪያው የድምጽ ውጽዓት እንዲቀርጽ እና አቅጣጫውን እንዲያዞር ያስችለዋል።"</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"ትኩስ ቃል ማወቅ"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"በ<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> ላይ እስከሚቀጥለው ማንቂያ ድረስ"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"እስከሚቀጥለው ማንቂያ ድረስ"</string>
     <string name="muted_by" msgid="6147073845094180001">"ድምጽ በ<xliff:g id="THIRD_PARTY">%1$s</xliff:g> ተዘግቷል"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"መሣሪያዎ ላይ የውስጣዊ ችግር አለ፣ የፋብሪካ ውሂብ ዳግም እስኪያስጀምሩት ድረስ ላይረጋጋ ይችላል።"</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"መሣሪያዎ ላይ የውስጣዊ ችግር አለ። ዝርዝሮችን ለማግኘት አምራችዎን ያነጋግሩ።"</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index f696947..98821ca 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"‏للسماح للتطبيق بتهيئة شاشات Wi-Fi والاتصال بها."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"‏التحكم في شاشات Wi-Fi"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"‏للسماح للتطبيق بالتحكم في الميزات ذات المستوى المنخفض في شاشات Wi-Fi."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"التحكم في الشبكات الظاهرية الخاصة"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"للسماح للتطبيق بالتحكم في ميزات المستوى المنخفض للشبكات الظاهرية الخاصة."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"التقاط إخراج الصوت"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"السماح للتطبيق بالتقاط إخراج الصوت وإعادة توجيهه."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"اكتشاف الكلمة المهمة"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"حتى التنبيه التالي في <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"حتى التنبيه التالي"</string>
     <string name="muted_by" msgid="6147073845094180001">"تم كتم الصوت بواسطة <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"حدثت مشكلة داخلية في جهازك، وقد لا يستقر وضعه حتى إجراء إعادة الضبط بحسب بيانات المصنع."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"حدثت مشكلة داخلية في جهازك. يمكنك الاتصال بالمصنِّع للحصول على تفاصيل."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 00640bb..97b8fc5 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Разрешава на приложението да конфигурира и да се свързва с дисплеите през WiFi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"контролиране на дисплеите през WiFi"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Разрешава на приложението да контролира функциите от ниско ниво на дисплеите през WiFi."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"управление на виртуалните частни мрежи"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Разрешава на приложението да управлява функциите от ниско ниво на виртуалните частни мрежи."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"записване на възпроизвеждания звук"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Разрешава на приложението да записва и пренасочва възпроизвеждания звук."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Откриване на активиращи думи"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"До следващия будилник в <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"До следващия будилник"</string>
     <string name="muted_by" msgid="6147073845094180001">"Заглушено от <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Възникна вътрешен проблем с устройството ви. То може да е нестабилно, докато не възстановите фабричните настройки."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Възникна вътрешен проблем с устройството ви. За подробности се свържете с производителя."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index b865a18..cb55c95 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Wifi প্রদর্শনগুলি অনুযায়ী কনফিগার করে নিতে এবং সংযোগ স্থাপন করতে অ্যাপ্লিকেশানটিকে মঞ্জুর করে৷"</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Wifi প্রদর্শনগুলিকে নিয়ন্ত্রণ করুন"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Wifi প্রদর্শনের নিম্ন মানের বৈশিষ্ট্যগুলিকে নিয়ন্ত্রণ করতে অ্যাপ্লিকেশানটিকে মঞ্জুর করে৷"</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"ভার্চুয়াল প্রাইভেট নেটওয়ার্ক নিয়ন্ত্রণ করুন"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"অ্যাপ্লিকেশানটিকে ভার্চুয়াল প্রাইভেট নেটওয়ার্কের নিম্নস্তরের বৈশিষ্ট্য নিয়ন্ত্রণ করতে দেয়৷"</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"অডিও আউটপুট গ্রহণ করে"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"অ্যাপ্লিকেশানটিকে অডিও আউটপুট গ্রহণ এবং পুনর্নির্দেশ করতে দেয়৷"</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"হটওয়ার্ড সনাক্তকরণ"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> এ পরবর্তী অ্যালার্ম পর্যন্ত"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"পরবর্তী অ্যালার্ম পর্যন্ত"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> দ্বারা নিঃশব্দ করা হয়েছে"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"আপনার ডিভাইসে একটি অভ্যন্তরীন সমস্যা হয়েছে, এবং আপনি যতক্ষণ না পর্যন্ত এটিকে ফ্যাক্টরি ডেটা রিসেট করছেন ততক্ষণ এটি ঠিকভাবে কাজ নাও করতে পারে৷"</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"আপনার ডিভাইসে একটি অভ্যন্তরীন সমস্যা হয়েছে৷ বিস্তারিত জানার জন্য প্রস্তুতকারকের সাথে যোগাযোগ করুন৷"</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 72179d8..3ac2fd8 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Permet a l\'aplicació configurar-se i connectar-se a les pantalles Wi-Fi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"control de les pantalles Wi-Fi"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permet a l\'aplicació controlar les funcions de baix nivell de les pantalles Wi-Fi."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"controlar xarxes privades virtuals"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Permet que l\'aplicació controli funcions de nivell baix de xarxes privades virtuals."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"captura la sortida d\'àudio"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Permet que l\'aplicació capturi i redirigeixi la sortida d\'àudio."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Detecció de paraules actives"</string>
@@ -833,8 +835,8 @@
     <string name="permdesc_handoverStatus" msgid="4788144087245714948">"Permet que aquesta aplicació rebi informació sobre les transferències d\'Android Beam actuals."</string>
     <string name="permlab_removeDrmCertificates" msgid="7044888287209892751">"suprimir els certificats DRM"</string>
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Permet que una aplicació suprimeixi els certificats DRM. No ha de ser mai necessari per a aplicacions normals."</string>
-    <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"vincular-la a un servei de missatgeria"</string>
-    <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Permet que el propietari la pugui vincular a la interfície principal d\'un servei de missatgeria. És possible que no s\'hagi d\'utilitzar mai amb aplicacions normals."</string>
+    <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"vincular-la al servei de missatgeria d\'un operador"</string>
+    <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Permet que el propietari la pugui vincular a la interfície principal del servei de missatgeria d\'un operador. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Definir les normes de contrasenya"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controla la longitud i els caràcters permesos a les contrasenyes de desbloqueig de pantalla."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Controlar els intents de desbloqueig de pantalla"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Fins que soni l\'alarma següent a les <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Fins que soni l\'alarma següent"</string>
     <string name="muted_by" msgid="6147073845094180001">"Silenciat per <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"S\'ha produït un error intern al dispositiu i és possible que funcioni de manera inestable fins que restableixis les dades de fàbrica."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"S\'ha produït un error intern al dispositiu. Contacta amb el fabricant del dispositiu per obtenir més informació."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index a91c3ba..81d2e50 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Povoluje aplikaci připojit a konfigurovat displeje přes Wi-Fi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"ovládat displeje přes Wi-Fi"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Povoluje aplikaci ovládat základní funkce displejů přes Wi-Fi."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"ovládat virtuální privátní sítě"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Umožňuje aplikaci ovládat nízkoúrovňové funkce virtuálních privátních síti."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"zachytit výstup zvuku"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Umožní aplikaci zachytit a přesměrovat výstup zvuku."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Detekce klíčových slov"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Do dalšího budíku v <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Do příštího budíku"</string>
     <string name="muted_by" msgid="6147073845094180001">"Ignorováno stranou <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"V zařízení došlo k internímu problému. Dokud neprovedete obnovení továrních dat, může být nestabilní."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"V zařízení došlo k internímu problému. Další informace vám sdělí výrobce."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 2088ac4..22c9506 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Tillader, at appen konfigurerer og opretter forbindelse til Wi-Fi-skærme."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"kontrollér Wi-Fi-skærme"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Tillader, at appen kontrollerer Wi-Fi-skærmfunktioner på lavt niveau."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"styre virtuelle private netværk"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Tillader, at appen styrer basale funktioner i virtuelle private netværk."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"opfang et lydoutput"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Tillader, at appen opfanger og omdirigerer et lydoutput."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Registrering af kommandoord"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Indtil næste alarm kl. <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Indtil næste alarm"</string>
     <string name="muted_by" msgid="6147073845094180001">"Lyden blev afbrudt af <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Der er et internt problem med enheden, og den vil muligvis være ustabil, indtil du gendanner fabriksdataene."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Der er et internt problem med enheden. Kontakt producenten for at få yderligere oplysninger."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index bd38d66..cdbe08d 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Erlaubt der App, WLAN-Anzeigen zu konfigurieren und eine Verbindung zu diesen herzustellen"</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"WLAN-Anzeigen steuern"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Erlaubt der App, untergeordnete Funktionen von WLAN-Anzeigen zu steuern"</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"Virtuelle private Netzwerke steuern"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Ermöglicht der App die Steuerung von Basisfunktionen von virtuellen privaten Netzwerken"</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"Audioausgabe erfassen"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Ermöglicht der App die Erfassung und Weiterleitung von Audioausgaben"</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Hotword-Erkennung"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Bis zum nächsten Weckruf um <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Bis zum nächsten Weckruf"</string>
     <string name="muted_by" msgid="6147073845094180001">"Stummgeschaltet durch <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Es liegt ein internes Problem mit Ihrem Gerät vor. Möglicherweise verhält es sich instabil, bis Sie es auf die Werkseinstellungen zurücksetzen."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Es liegt ein internes Problem mit Ihrem Gerät vor. Bitte wenden Sie sich diesbezüglich an den Hersteller."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index fcd4a9d..c062e42 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Επιτρέπει τη διαμόρφωση της εφαρμογής και τη σύνδεσης σε οθόνες Wifi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"έλεγχος οθονών Wifi"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Επιτρέπει στην εφαρμογή τον έλεγχο των λειτουργιών χαμηλού επιπέδου των οθονών Wifi."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"έλεγχος εικονικών ιδιωτικών δικτύων"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Επιτρέπει στην εφαρμογή να ελέγχει τις λειτουργίες χαμηλού επιπέδου των εικονικών ιδιωτικών δικτύων."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"έγγραφή εξόδου ήχου"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Δίνει στην εφαρμογή τη δυνατότητα εγγραφής και ανακατεύθυνσης εξόδου ήχου."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Ανίχνευση ενεργών λέξεων"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Έως την επόμενη ειδοποίηση στις <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Έως την επόμενη ειδοποίηση"</string>
     <string name="muted_by" msgid="6147073845094180001">"Σίγαση από <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Υπάρχει ένα εσωτερικό πρόβλημα με τη συσκευή σας και ενδέχεται να είναι ασταθής μέχρι την επαναφορά των εργοστασιακών ρυθμίσεων."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Υπάρχει ένα εσωτερικό πρόβλημα με τη συσκευή σας. Επικοινωνήστε με τον κατασκευαστή σας για λεπτομέρειες."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 678f2e6..98dc0f5 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Allows the app to configure and connect to Wi-Fi displays."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"control Wi-Fi displays"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Allows the app to control low-level features of Wi-Fi displays."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"control Virtual Private Networks"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Allows the app to control low-level features of Virtual Private Networks."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"capture audio output"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Allows the app to capture and redirect audio output."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Hotword detection"</string>
@@ -1902,4 +1904,12 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Until next alarm at <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Until next alarm"</string>
     <string name="muted_by" msgid="6147073845094180001">"Muted by <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"There\'s an internal problem with your device, and it may be unstable until you factory data reset."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"There\'s an internal problem with your device. Contact your manufacturer for details."</string>
+    <string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD request is modified to DIAL request."</string>
+    <string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD request is modified to SS request."</string>
+    <string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD request is modified to new USSD request."</string>
+    <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS request is modified to DIAL request."</string>
+    <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS request is modified to USSD request."</string>
+    <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS request is modified to new SS request."</string>
 </resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 678f2e6..98dc0f5 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Allows the app to configure and connect to Wi-Fi displays."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"control Wi-Fi displays"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Allows the app to control low-level features of Wi-Fi displays."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"control Virtual Private Networks"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Allows the app to control low-level features of Virtual Private Networks."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"capture audio output"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Allows the app to capture and redirect audio output."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Hotword detection"</string>
@@ -1902,4 +1904,12 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Until next alarm at <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Until next alarm"</string>
     <string name="muted_by" msgid="6147073845094180001">"Muted by <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"There\'s an internal problem with your device, and it may be unstable until you factory data reset."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"There\'s an internal problem with your device. Contact your manufacturer for details."</string>
+    <string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD request is modified to DIAL request."</string>
+    <string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD request is modified to SS request."</string>
+    <string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD request is modified to new USSD request."</string>
+    <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS request is modified to DIAL request."</string>
+    <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS request is modified to USSD request."</string>
+    <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS request is modified to new SS request."</string>
 </resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 18424ab..e9fd79d 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Permite que la aplicación configure y se conecte a pantallas Wi-Fi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"controlar pantallas Wi-Fi"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permite que la aplicación controle funciones de bajo nivel de las pantallas Wi-Fi."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"controlar redes privadas virtuales"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Permite que la aplicación controle las funciones de bajo nivel de las redes privadas virtuales."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"Capturar salida de audio"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Permite que la aplicación capture y redirija la salida de audio."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Detectar palabras activas"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Hasta la próxima alarma a la(s) <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Hasta la próxima alarma"</string>
     <string name="muted_by" msgid="6147073845094180001">"Silenciados por <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Existe un problema interno con el dispositivo, de modo que el dispositivo puede estar inestable hasta que restablezcas la configuración de fábrica."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Existe un problema interno con el dispositivo. Comunícate con el fabricante para obtener más información."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index a90ef65..a8bdbbd 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Permite que la aplicación configure pantallas Wi-Fi y se conecte a ellas."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"controlar pantallas Wi-Fi"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permite que la aplicación controle funciones de bajo nivel de pantallas Wi-Fi."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"controlar redes privadas virtuales"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Permite que la aplicación controle funciones de bajo nivel de redes privadas virtuales."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"capturar salida de audio"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Permite que la aplicación capture y redirija la salida de audio."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Detectar palabras activas"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Hasta la próxima alarma a las <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Hasta la próxima alarma"</string>
     <string name="muted_by" msgid="6147073845094180001">"Silenciado por <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Se ha producido un problema interno en el dispositivo y es posible que este no sea estable hasta que restablezcas los datos de fábrica."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Se ha producido un problema interno en el dispositivo. Ponte en contacto con el fabricante para obtener más información."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 08b82a7..d6627da 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Lubab rakendusel seadistada WiFi-ekraane ja nendega ühendus luua."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"WiFi-ekraanide juhtimine"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Lubab rakendusel juhtida WiFi-ekraanide madala taseme funktsioone."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"virtuaalsete privaatvõrkudega juhtimine"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Lubab rakendusel juhtida virtuaalsete privaatvõrkude alamtaseme funktsioone."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"heliväljundi jäädvustamine"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Lubab rakendusel jäädvustada ja ümber suunata heliväljundit."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Otsetee sõna tuvastamine"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Kuni järgmise alarmini <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Kuni järgmise alarmini"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> vaigistas"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Seadmes ilmnes sisemine probleem ja seade võib olla ebastabiilne seni, kuni lähtestate seadme tehase andmetele."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Seadmes ilmnes sisemine probleem. Üksikasjaliku teabe saamiseks võtke ühendust tootjaga."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index bc4912c..aa7d6c4 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Wi-Fi pantailak konfiguratzeko eta haietara konektatzeko baimena ematen die aplikazioei."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Wi-Fi pantailak kontrolatzea"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Wi-Fi pantailetako behe-mailako eginbideak kontrolatzeko baimena ematen die aplikazioei."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"Kontrolatu sare pribatu birtualak"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Sare pribatu birtualen behe-mailako eginbideak kontrolatzea baimentzen die aplikazioei."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"Grabatu audio-irteera"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Audio-irteera grabatzeko eta birbideratzeko aukera ematen die aplikazioei."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Hauteman Hotword"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Hurrengo alarmara arte (<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>)"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Hurrengo alarmara arte"</string>
     <string name="muted_by" msgid="6147073845094180001">"Audioa desaktibatu da (<xliff:g id="THIRD_PARTY">%1$s</xliff:g>)"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Barneko arazo bat dago zure gailuan eta agian ezegonkor egongo da jatorrizko datuak berrezartzen dituzun arte."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Barneko arazo bat dago zure gailuan. Xehetasunak jakiteko, jarri fabrikatzailearekin harremanetan."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 0ddb458..51ba165 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"‏به برنامه اجازه می‌دهد تا اتصال به صفحات نمایش Wi‑Fi را پیکربندی کند."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"‏کنترل صفحه نمایش‌های Wi‑Fi"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"‏به برنامه اجازه می‌دهد که ویژگی‌های سطح پایین صفحه‌های نمایش Wi‑Fi را کنترل کند."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"کنترل شبکه‌های خصوصی مجازی"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"به برنامه امکان کنترل ویژگی‌های سطح پایین شبکه‌های خصوصی مجازی را می‌دهد."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"ضبط خروجی صدا"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"به برنامه امکان می‌دهد خروجی صدا را ضبط و هدایت کند."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"تشخیص کلیدگفته"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"تا هشدار بعدی در <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"تا هشدار بعدی"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> آن را بی‌صدا کرد"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"دستگاهتان یک مشکل داخلی دارد، و ممکن است تا زمانی که بازنشانی به داده کارخانه انجام نگیرد، بی‌ثبات بماند."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"دستگاهتان یک مشکل داخلی دارد. برای جزئیات آن با سازنده‌تان تماس بگیرید."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index a484cf7..f39abf1 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Antaa sovelluksen määrittää wifi-näyttöjä ja muodostaa yhteyden niihin."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"hallitse wifi-näyttöjä"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Antaa sovelluksen hallita wifi-näyttöjen matalan tason ominaisuuksia."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"Hallita virtuaalisia yksityisverkkoja."</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Sallii sovelluksen hallita virtuaalisten yksityisverkkojen alempien tasojen ominaisuuksia."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"äänentoiston kaappaus"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Antaa sovellukselle luvan äänentoiston kaappaamiseen ja uudelleenohjaamiseen."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Toimintosanan tunnistus"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Seuraavaan herätykseen saakka (<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>)"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Seuraavaan herätykseen saakka"</string>
     <string name="muted_by" msgid="6147073845094180001">"Mykistänyt <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Laitteellasi on sisäinen ongelma, joka aiheuttaa epävakautta. Voit korjata tilanteen palauttamalla tehdasasetukset."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Laitteesi yhdistäminen ei onnistu sisäisen virheen takia. Saat lisätietoja valmistajalta."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 8f08926..6925454 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Permet à l\'application de configurer des écrans Wi-Fi et de s\'y connecter."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"contrôler les écrans Wi-Fi"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permet à l\'application de contrôler les fonctionnalités de base des écrans Wi-Fi."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"commander les réseaux privés virtuels"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Permet à l\'application de commander les fonctions de bas niveau des réseaux privés virtuels."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"capturer la sortie audio"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Autoriser l\'application à capturer et à rediriger la sortie audio."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Détection de mots clés"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Jusqu\'à la prochaine alarme, à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Jusqu\'à la prochaine alarme"</string>
     <string name="muted_by" msgid="6147073845094180001">"Mis en sourdine par <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Un problème interne est survenu avec votre appareil. Il se peut qu\'il soit instable jusqu\'à ce que vous le réinitialisiez à sa configuration d\'usine."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Un problème interne est survenu avec votre appareil. Communiquez avec le fabricant pour obtenir plus de détails."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 95d58ad..def3d35 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Permet à l\'application de configurer des écrans Wi-Fi et de s\'y connecter."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"contrôler les écrans Wi-Fi"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permet à l\'application de contrôler les fonctionnalités de base des écrans Wi-Fi."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"contrôler les réseaux privés virtuels"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Permettre à l\'application de contrôler les fonctionnalités de base des réseaux privés virtuels"</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"enregistrer les sorties audio"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Autoriser l\'application à enregistrer et à rediriger les sorties audio"</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Détection de mot clé"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Jusqu\'à la prochaine alarme à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Jusqu\'à la prochaine alarme"</string>
     <string name="muted_by" msgid="6147073845094180001">"Son coupé par : <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Un problème interne lié à votre appareil est survenu. Ce dernier risque d\'être instable jusqu\'à ce que vous rétablissiez la configuration d\'usine."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Un problème interne lié à votre appareil est survenu. Veuillez contacter le fabricant pour en savoir plus."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index c6264b9..0380519 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Permite á aplicación configurar e conectarse a pantallas wifi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"controlar pantallas wifi"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permite á aplicación controlar funcións de baixo nivel de pantallas wifi."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"controlar redes virtuais privadas"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Permite que a aplicación controle as funcións de nivel básico das redes virtuais privadas."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"capturar saída de audio"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Permite á aplicación capturar e redireccionar a saída de audio."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Detección de palabras activas"</string>
@@ -833,8 +835,8 @@
     <string name="permdesc_handoverStatus" msgid="4788144087245714948">"Permite a esta aplicación recibir información acerca das transferencias actuais de Android Beam"</string>
     <string name="permlab_removeDrmCertificates" msgid="7044888287209892751">"eliminar certificados DRM"</string>
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Permite a unha aplicación eliminar os certificados DRM. As aplicacións normais non o deberían precisar nunca."</string>
-    <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"vincular a un servizo de mensaxería do operador"</string>
-    <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Permite ao propietario vincularse á interface de nivel superior dun servizo de mensaxería do operador. As aplicacións normais non deberían necesitar este permiso."</string>
+    <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"vincular a un servizo de mensaxería"</string>
+    <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Permite ao propietario vincularse á interface de nivel superior dun servizo de mensaxería. As aplicacións normais non deberían necesitar este permiso."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Establecer as normas de contrasinal"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar a lonxitude e os caracteres permitidos nos contrasinais de desbloqueo da pantalla."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Supervisar os intentos de desbloqueo da pantalla"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Ata que soe a seguinte alarma ás <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Ata que soe a seguinte alarma"</string>
     <string name="muted_by" msgid="6147073845094180001">"Silenciado por <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Produciuse un problema interno co teu dispositivo e quizais estea inestable ata o restablecemento dos datos de fábrica."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Produciuse un problema interno co teu dispositivo. Contacta co teu fabricante para obter máis detalles."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index cdff615..ab2edfc 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"ऐप्स  को कॉन्फ़िगर करने देता है और Wifi डिस्प्ले से कनेक्ट करता है."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Wifi डिस्प्ले को नियंत्रित करें"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"ऐप्स  को Wifi डिस्प्ले की निम्न-स्तर की सुविधाएं नियंत्रित करने देता है."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"आभासी निजी नेटवर्क को नियंत्रित करें"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"ऐप्‍स को आभासी निजी नेटवर्क की निम्‍न-स्‍तर की सुविधाओं को नियंत्रित करने देती है."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"ऑडियो आउटपुट को कैप्‍चर करें"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"ऐप्स को ऑडियो आउटपुट को कैप्‍चर और रीडायरेक्‍ट करने देता है."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"हॉटवर्ड पहचान"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> पर अगले अलार्म तक"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"अगले अलार्म तक"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> द्वारा म्यूट किया गया"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"आपके डिवाइस के साथ कोई आंतरिक त्रुटि हुई और यह तब तक अस्‍थिर रह सकता है, जब तक आप फ़ैक्‍टरी डेटा रीसेट नहीं करते."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"आपके डिवाइस के साथ कोई आंतरिक त्रुटि हुई. विवरणों के लिए अपने निर्माता से संपर्क करें."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 6c82b25..2315075 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Omogućuje aplikaciji konfiguriranje i povezivanje s Wi-Fi zaslonima."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"upravljaj Wifi zaslonima"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Omogućuje aplikaciji upravljanje značajkama Wi-Fi zaslona niske razine."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"upravljanje virtualnim privatnim mrežama"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Aplikaciji omogućuje upravljanje značajkama niske razine na virtualnim privatnim mrežama."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"primanje audioizlaza"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Omogućuje aplikaciji primanje i preusmjeravanje audioizlaza."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Otkrivanje pokretača značajke"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Do sljedećeg alarma u <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Do sljedećeg alarma"</string>
     <string name="muted_by" msgid="6147073845094180001">"Zvuk je isklj. treća strana <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Na vašem uređaju postoji interni problem i možda neće biti stabilan dok ga ne vratite na tvorničko stanje."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Na vašem uređaju postoji interni problem. Obratite se proizvođaču za više pojedinosti."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 79f36c0..1e56caf 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Lehetővé teszi, hogy az alkalmazás Wi-Fi kijelzőket konfiguráljon, és csatlakozzon hozzájuk."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Wi-Fi kijelzők irányítása"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Lehetővé teszi, hogy az alkalmazás irányítsa a Wi-Fi kijelzők alacsonyabb szintű funkcióit."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"virtuális magánhálózatok kezelése"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Lehetővé teszi, hogy az alkalmazás kezelje a virtuális magánhálózatok alacsony szintű funkcióit."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"audiokimenet rögzítése"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Engedélyezi az alkalmazásnak a hangkimenet rögzítését és átirányítását."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Hotwordérzékelés"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"A következő ébresztésig ekkor: <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"A következő ébresztésig"</string>
     <string name="muted_by" msgid="6147073845094180001">"A(z) <xliff:g id="THIRD_PARTY">%1$s</xliff:g> elnémította"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Belső probléma van az eszközzel, és instabil lehet, amíg vissza nem állítja a gyári adatokat."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Belső probléma van az eszközzel. A részletekért vegye fel a kapcsolatot a gyártóval."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index ec4e551..018dbb3 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Թույլ է տալիս հավելվածին կարգավորել և միանալ WiFi ցուցադրիչներին:"</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"կառավարել Wifi-ի ցուցադրումը"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Թույլ է տալիս հավելվածին կառավարել WiFi ցուցադրիչների ցածր մակարդակի գործառույթները:"</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"վերահսկել Վիրտուալ մասնավոր ցանցերը"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Թույլ է տալիս հավելվածին վերահսկել Վիրտուալ մասնավոր ցանցերի ցածր մակարդակի գործառույթները:"</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"պահել աուդիո արտածումը"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Թույլ է տալիս ծրագրին պահել և վերահղել աուդիո արտածումը:"</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Թեժ բառի հայտնաբերում"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Մինչև հաջորդ զարթուցիչը՝ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Մինչև հաջորդ զարթուցիչը"</string>
     <string name="muted_by" msgid="6147073845094180001">"Համրեցվել է <xliff:g id="THIRD_PARTY">%1$s</xliff:g>-ի կողմից"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Սարքում ներքին խնդիր է առաջացել և այն կարող է կրկնվել, եթե գործարանային տվյալների վերականգնում չկատարեք:"</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Սարքում ներքին խնդիր է առաջացել: Մանրամասների համար կապվեք արտադրողի հետ:"</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index c5748e6..98556a2 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -34,7 +34,7 @@
     <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> jam <xliff:g id="MINUTES">%2$d</xliff:g> mnt"</string>
     <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> jam <xliff:g id="MINUTES">%2$d</xliff:g> mnt"</string>
     <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> mnt"</string>
-    <string name="durationMinute" msgid="7155301744174623818">"<xliff:g id="MINUTES">%1$d</xliff:g> mnt"</string>
+    <string name="durationMinute" msgid="7155301744174623818">"<xliff:g id="MINUTES">%1$d</xliff:g> menit"</string>
     <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> mnt <xliff:g id="SECONDS">%2$d</xliff:g> dtk"</string>
     <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> mnt <xliff:g id="SECONDS">%2$d</xliff:g> dtk"</string>
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> dtk"</string>
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Izinkan aplikasi mengonfigurasi dan terhubung ke tampilan Wi-Fi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"mengontrol tampilan Wi-Fi"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Izinkan aplikasi mengontrol fitur tingkat rendah dari tampilan Wi-Fi."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"kontrol Jaringan Pribadi Maya"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Mengizinkan aplikasi untuk mengontrol fitur tingkat rendah dari Jaringan Pribadi Maya."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"tangkap keluaran audio"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Memungkinkan aplikasi menangkap dan mengalihkan keluaran audio."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Deteksi kata cepat"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Sampai alarm berikutnya pukul <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Sampai alarm berikutnya"</string>
     <string name="muted_by" msgid="6147073845094180001">"Dinonaktifkan oleh <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Ada masalah internal dengan perangkat, dan mungkin tidak stabil sampai dikembalikan ke setelan pabrik."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Ada masalah internal dengan perangkat. Hubungi pembuat perangkat untuk detail lengkap."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index 5c9def4..a852cda 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Leyfir forriti að grunnstilla og tengjast þráðlausum skjáum."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"stjórna þráðlausum skjáum"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Leyfir forriti að stjórna grunnvirkni þráðlausra skjáa."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"stjórna VPN-sýndarnetum"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Leyfir forritinu að stjórna grunneiginleikum VPN-sýndarneta."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"fanga hljóðúttak"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Leyfir forriti að fanga og endurbeina hljóðúttaki."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Greining skipana"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Fram að næsta vekjara kl. <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Fram að næsta vekjara"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> tók hljóðið af"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Innra vandamál kom upp í tækinu og það kann að vera óstöðugt þangað til þú núllstillir það."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Innra vandamál kom upp í tækinu. Hafðu samband við framleiðanda til að fá nánari upplýsingar."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index e08b34f..8fc5786 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Consente all\'applicazione di configurare schermi Wi-Fi e di collegarsi a essi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"controllo di schermi Wi-Fi"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Consente all\'applicazione di controllare le funzioni di basso livello di schermi Wi-Fi."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"controllo di reti private virtuali"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Consente all\'app di controllare le funzioni di basso livello di reti private virtuali."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"acquisizione dell\'uscita audio"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Consente all\'app di acquisire e reindirizzare l\'uscita audio."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Rilevamento hotword"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Fino alla prossima sveglia alle ore <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Fino alla prossima sveglia"</string>
     <string name="muted_by" msgid="6147073845094180001">"Audio disattivato da <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Si è verificato un problema interno con il dispositivo, che potrebbe essere instabile fino al ripristino dei dati di fabbrica."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Si è verificato un problema interno con il dispositivo. Per informazioni dettagliate, contatta il produttore."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index a7f8870..d469ca8 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"‏מאפשר לאפליקציה להגדיר ולהתחבר לתצוגות Wi-Fi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"‏שלוט בתצוגות Wi-Fi"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"‏מאפשר לאפליקציה לשלוט בתכונות ברמה נמוכה של תצוגות Wi-Fi."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"שליטה על רשתות וירטואליות פרטיות"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"מאפשר לאפליקציה לקבוע תכונות ברמה נמוכה של רשתות וירטואליות פרטיות."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"קליטת פלט אודיו"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"מאפשרת לאפליקציה לקלוט ולהפנות מחדש פלט אודיו."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"זיהוי של מילת הפעלה"</string>
@@ -1902,4 +1904,12 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"עד ההתראה הבאה ב-<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"עד ההתראה הבאה"</string>
     <string name="muted_by" msgid="6147073845094180001">"הושתק על ידי <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"קיימת בעיה פנימית במכשיר שלך, וייתכן שהתפקוד שלו לא יהיה יציב עד שתבצע איפוס לנתוני היצרן."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"קיימת בעיה פנימית במכשיר שלך. לקבלת פרטים, צור קשר עם היצרן."</string>
+    <string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"‏בקשת USSD שונתה לבקשת DIAL."</string>
+    <string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"‏בקשת USSD שונתה לבקשת SS."</string>
+    <string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"‏בקשת USSD שונתה לבקשת USSD חדשה."</string>
+    <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"‏בקשת SS שונתה לבקשת DIAL."</string>
+    <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"‏בקשת SS שונתה לבקשת USSD."</string>
+    <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"‏בקשת SS שונתה לבקשת SS חדשה."</string>
 </resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index f44681d..93f6f79 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Wi-Fiディスプレイを設定して接続することをアプリに許可します。"</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Wi-Fiディスプレイの制御"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Wi-Fiディスプレイの低レベル機能を制御することをアプリに許可します。"</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"仮想プライベートネットワークの制御"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"仮想プライベートネットワークの低レベル機能を制御することをアプリに許可します。"</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"音声出力のキャプチャ"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"音声出力のキャプチャとリダイレクトをアプリに許可します。"</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"注目ワード検出"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"次のアラーム(<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>)まで"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"次のアラームまで"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g>によりミュートになっています"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"端末で内部的な問題が発生しました。データが初期化されるまで不安定になる可能性があります。"</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"端末で内部的な問題が発生しました。詳しくはメーカーにお問い合わせください。"</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index d6f48fd..eebaabf 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"აპს შეეძლება Wifi ეკრანებთან დაკავშირება და დაკონფიგურირება."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Wifi ეკრანების მართვა"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"აპს შეეძლება აკონტროლოს Wifi ეკრანების დაბალი დონის ფუნქციები."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"ვირტუალური კერძო ქსელების კონტროლი"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"საშუალებას აძლევს აპლიკაციას აკონტროლოს ვირტუალური პირადი ქსელების დაბალი დონის ფუნქციები."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"გამომავალი აუდიოს დაჭერა"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"საშუალებას აძლევს აპს დაიჭიროს და გადაამისამართოს გამომავალი აუდიო."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"ჯადოსნური სიტყვის პოვნა"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"შემდეგ მაღვიძარამდე <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>-ში"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"შემდეგ მაღვიძარამდე"</string>
     <string name="muted_by" msgid="6147073845094180001">"დადუმებულია <xliff:g id="THIRD_PARTY">%1$s</xliff:g>-ის მიერ"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"ფიქსირდება თქვენი მ ოწყობილობის შიდა პრობლემა და შეიძლება არასტაბილური იყოს, სანამ ქარხნულ მონაცემების არ განაახლებთ."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"ფიქსირდება თქვენი მოწყობილობის შიდა პრობლემა. დეტალებისათვის, მიმართეთ თქვენს მწარმოებელს."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index a15ac78..97b435a 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Қолданбаларға Wifi дисплейлерін конфигурациялау және қосылу мүмкіндігін береді."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Wifi дисплейлерін басқару"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Қолданбаларға Wifi дисплейлерінің төмен деңгейлі функцияларын басқару мүмкіндігін береді."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"control Virtual Private Networks"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Allows the app to control low-level features of Virtual Private Networks."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"аудио шығысын жазып алу"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Қолданбаға аудио сигналды қабылдап, басқа бағытта жөнелту мүмкіндігін ұсынады."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Байланыс сөзін анықтау"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> уақытындағы келесі дабылға дейін"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Келесі дабылға дейін"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> үнін өшірген"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"There\'s an internal problem with your device, and it may be unstable until you factory data reset."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"There\'s an internal problem with your device. Contact your manufacturer for details."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 5be27a8..9b13133 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"ឲ្យ​កម្មវិធី​កំណត់​រចនាសម្ព័ន្ធ​ និង​ភ្ជាប់​ទៅ​ការ​បង្ហាញ​វ៉ាយហ្វាយ។"</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"ពិនិត្យ​ការ​បង្ហាញ​វ៉ាយហ្វាយ"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"ឲ្យ​កម្មវិធី​ពិនិត្យ​លក្ខណៈ​កម្រិត​ទាប​​នៃ​ការ​បង្ហាញ​វ៉ាយហ្វាយ។"</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"គ្រប់គ្រង បណ្តាញឯកជននិមិត្ម"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"អនុញ្ញាតឲ្យកម្មវិធីគ្រប់គ្រងលក្ខណៈពិសេសកម្រិតទាបនៃបណ្តាញឯកជននិមិត្ម Virtual Private Networks។"</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"ចាប់​យក​លទ្ធផល​អូឌីយ៉ូ"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"​ឱ្យ​កម្មវិធី​ដើម្បី​ចាប់​យក​ និង​​ប្ដូរ​​ទិស​លទ្ធផល​អូឌីយ៉ូ​។"</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"ការ​រក​ឃើញ​ពាក្យ"</string>
@@ -1904,4 +1906,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"រហូត​ដល់​ការ​ជូន​ដំណឹង​បន្ទាប់​នៅ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"រហូត​ការ​ជូន​ដំណឹង​បន្ទាប់"</string>
     <string name="muted_by" msgid="6147073845094180001">"បាន​បិទ​សំឡេង​ដោយ <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"មានបញ្ហាខាងក្នុងឧបករណ៍របស់អ្នក ហើយវាអ្នកមិនមានស្ថេរភាព រហូតទាល់តែអ្នកកំណត់ដូចដើមវិញទាំងស្រុង។"</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"មានបញ្ហាខាងក្នុងឧបករណ៍របស់អ្នក ទំនាក់ទំនងក្រុមហ៊ុនផលិតឧបករណ៍របស់អ្នកសម្រាប់ព័ត៌មានបន្ថែម។"</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index f932c1d..e53fb1e 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"ವೈಫೈ ಪ್ರದರ್ಶನಗಳಿಗೆ ಕಾನ್ಫಿಗರ್ ಮಾಡಲು ಮತ್ತು ಸಂಪರ್ಕಪಡಿಸಲು ಅಪ್ಲಿಕೇಶನ್‍‍ಗೆ ಅವಕಾಶ ನೀಡುತ್ತದೆ."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"ವೈಫೈ ಪ್ರದರ್ಶನಗಳನ್ನು ನಿಯಂತ್ರಿಸಿ"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"ವೈಫೈ ಪ್ರದರ್ಶನಗಳ ಕೆಳ-ಮಟ್ಟದ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ನಿಯಂತ್ರಿಸಲು ಅಪ್ಲಿಕೇಶನ್‍‍ಗೆ ಅವಕಾಶ ಕಲ್ಪಿಸುತ್ತದೆ."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"ವರ್ಚುವಲ್ ಖಾಸಗಿ ನೆಟ್‌ವರ್ಕ್‌ಗಳನ್ನು ನಿಯಂತ್ರಿಸಿ"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"ವರ್ಚುವಲ್ ಖಾಸಗಿ ನೆಟ್‌ವರ್ಕ್‌ಗಳ ಕೆಳ ಮಟ್ಟದ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ನಿಯಂತ್ರಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"ಆಡಿಯೊ ಔಟ್‌ಪುಟ್ ಸೆರೆಹಿಡಿಯಿರಿ"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"ಆಡಿಯೊ ಔಟ್‌ಪುಟ್ ಸೆರೆಹಿಡಿಯಲು ಮತ್ತು ಮರುನಿರ್ದೇಶಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"ಹಾಟ್‌ವರ್ಡ್ ಪತ್ತೆಹಚ್ಚುವಿಕೆ"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"ಮುಂದಿನ ಅಲಾರಮ್ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> ವರೆಗೆ"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"ಮುಂದಿನ ಅಲಾರಮ್‌ವರೆಗೆ"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> ಅವರಿಂದ ಮ್ಯೂಟ್‌ ಮಾಡಲಾಗಿದೆ"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಆಂತರಿಕ ಸಮಸ್ಯೆಯಿದೆ ಹಾಗೂ ನೀವು ಫ್ಯಾಕ್ಟರಿ ಡೇಟಾವನ್ನು ಮರುಹೊಂದಿಸುವರೆಗೂ ಅದು ಅಸ್ಥಿರವಾಗಬಹುದು."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಆಂತರಿಕ ಸಮಸ್ಯೆಯಿದೆ. ವಿವರಗಳಿಗಾಗಿ ನಿಮ್ಮ ತಯಾರಕರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index d279b73..f7b8052 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"앱이 Wi-Fi 디스플레이를 설정하고 연결하도록 허용합니다."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Wi-Fi 디스플레이 제어"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"앱이 Wi-Fi 디스플레이의 하위 수준 기능을 제어하도록 허용합니다."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"가상 사설망(VPN) 관리"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"앱에서 가상 사설망(VPN)의 하위 수준 기능을 관리하도록 허용하세요."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"오디오 출력 캡처"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"앱이 오디오 출력을 캡처하고 리디렉션하도록 허용합니다."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"핫워드 감지"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"다음 <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> 알람까지"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"다음 알람까지"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g>에서 알림음 음소거"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"사용 중인 기기 내부에 문제가 발생했습니다. 초기화할 때까지 불안정할 수 있습니다."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"사용 중인 기기 내부에 문제가 발생했습니다. 자세한 내용은 제조업체에 문의하세요."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index 392f790..be5b499 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -728,6 +728,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Колдонмого тууралоолорду жүргүзүп, Wifi-дисплейлерге туташуу уруксатын берет."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Wifi дисплейлерин башкаруу"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Колдонмого Wifi-дисплейлердин төмөнкү деңгээл мүмкүнчүлүктөрүн башкаруу уруксатын берет."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"Виртуалдык жеке тармактарды көзөмөлдөө"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Колдонмо Виртуалдык жеке тармактардын төмөнкү деңгээлдеги мүмкүнчүлүктөрүн көзөмөлдөй алат."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"аудио чыгарылышты жаздыруу"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Колдонмого аудио чыгарылышты жаздырып, аны кайра багыттоо мүмкүнчүлүгүн берет."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Ачкыч сөз таануу"</string>
@@ -2382,4 +2384,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Саат <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> боло турган кийинки айгайга чейин"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Кийинки айгайга чейин"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> тарабынан үнсүздөлдү"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Түзмөгүңүздө ички көйгөй бар жана ал баштапкы абалга кайтарылмайынча туруктуу иштебей коюшу мүмкүн."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Түзмөгүңүздө ички көйгөй бар. Анын чоо-жайын билүү үчүн өндүрүүчүңүзгө кайрылыңыз."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index 94ad1ec..fbb8857 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"ອະນຸຍາດໃຫ້ແອັບຯຕັ້ງຄ່າ ແລະເຊື່ອມຕໍ່ຈໍສະແດງຜົນ WiFi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"ຄວບຄຸມການສະແດງ WiFi"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"ອະນຸຍາດໃຫ້ແອັບຯ ຄວບຄຸມຄວາມສາມາດລະດັບຕໍ່າຂອງການສະແດງຜົນ Wifi."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"ຄວບ​ຄຸມ​ເຄືອ​ຂ່າຍ​ສ່ວນ​ຕົວ​ສະ​ເໝືອນ"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"ອະ​ນຸ​ຍາດ​ໃຫ້​ແອັບ​ຄວບ​ຄຸມ​ຄຸນ​ສົມ​ບັດ​ເຄືອ​ຂ່າຍ​ສ່ວນ​ຕົວ​​ສະ​ເໝືອນລະ​ດັບ​ຕ່ຳ."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"ບັນທຶກສຽງອອກ"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"ອະນຸຍາດໃຫ້ແອັບຯບັນທຶກ ແລະປ່ຽນເສັ້ນທາງການປ້ອນຂໍ້ມູນອອກຂອງສຽງ."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"ການກວດຫາ Hotword"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"​ຈົນ​ກວ່າ​ໂມງ​ປຸກ​ຄັ້ງ​ຕໍ່​ໄປ​ໃນ​ເວ​ລາ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"​ຈົນ​ກວ່າ​ໂມງ​ປຸກ​ຄັ້ງຕໍ່​ໄປ"</string>
     <string name="muted_by" msgid="6147073845094180001">"ຖືກ​ປິດ​ສຽງ​ໂດຍ <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"ມີ​ບັນ​ຫາ​ພາຍ​ໃນ​ກັບ​ອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ, ແລະ​ມັນ​ອາດ​ຈະ​ບໍ່​ສະ​ຖຽນ​ຈົນ​ກວ່າ​ທ່ານ​ຕັ້ງ​ເປັນ​ຂໍ້​ມູນ​ໂຮງ​ງານ​ຄືນ​ແລ້ວ."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"ມີ​ບັນ​ຫາ​ພາຍ​ໃນ​ກັບ​ອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ. ຕິດ​ຕໍ່ຜູ້​ຜະ​ລິດ​ຂອງ​ທ່ານ​ສຳ​ລັບ​ລາຍ​ລະ​ອຽດ​ຕ່າງໆ."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 24b5e01..273ff62 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Leidžiama programai konfigūruoti ir prisijungti prie „Wi-Fi“ pateikčių."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"valdyti „Wi-Fi“ pateiktis"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Leidžiama programai valdyti „Wi-Fi“ pateikčių žemo lygio funkcijas."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"valdyti virtualiuosius privačiuosius tinklus"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Programai leidžiama valdyti pagrindines virtualiųjų privačiųjų tinklų funkcijas."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"fiksuoti garso išvestį"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Programai leidžiama fiksuoti ir peradresuoti garso išvestį."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Aktyvinamųjų žodžių aptikimas"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Iki kito įspėjimo <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Iki kito įspėjimo"</string>
     <string name="muted_by" msgid="6147073845094180001">"Nutildė <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Iškilo vidinė su jūsų įrenginiu susijusi problema, todėl įrenginys gali veikti nestabiliai, kol neatkursite gamyklinių duomenų."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Iškilo vidinė su jūsų įrenginiu susijusi problema. Jei reikia išsamios informacijos, susisiekite su gamintoju."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index ce85173..4c96dd9 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Ļauj lietotnei konfigurēt Wi-Fi displejus un veidot savienojumu ar tiem."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Wi-Fi displeju vadība"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Ļauj lietotnei kontrolēt zema līmeņa funkcijas Wi-Fi displejos."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"Virtuālo privāto tīklu kontrolēšana"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Ļauj lietotnei kontrolēt virtuālo privāto tīklu zema līmeņa funkcijas."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"tvert audio izvadi"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Ļauj lietotnei tvert un novirzīt audio izvadi."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Īsinājumvārda noteikšana"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Līdz nākamajam signālam: <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Līdz nākamajam signālam"</string>
     <string name="muted_by" msgid="6147073845094180001">"Skaņu izslēdza <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Jūsu ierīcē ir radusies iekšēja problēma, un ierīce var darboties nestabili. Lai to labotu, veiciet rūpnīcas datu atiestatīšanu."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Jūsu ierīcē ir radusies iekšēja problēma. Lai iegūtu plašāku informāciju, lūdzu, sazinieties ar ražotāju."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index 78ff999..531b6c1 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Овозможува апликацијата да конфигурира и да се поврзува со Wi-Fi прикази."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"контролирај прикази на Wi-Fi"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Овозможува апликацијата да контролира карактеристики на ниско ниво на Wi-fi прикази."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"Контролирајте виртуелни приватни мрежи"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Дозволува апликацијата да ги контролира функциите на ниско ниво на виртуелните приватни мрежи."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"сними аудио излез"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Овозможува апликацијата да снима и пренасочува аудио излез."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Откривање клучни зборови"</string>
@@ -1904,4 +1906,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"До следниот аларм во <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"До следниот аларм"</string>
     <string name="muted_by" msgid="6147073845094180001">"Звукот го исклучи <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Настана внатрешен проблем со уредот и може да биде нестабилен сè додека не ресетирате на фабричките податоци."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Настана внатрешен проблем со уредот. Контактирајте го производителот за детали."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index 2ab0fa8..0c32045 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"വൈഫൈ ഡിസ്പ്ലേകൾ കോൺഫിഗർ ചെയ്യാനും അതിലേക്ക് കണക്റ്റുചെയ്യാനും അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"വൈഫൈ ഡിസ്‌പ്ലേകൾ നിയന്ത്രിക്കുക"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"വൈഫൈ ഡിസ്‌പ്ലേകളുടെ കുറഞ്ഞ നിലയിലുള്ള സവിശേഷതകൾ നിയന്ത്രിക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"വെർച്വൽ സ്വകാര്യ നെറ്റ്‌വർക്കുകൾ നിയന്ത്രിക്കുക"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"വെർച്വൽ സ്വകാര്യ നെറ്റ്‌വർക്കുകളുടെ താഴ്‌ന്ന നിലയിലുള്ള ഫീച്ചറുകൾ നിയന്ത്രിക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"ഓഡിയോ ഔട്ട്പുട്ട് ക്യാപ്‌ചർ ചെയ്യുക"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"ഓഡിയോ ഔട്ട്‌പുട്ട് ക്യാപ്‌ചർ ചെയ്‌ത് റീഡയറക്‌ടുചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"ഹോട്ട്‌വേഡ് തിരിച്ചറിയൽ"</string>
@@ -1900,4 +1902,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>-നുള്ള അടുത്ത അലാറം വരെ"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"അടുത്ത അലാറം വരെ"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g>, മ്യൂട്ടുചെയ്‌തു"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"നിങ്ങളുടെ ഉപകരണത്തിൽ ഒരു ആന്തരിക പ്രശ്‌നമുണ്ട്, ഫാക്‌ടറി വിവര പുനഃസജ്ജീകരണം ചെയ്യുന്നതുവരെ ഇതു അസ്ഥിരമായിരിക്കാനിടയുണ്ട്."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"നിങ്ങളുടെ ഉപകരണത്തിൽ ഒരു ആന്തരിക പ്രശ്‌നമുണ്ട്. വിശദാംശങ്ങൾക്കായി നിർമ്മാതാവിനെ ബന്ധപ്പെടുക."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index 47fb415..8074a99 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Апп нь Wifi дэлгэцийг тохируулах болон холбогдох боломжтой."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Wifi дэлгэцийг удирдах"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Апп нь Wifi дэлгэцний доод-төвшиний функцийг удирдах боломжтой."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"Виртуал Хувийн Сүлжээнүүдийг удирдах"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Виртуал Хувийн Сүлжээнүүдийн доод түвшний функцүүдийг тус апликейшнээр удирдахыг зөвшөөрдөг."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"аудио гаралтыг барих"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Апп-т аудио гаралтыг барих, дахин чиглүүлэхийг зөвшөөрнө."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Хотворд таних"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> дахь дараагийн анхааруулга хүртэл"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Дараагийн анхааруулга хүртэл"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g>-с хаасан"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Таны төхөөрөмжид дотоод алдаа байна.Та төхөөрөмжөө үйлдвэрээс гарсан төлөвт шилжүүлэх хүртэл таны төхөөрөмж чинь тогтворгүй байж болох юм."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Таны төхөөрөмжид дотоод алдаа байна. Дэлгэрэнгүй мэдээлэл авахыг хүсвэл үйлдвэрлэгчтэйгээ холбоо барина уу."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index f0391dd..1f51ecb 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"वायफाय प्रदर्शने कॉन्फिगर करण्यासाठी आणि त्यावर कनेक्ट करण्यासाठी अॅप ला अनुमती देते."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"वायफाय प्रदर्शने नियंत्रित करा"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"वायफाय प्रदर्शनांची निम्न-स्तर वैशिष्ट्ये नियंत्रित करण्यासाठी अॅप ला अनुमती देते."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"व्हर्च्युअल प्रायव्हेट नेटवर्क नियंत्रित करा"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"अ‍ॅपला व्हर्च्युअल प्रायव्हेट नेटवर्कच्या निम्न-दर्जाच्या वैशिष्‍ट्यांना नियंत्रित करण्‍याची अनुमती देते."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"ऑडिओ आउटपुट कॅप्‍चर करा"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"अ‍ॅपला ऑडिओ आउटपुट कॅप्‍चर करण्‍याची आणि पुनर्निर्देशित करण्‍याची अनुमती देते."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Hotword शोध"</string>
@@ -833,7 +835,7 @@
     <string name="permdesc_handoverStatus" msgid="4788144087245714948">"वर्तमान Android बीम स्थानांतरणांविषयी माहिती प्राप्त करण्यासाठी या अनुप्रयोगास अनुमती देते"</string>
     <string name="permlab_removeDrmCertificates" msgid="7044888287209892751">"DRM प्रमाणपत्रे काढा"</string>
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"DRM प्रमाणपत्रे काढण्यासाठी अनुप्रयोगास अनुमती देते. सामान्य अॅप्स साठी कधीही आवश्यकता नसते."</string>
-    <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"एका वाहक संदेशन सेवेवर प्रतिबद्ध करा"</string>
+    <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"एका वाहक संदेशन सेवेसाठी प्रतिबद्ध"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"वाहक संदेशन सेवेचा शीर्ष-स्तर इंटरफेस प्रतिबद्ध करण्यासाठी होल्डरला अनुमती देते. सामान्‍य अ‍ॅप्‍सकरिता कधीही आवश्‍यक नसते."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"संकेतशब्द नियम सेट करा"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"स्क्रीन-अनलॉक संकेतशब्दांमध्ये अनुमती दिलेली लांबी आणि वर्ण नियंत्रित करा."</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> वाजता पुढील अलार्मपर्यंत"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"पुढील अलार्मपर्यंत"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> द्वारे नि:शब्द केले"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"आपल्‍या डिव्‍हाइसमध्‍ये अंतर्गत समस्‍या आहे आणि आपला फॅक्‍टरी डेटा रीसेट होईपर्यंत ती अस्‍थिर असू शकते."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"आपल्‍या डिव्‍हाइसमध्‍ये अंतर्गत समस्‍या आहे. तपशीलांसाठी आपल्‍या निर्मात्याशी संपर्क साधा."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 1a295d2..01d1bbb 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Membenarkan apl mengkonfigurasi dan menyambung ke paparan Wifi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"kawal paparan Wifi"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Membenarkan apl mengawal ciri tahap rendah paparan Wifi."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"kawal Rangkaian Peribadi Maya"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Membenarkan apl mengawal ciri tahap rendah Rangkaian Peribadi Maya."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"tangkap output audio"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Membenarkan apl menangkap dan mengubah hala output audio."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Pengesanan sebutan laluan"</string>
@@ -834,7 +836,7 @@
     <string name="permlab_removeDrmCertificates" msgid="7044888287209892751">"alih keluar sijil DRM"</string>
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Membenarkan aplikasi mengalih keluar sijil DRM. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"terikat kepada perkhidmatan pemesejan pembawa"</string>
-    <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan pemesejan pembawa. Tidak sekali-kali diperlukan untuk apl biasa."</string>
+    <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi perkhidmatan pemesejan pembawa. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Tetapkan peraturan kata laluan"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Mengawal panjang dan aksara yang dibenarkan dalam kata laluan buka kunci skrin."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Memantau percubaan buka kunci skrin"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Sehingga penggera seterusnya pada <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Sehingga penggera seterusnya"</string>
     <string name="muted_by" msgid="6147073845094180001">"Diredam oleh <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Terdapat masalah dalaman dengan peranti anda. Peranti mungkin tidak stabil sehingga anda membuat tetapan semula data kilang."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Terdapat masalah dalaman dengan peranti anda. Hubungi pengilang untuk mengetahui butirannya."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index 2beba37..c2ea4bd 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"အပလီကေးရှင်းအား ဝိုင်ဖိုင်မှ တဆင့် ပြသမှုအား ပြင်ဆင်ခြင်း၊ ဆက်သွယ်ခြင်း ခွင့်ပြုပါ"</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"ဝိုင်ဖိုင်ဖြင့် ပြသမှု အား ထိန်းချုပ်ရန်"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"အပလီကေးရှင်းအား စက်ရဲ့ အနိမ့်ပိုင်းမှာ ရှိသော ဝိုင်ဖိုင် ပြသမှုအား ထိန်းချုပ်ခွင့်ပြုပါ"</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"ကိုယ်ပိုင်ကွန်ယက်အတုကို ထိန်းချုပ်ရန်"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"ကိုယ်ပိုင်ကွန်ယက်အတု၏ အရည်အသွေးနိမ့်လုပ်ဆောင်ချက်များကို ထိန်းချုပ်ရန် app အား ခွင့်ပြုပါ။"</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"အသံထွက်မှု အား ဖမ်းယူခြင်း"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"အပလီကေးရှင်းကို အသံဖမ်းခွင့် လမ်းကြောင်းလွှဲခွင့်များ ခွင့်ပြုခြင်း"</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"အသံဖြင့်ညွှန်ကြားရန်အတိုကောက်များအား ဖမ်းယူ သိနိုင်မှု"</string>
@@ -1900,4 +1902,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"နောက်ထပ် <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> ၌နိုးစက်အထိ"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"နောက်ထပ်နိုးစက်အထိ"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> အသံပိတ်သည်"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"သင့်ကိရိယာအတွင်းပိုင်းတွင် ပြဿနာရှိနေပြီး၊ မူလစက်ရုံထုတ်အခြေအနေအဖြစ် ပြန်လည်ရယူနိုင်သည်အထိ အခြေအနေမတည်ငြိမ်နိုင်ပါ။"</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"သင့်ကိရိယာအတွင်းပိုင်းတွင် ပြဿနာရှိနေ၏။ အသေးစိတ်သိရန်အတွက် ပစ္စည်းထုတ်လုပ်သူအား ဆက်သွယ်ပါ။"</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index e2c8f05..101f201 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Tillater appen å konfigurere og koble til Wi-Fi-skjermer."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"kontrollere Wi-Fi-skjermer"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Tillater appen å kontrollere lavnivåfunksjoner i Wi-Fi-skjermer."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"kontrollér virtuelle private nettverk"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Lar appen kontrollere de grunnleggende funksjonene for virtuelle private nettverk."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"ta opp fra lydutdata"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Lar appen ta opp og omdirigere lydutdata."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Gjenkjennelse av kommandoord"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Inntil neste alarm kl. <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Inntil neste alarm"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> har kuttet lyden"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Det har oppstått et internt problem på enheten din, og den kan være ustabil til du tilbakestiller den til fabrikkdata."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Det har oppstått et internt problem på enheten din. Ta kontakt med produsenten for mer informasjon."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index 168e5f2..c8193c2 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"अनुप्रयोगलाई कन्फिगर गर्न र वाइफाइ प्रदर्शनहरूसँग जोड्न अनुमति दिन्छ।"</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"वाइफाइ प्रदर्शनहरू नियन्त्रण गर्नुहोस्"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"वाइफाइ प्रदर्शनीका तल्लो तह विषेशताहरू नियन्त्रण गर्न अनुप्रयोगलाई अनुमति दिन्छ।"</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"भर्चुअल निजी नेटवर्कलाई नियन्त्रण गर्छ"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"भर्चुअल निजी नेटवर्कहरूको कम-स्तर सुविधाहरू नियन्त्रण गर्न एपलाई अनुमति दिन्छ।"</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"अडियो आउटपुट कैद गर्नुहोस्"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"अनुप्रयोगलाई अडियो आउटपुट कैद गर्न र रिडाइरेक्ट गर्न अनुमति दिन्छ।"</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Hotword पत्ता लगाउने कार्य"</string>
@@ -1910,4 +1912,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> मा अर्को अलार्म सम्म"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"अर्को अलार्म सम्म"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> द्वारा मौन गरिएको"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"तपाईंको यन्त्रसँग आन्तरिक समस्या छ, र तपाईंले फ्याक्ट्री डाटा रिसेट नगर्दासम्म यो अस्थिर रहन्छ।"</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"तपाईंको यन्त्रसँग आन्तरिक समस्या छ। विवरणहरूको लागि आफ्नो निर्मातासँग सम्पर्क गर्नुहोस्।"</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index c5e70bd..668d7b0 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"De app toestaan wifi-displays te configureren en hiermee verbinding te maken."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"wifi-displays beheren"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"De app toestaan minder belangrijke functies van wifi-displays te beheren."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"VPN\'s (Virtual Private Networks) beheren"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Hiermee kan de app VPN-functies (Virtual Private Networks) op laag niveau beheren."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"audio-uitvoer vastleggen"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Hiermee kan de app audio-uitvoer vastleggen en verwerken."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Detectie van hotwords"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Tot het volgende alarm om <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Tot het volgende alarm"</string>
     <string name="muted_by" msgid="6147073845094180001">"Gedempt door <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Er is een intern probleem met uw apparaat. Het apparaat kan instabiel zijn totdat u het apparaat terugzet naar de fabrieksinstellingen."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Er is een intern probleem met uw apparaat. Neem contact op met de fabrikant voor meer informatie."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index f50ab9b..83303b7 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Zezwala aplikacji na konfigurację wyświetlaczy Wi-Fi i łączenie z nimi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"zarządzanie wyświetlaczami Wi-Fi"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Zezwala aplikacji na zarządzanie niskopoziomowymi funkcjami wyświetlaczy Wi-Fi."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"kontrola nad wirtualnymi sieciami prywatnymi (VPN)"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Zezwala aplikacji na kontrolę nad niskopoziomowymi funkcjami wirtualnych sieci prywatnych (VPN)."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"przechwyć wyjście audio"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Zezwala aplikacji na przechwytywanie i przekierowywanie wyjścia audio."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Wykrywanie słów-kluczy"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Do następnego alarmu o <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Do następnego alarmu"</string>
     <string name="muted_by" msgid="6147073845094180001">"Ściszone przez: <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"W Twoim urządzeniu wystąpił problem wewnętrzny. Może być ono niestabilne, dopóki nie przywrócisz danych fabrycznych."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"W Twoim urządzeniu wystąpił problem wewnętrzny. Skontaktuj się z jego producentem, by otrzymać szczegółowe informacje."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 16385b4..b1ebcc9 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Permite que a aplicação se configure e se ligue a visores Wi-Fi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"controlar visores Wi-Fi"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permite que a aplicação controle funcionalidades de baixo nível em visores Wi-Fi."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"controlar Redes privadas virtuais"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Permite que a aplicação controle funcionalidades de baixo nível de Redes privadas virtuais"</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"capturar saída de áudio"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Permite à aplicação capturar e redirecionar a saída de áudio."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Deteção de palavra de ativação"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Até ao próximo alarme, às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Até ao próximo alarme"</string>
     <string name="muted_by" msgid="6147073845094180001">"Som desativado por <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Existe um problema interno no seu dispositivo e pode ficar instável até efetuar uma reposição de dados de fábrica."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Existe um problema interno no seu dispositivo. Contacte o fabricante para obter mais informações."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 92143b9..00b82be 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Permite que o app configure e conecte a monitores Wi-Fi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"controlar monitores Wi-Fi"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permite que o app controle recursos de baixo nível de monitores Wi-Fi."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"controlar Redes Privadas Virtuais"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Permite que o app controle os recursos de nível inferior das Redes Privadas Virtuais."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"capturar saída de áudio"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Permite que o app capture e redirecione a saída de áudio."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Detecção de hotwords"</string>
@@ -795,14 +797,10 @@
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Permite que o app leia e grave o sistema de arquivos cache."</string>
     <string name="permlab_use_sip" msgid="2052499390128979920">"fazer/receber chamadas SIP"</string>
     <string name="permdesc_use_sip" msgid="2297804849860225257">"Permite que o app faça e receba chamadas SIP."</string>
-    <!-- no translation found for permlab_register_sim_subscription (3166535485877549177) -->
-    <skip />
-    <!-- no translation found for permdesc_register_sim_subscription (2138909035926222911) -->
-    <skip />
-    <!-- no translation found for permlab_register_call_provider (108102120289029841) -->
-    <skip />
-    <!-- no translation found for permdesc_register_call_provider (7034310263521081388) -->
-    <skip />
+    <string name="permlab_register_sim_subscription" msgid="3166535485877549177">"registrar novas conexões SIM de telecomunicações"</string>
+    <string name="permdesc_register_sim_subscription" msgid="2138909035926222911">"Permite que o app registre novas conexões SIM de telecomunicações."</string>
+    <string name="permlab_register_call_provider" msgid="108102120289029841">"registrar novas conexões de telecomunicações"</string>
+    <string name="permdesc_register_call_provider" msgid="7034310263521081388">"Permite que o app registre novas conexões de telecomunicações."</string>
     <string name="permlab_connection_manager" msgid="1116193254522105375">"gerenciar conexões de telecomunicações"</string>
     <string name="permdesc_connection_manager" msgid="5925480810356483565">"Permite que o app gerencie conexões de telecomunicações."</string>
     <string name="permlab_bind_incall_service" msgid="6773648341975287125">"interagir com chamada na tela"</string>
@@ -1906,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Até o próximo alarme em <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Até o próximo alarme"</string>
     <string name="muted_by" msgid="6147073845094180001">"Som desativado por <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Há um problema interno com seu dispositivo. Ele pode ficar instável até que você faça a redefinição para configuração original."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Há um problema interno com seu dispositivo. Entre em contato com o fabricante para saber mais detalhes."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 70f3b49..57e72a8 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Permite aplicaţiei să configureze şi să se conecteze la afişaje Wi-Fi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"controlează afişaje Wi-Fi"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permite aplicaţiei să controleze funcţiile de nivel redus ale afişajelor Wi-Fi."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"controlează rețelele private virtuale"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Permite aplicației să controleze funcțiile de nivel inferior ale rețelelor private virtuale."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"să intercepteze ieșirea audio"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Permite aplicației să intercepteze și să redirecționeze ieșirea audio."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"detectarea expresiei de activare"</string>
@@ -834,7 +836,7 @@
     <string name="permlab_removeDrmCertificates" msgid="7044888287209892751">"eliminarea certificatelor DRM"</string>
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Permite unei aplicații să elimine certificatele DRM. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"se conectează la un serviciu de mesagerie oferit de operator"</string>
-    <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu de mesagerie oferit de operator. Nu ar trebui să fie niciodată necesară pentru aplicațiile obișnuite."</string>
+    <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Permite aplicației să se conecteze la interfața de nivel superior a unui serviciu de mesagerie oferit de operator. Nu ar trebui să fie niciodată necesară pentru aplicațiile obișnuite."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Setaţi reguli pentru parolă"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Stabiliţi lungimea şi tipul de caractere permise în parolele pentru deblocarea ecranului."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitorizaţi încercările de deblocare a ecranului"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Până la alarma următoare, la <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Până la alarma următoare"</string>
     <string name="muted_by" msgid="6147073845094180001">"Dezactivate de <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"A apărut o problemă internă pe dispozitiv, iar acesta poate fi instabil până la revenirea la setările din fabrică."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"A apărut o problemă internă pe dispozitiv. Pentru detalii, contactați producătorul."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 18fc49f..768b071 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Приложение сможет подключаться к экранам с помощью Wi-Fi и настраивать их."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Управление мониторами, подключенными через Wi-Fi"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Приложение сможет управлять низкоуровневыми функциями экранов, подключенных через Wi-Fi."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"управление виртуальными частными сетями"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Управление низкоуровневыми функциями виртуальных частных сетей."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"захват аудиосигнала"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Приложение сможет захватывать и перенаправлять аудиосигнал."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"распознавать голосовые команды"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"До следующего будильника в <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"До следующего будильника"</string>
     <string name="muted_by" msgid="6147073845094180001">"Звук отключен приложением \"<xliff:g id="THIRD_PARTY">%1$s</xliff:g>\""</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Произошла внутренняя ошибка, и устройство может работать нестабильно, пока вы не выполните сброс настроек."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Произошла внутренняя ошибка. Обратитесь к производителю устройства за подробными сведениями."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index af76b0f..3460606 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"වින්‍යාස කිරීමට සහ Wifi සංදර්ශක වෙත සම්බන්ධ වීමට යෙදුමට අවසර දෙන්න."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Wifi සංදර්ශක පාලනය"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Wifi සංදර්ශකයේ පහළ මට්ටමේ විශේෂාංග පාලනයට යෙදුමට අවසර දෙන්න."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"අතථ්‍ය පුද්ගලික ජාල පාලනය කරන්න"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"යෙදුමට අතථ්‍ය පුද්ගලික ජාලවල පහළ-මට්ටම් විශේෂාංග පාලනය කිරීමට ඉඩ දෙයි."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"ශබ්ද ප්‍රතිදානය ග්‍රහණය"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"යෙදුමට ශබ්ද ප්‍රතිදානය ග්‍රහණය කර හරවා යැවීමට ඉඩ දේ."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Hotword හදුනා ගැනීම"</string>
@@ -1904,4 +1906,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> හි ඊළඟ සීනුව තෙක්"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"ඊළඟ සීනුව තෙක්"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> විසින් නිශ්ශබ්ද කරන ලදි"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"ඔබේ උපාංගය සමගින් ගැටලුවක් ඇති අතර, ඔබේ කර්මාන්තශාලා දත්ත යළි සකසන තෙක් එය අස්ථායි විය හැකිය."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"ඔබේ උපාංගය සමගින් අභ්‍යන්තර ගැටලුවක් ඇත. විස්තර සඳහා ඔබේ නිෂ්පාදක අමතන්න."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index f42a7dc..d29ef6b 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Umožňuje aplikácii konfigurovať displeje a pripojiť sa k nim cez siete Wi-Fi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"ovládať displeje cez sieť Wi-Fi"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Umožňuje aplikácii ovládať základné funkcie displejov cez siete Wi-Fi."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"ovládanie virtuálnych súkromných sietí"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Umožňuje aplikáciám ovládať funkcie nízkej úrovne virtuálnych súkromných sietí."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"zachytiť výstup zvuku"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Umožňuje aplikácii zachytiť a presmerovať výstup zvuku."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Rozpoznanie kľúčových slov"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Do ďalšieho budíka o <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Do ďalšieho budíka"</string>
     <string name="muted_by" msgid="6147073845094180001">"Stlmené aplikáciou <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Vo vašom zariadení došlo k internému problému. Môže byť nestabilné, kým neobnovíte jeho továrenské nastavenia."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Vo vašom zariadení došlo k internému problému. Ak chcete získať podrobné informácie, obráťte sa na jeho výrobcu."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index ba85bde..8880265 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Omogoča aplikaciji konfiguriranje zaslonov Wi-Fi in povezovanje z njimi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"nadzor zaslonov Wi-Fi"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Omogoča aplikaciji nadzor osnovnih funkcij zaslonov Wi-Fi."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"upravljanje navideznih zasebnih omrežij"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Aplikaciji omogoča upravljanje funkcij nizke ravni navideznih zasebnih omrežij."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"zajem avdioizhoda"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Omogoči aplikaciji, da zajame in preusmeri avdioizhod."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Zaznavanje sprožilnih besed"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Do naslednjega alarma ob <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Do naslednjega alarma"</string>
     <string name="muted_by" msgid="6147073845094180001">"Izklop zvoka: <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Vaša naprava ima notranjo napako in bo morda nestabilna, dokler je ne ponastavite na tovarniške nastavitve."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Vaša naprava ima notranjo napako. Če želite več informacij, se obrnite na proizvajalca."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 108b99d..e91a58b 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Дозвољава апликацији да конфигурише Wi-Fi екране и повезује се са њима."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"контрола Wi-Fi екрана"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Дозвољава апликацији да контролише функције Wi-Fi екрана ниског нивоа."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"контролиши виртуелне приватне мреже"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Дозвољава апликацији да контролише функције ниског нивоа виртуелних приватних мрежа."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"снимање аудио садржаја"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Дозвољава апликацији да снима и преусмерава аудио садржај."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Откривање актуелних речи"</string>
@@ -987,10 +989,10 @@
     <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Број за хитне случајеве"</string>
     <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Нема услуге."</string>
     <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Екран је закључан."</string>
-    <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Притисните „Мени“ да бисте откључали телефон или упутите хитни позив."</string>
+    <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Притисните „Мени“ да бисте откључали телефон или упутите хитан позив."</string>
     <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Притисните „Мени“ за откључавање."</string>
     <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Унесите шаблон за откључавање"</string>
-    <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Хитни позив"</string>
+    <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Хитан позив"</string>
     <string name="lockscreen_return_to_call" msgid="5244259785500040021">"Назад на позив"</string>
     <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Тачно!"</string>
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Покушајте поново"</string>
@@ -1640,7 +1642,7 @@
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Нема више 4G података"</string>
     <string name="data_usage_mobile_limit_title" msgid="557158376602636112">"Нема више подат. за мобил. уређ."</string>
     <string name="data_usage_wifi_limit_title" msgid="5803363779034792676">"Нема више Wi-Fi података"</string>
-    <string name="data_usage_limit_body" msgid="291731708279614081">"Нема података до краја циклуса"</string>
+    <string name="data_usage_limit_body" msgid="291731708279614081">"Потрошили сте податке за овај месец"</string>
     <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"Прекорачен пренос 2G-3G података"</string>
     <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"Прекорачење преноса 4G података"</string>
     <string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"Ограничење мобилних података је прекорачено"</string>
@@ -1698,7 +1700,7 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Постављени елемент бр. <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>×<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", безбедно"</string>
-    <string name="kg_emergency_call_label" msgid="684946192523830531">"Хитни позив"</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Хитан позив"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Заборављени шаблон"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Погрешан шаблон"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Погрешна лозинка"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"До следећег аларма у <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"До следећег аларма"</string>
     <string name="muted_by" msgid="6147073845094180001">"Звук је искључио/ла <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Дошло је до интерног проблема у вези са уређајем и можда ће бити нестабилан док не обавите ресетовање на фабричка подешавања."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Дошло је до интерног проблема у вези са уређајем. Потражите детаље од произвођача."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index abbf28a..2023f5a 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Tillåter att appen konfigurerar och ansluter till Wi-Fi-skärmar."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"kontrollerar Wi-Fi-skärmar"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Tillåter att appen kontrollerar grundläggande funktioner för Wi-Fi-skärmar."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"styra virtuella privata nätverk"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Tillåter att appen styr grundläggande funktioner i virtuella privata nätverk."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"fånga upp ljudutgång"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Tillåt att appen fångar upp och omdirigerar ljudutgången."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Kommandoordsidentifiering"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Till nästa alarm kl. <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Till nästa alarm"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> har stängt av ljudet"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Ett internt problem har uppstått i enheten, och det kan hända att problemet kvarstår tills du återställer standardinställningarna."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Ett internt problem har uppstått i enheten. Kontakta tillverkaren om du vill veta mer."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 2e265c9..b9237ce 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Inaruhusu programu kusanidi na kuunganika kwenye maonyesho ya Wifi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"dhibiti maonyesho ya Wifi"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Inaruhusu programu kudhibiti vipengele vya kiwango cha chini vya maonyesho ya Wifi."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"dhibiti Virtual Private Networks"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Huruhusu programu kudhibiti vipengele vya viwango vya chini vya Virtual Private Networks."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"nasa sauti"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Inaruhusu programu kunasa na kuelekeza sauti kwingine."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Kutambua neno tekelezi"</string>
@@ -1700,7 +1702,7 @@
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", salama"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Simu ya dharura"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Umesahau Ruwaza"</string>
-    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Mchoro Usio sahihi"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Mchoro huo si sahihi"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Nenosiri Lisilo sahihi"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Nambari ya PIN si sahihi"</string>
     <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Jaribu tena baada ya sekunde <xliff:g id="NUMBER">%1$d</xliff:g>."</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Hadi kengele inayofuata saa <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Hadi kengele inayofuata"</string>
     <string name="muted_by" msgid="6147073845094180001">"Sauti imezimwa na <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Kuna hitilafu ya ndani ya kifaa chako, na huenda kisiwe thabiti mpaka urejeshe mipangilio ya kiwandani."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Kuna hitilafu ya ndani ya kifaa chako. Wasiliana na mtengenezaji wa kifaa chako kwa maelezo."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index 4c8c97a..809d354 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Wifi காட்சிகளை உள்ளமைத்து அவற்றுடன் இணையப் பயன்பாட்டை அனுமதிக்கிறது."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Wifi காட்சிகளைக் கட்டுப்படுத்துதல்"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Wifi காட்சிகளில் கீழ்-நிலை அம்சங்களைக் கட்டுப்படுத்தப் பயன்பாட்டை அனுமதிக்கிறது."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"மெய்நிகர் தனியார் பிணையங்களைக் கட்டுப்படுத்துதல்"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"மெய்நிகர் தனியார் பிணையங்களின் குறை-நிலை அம்சங்களைக் கட்டுப்படுத்த பயன்பாட்டை அனுமதிக்கும்."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"ஆடியோ வெளியீட்டைப் பதிவுசெய்தல்"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"ஆடியோ வெளியீட்டைப் பதிவுசெய்ய மற்றும் திசைதிருப்ப பயன்பாட்டை அனுமதிக்கிறது."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"குறிப்பிட்ட சொல்லைக் கண்டறிதல்"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>க்கு ஒலிக்கும் அடுத்த அலாரம் வரை"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"அடுத்த அலாரம் வரை"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> ஒலியடக்கினார்"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"சாதனத்தில் அகச் சிக்கல் இருக்கிறது, அதனை ஆரம்பநிலைக்கு மீட்டமைக்கும் வரை நிலையற்று இயங்கலாம்."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"சாதனத்தில் அகச் சிக்கல் இருக்கிறது. விவரங்களுக்கு சாதன தயாரிப்பாளரைத் தொடர்புகொள்ளவும்."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index 104c052..a1b28e3 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"వైఫై డిస్‌ప్లేలను కాన్ఫిగర్ చేయడానికి మరియు వాటికి కనెక్ట్ చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"వైఫై డిస్‌ప్లేలను నియంత్రించడం"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"వైఫై డిస్‌ప్లేల యొక్క తక్కువ-స్థాయి లక్షణాలను నియంత్రించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"వర్చువల్ ప్రైవేట్ నెట్‌వర్క్‌లను నియంత్రించడం"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"వర్చువల్ ప్రైవేట్ నెట్‌వర్క్‌ల తక్కువ-స్థాయి లక్షణాలను నియంత్రించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"ఆడియో అవుట్‌పుట్‌ను క్యాప్చర్ చేయడం"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"ఆడియో అవుట్‌పుట్‌ను క్యాప్చర్ చేసి, దారి మళ్లించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"హాట్‌వర్డ్ గుర్తింపు"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>కి సెట్ చేసిన తదుపరి అలారం వరకు"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"తదుపరి అలారం వరకు"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> ద్వారా మ్యూట్ చేయబడింది"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"మీ పరికరంతో అంతర్గత సమస్య ఏర్పడింది మరియు మీరు ఫ్యాక్టరీ డేటా రీసెట్ చేసే వరకు అస్థిరంగా ఉంటుంది."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"మీ పరికరంతో అంతర్గత సమస్య ఏర్పడింది. వివరాల కోసం మీ తయారీదారుని సంప్రదించండి."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 7455f84..852054f 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"อนุญาตให้แอปกำหนดค่าและเชื่อมต่อกับจอแสดงผล WiFi ได้"</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"ควบคุมการแสดงผลด้วย WiFi"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"อนุญาตให้แอปควบคุมคุณลักษณะต่างๆ ในระดับล่างของการแสดงผลด้วย WiFi"</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"ควบคุมเครือข่ายส่วนตัวเสมือน"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"อนุญาตให้แอปควบคุมคุณลักษณะระดับต่ำของเครือข่ายส่วนตัวเสมือน"</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"บันทึกเอาต์พุตเสียง"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"อนุญาตให้แอปบันทึกและเปลี่ยนเส้นทางเอาต์พุตเสียง"</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"การตรวจหาคำที่นิยม"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"จนถึงการตั้งปลุกครั้งถัดไปในเวลา <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"จนถึงการตั้งปลุกครั้งถัดไป"</string>
     <string name="muted_by" msgid="6147073845094180001">"ปิดเสียงโดย <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"เกิดปัญหาภายในกับอุปกรณ์ของคุณ อุปกรณ์อาจทำงานไม่เสถียรจนกว่าคุณจะรีเซ็ตข้อมูลเป็นค่าเริ่มต้น"</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"เกิดปัญหาภายในกับอุปกรณ์ของคุณ โปรดติดต่อผู้ผลิตสำหรับรายละเอียดเพิ่มเติม"</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index a2f793a..5a4063f 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Pinapayagan ang app na mag-configure at kumonekta sa mga Wifi display."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"magkontrol ng mga Wifi display"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Pinapayagan ang app na magkontrol ng mga tampok sa mababang antas ng mga dispay ng Wifi."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"kontrolin ang mga Virtual Private Network"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Nagbibigay-daan sa app na kontrolin ang mga nasa mababang antas na feature ng mga Virtual Private Network."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"kumuha ng audio output"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Pinapayagan ang app na kumuha at mag-redirect ng audio output."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Paghahanap ng hotword"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Hanggang sa susunod na alarma sa <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Hanggang sa susunod na alarma"</string>
     <string name="muted_by" msgid="6147073845094180001">"Na-mute ng <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"May internal na problema sa iyong device, at maaaring hindi ito maging stable hanggang sa i-reset mo ang factory data."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"May internal na problema sa iyong device. Makipag-ugnayan sa iyong manufacturer upang malaman ang mga detalye."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index dd95ce9..45cac47 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Uygulamaya kablosuz ekranları yapılandırma ve bunlara bağlanma izni verir."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Kablosuz ekranları denetle"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Uygulamaya kablosuz ekranların alt düzey özelliklerini kontrol etme izni verir."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"Sanal Özel Ağları denetle"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Uygulamaya, Sanal Özel Ağların düşük seviye özelliklerini denetleme izni verir."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"ses çıkışını yakala"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Uygulamaya, ses çıkışını yakalayıp yönlendirme izni verir."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Özel kelime algılama"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> saatindeki bir sonraki alarma kadar"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Bir sonraki alarma kadar"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> tarafından kapatıldı"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Cihazınızla ilgili dahili bir sorun oluştu ve fabrika verilerine sıfırlama işlemi gerçekleştirilene kadar kararsız çalışabilir."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Cihazınızla ilgili dahili bir sorun oluştu. Ayrıntılı bilgi için üreticinizle iletişim kurun."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index e3b34b1..591bc2a 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Дозволяє програмі налаштовувати екрани Wi-Fi і під’єднуватися до них."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"керувати екранами Wi-Fi"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Дозволяє програмі керувати низькорівневими функціями екранів Wi-Fi."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"керування віртуальними приватними мережами"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Додаток може керувати низькорівневими функціями віртуальних приватних мереж."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"отримувати доступ до аудіовиходу"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Дозволяє програмі отримувати доступ до аудіовиходу й переспрямовувати його."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"виявляти команди швидкого запуску"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"До наступного сигналу о <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"До наступного сигналу"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> вимикає звук"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Через внутрішню помилку ваш пристрій може працювати нестабільно. Відновіть заводські налаштування."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"На пристрої сталася внутрішня помилка. Зв’яжіться з виробником пристрою, щоб дізнатися більше."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index 39657de..bf8c64f 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"‏ایپ کو Wifi ڈسپلیز کے ساتھ ترتیب دینے اور مربوط کرنے کی اجازت دیتا ہے۔"</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"‏Wifi ڈسپلیز کنٹرول کریں"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"‏ایپ کو Wifi ڈسپلیز کی کم سطح والی خصوصیات کو کنٹرول کرنے کی اجازت دیتا ہے۔"</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"ورچوئل نجی نیٹ ورکس کو کنٹرول کریں"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"ایپ کو ورچوئل نجی نیٹ ورکس کی کم سطحی خصوصیات کو کنٹرول کرنے کی اجازت دیتی ہے۔"</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"آڈیو آؤٹ پٹ کیپچر کریں"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"ایپ کو آڈیو آؤٹ پٹ کو کیپچر کرنے اور ری ڈائریکٹ کرنے کی اجازت دیتا ہے۔"</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"ہاٹ ورڈ کا پتہ لگانا"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"اگلے الارم تک بوقت <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"اگلے الارم تک"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> کے ذریعے خاموش کردہ"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"آپ کے آلہ میں ایک داخلی مسئلہ ہے اور جب تک آپ فیکٹری ڈیٹا کو دوبارہ ترتیب نہیں دے دیتے ہیں، ہوسکتا ہے کہ یہ غیر مستحکم رہے۔"</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"آپ کے آلہ میں ایک داخلی مسئلہ ہے۔ تفصیلات کیلئے اپنے مینوفیکچرر سے رابطہ کریں۔"</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index 0c5c83f..c6f44e8 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Ilovaga Wifi ekranlarini sozlashga va ularga ulanishga ruxsat beradi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Wifi ekranlarini boshqarish"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Ilovaga Wifi ekranlarining past darajali xususiyatlarini boshqarishga ruxsat beradi."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"virtual xususiy tarmoqlarni (VPN) boshqarish"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Ilovaga virtual xususiy tarmoqlarning (VPN) quyi darajali funksiyalarini boshqarish uchun ruxsat beradi."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"audio chiqishni yozib olish"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Dasturga ovoz lavhasini yozib olib, qayta yo‘llashga ruxsat beradi."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Hotword aniqlash"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Keyingi uyg‘otkich vaqtigacha (<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>)"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Keyingi uyg‘otkich vaqtigacha"</string>
     <string name="muted_by" msgid="6147073845094180001">"“<xliff:g id="THIRD_PARTY">%1$s</xliff:g>” tomonidan ovozsiz qilingan"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Qurilmangiz bilan bog‘liq ichki muammo mavjud. U zavod sozlamalari tiklanmaguncha barqaror ishlamasligi mumkin."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Qurilmangiz bilan bog‘liq ichki muammo mavjud. Tafsilotlar uchun qurilmangiz ishlab chiqaruvchisiga murojaat qiling."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index c088e68..c9ded6d 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Cho phép ứng dụng định cấu hình và kết nối với màn hình Wi-Fi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"kiểm soát màn hình Wi-Fi"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Cho phép ứng dụng kiểm soát các tính năng cấp thấp của màn hình Wi-Fi."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"kiểm soát Mạng riêng ảo"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Cho phép ứng dụng kiểm soát các tính năng cấp thấp của Mạng riêng ảo."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"thu thập dữ liệu đầu ra âm thanh"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Cho phép ứng dụng thu thập và chuyển hướng dữ liệu đầu ra âm thanh."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Phát hiện từ nóng"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Cho đến lần báo thức tiếp theo vào <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Cho đến lần báo thức tiếp theo"</string>
     <string name="muted_by" msgid="6147073845094180001">"Do <xliff:g id="THIRD_PARTY">%1$s</xliff:g> tắt tiếng"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Đã xảy ra sự cố nội bộ với thiết bị của bạn và thiết bị có thể sẽ không ổn định cho tới khi bạn thiết lập lại dữ liệu ban đầu."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Đã xảy ra sự cố nội bộ với thiết bị. Hãy liên hệ với nhà sản xuất của bạn để biết chi tiết."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 1b4aad1..54040d6 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -564,6 +564,10 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"允许应用配置并连接到WLAN显示设备。"</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"控制WLAN显示设备"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"允许应用控制WLAN显示设备的基础功能。"</string>
+    <!-- no translation found for permlab_controlVpn (2618442789397588200) -->
+    <skip />
+    <!-- no translation found for permdesc_controlVpn (762852603315861214) -->
+    <skip />
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"捕获音频输出"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"允许该应用捕获和重定向音频输出。"</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"启动指令检测"</string>
@@ -833,10 +837,8 @@
     <string name="permdesc_handoverStatus" msgid="4788144087245714948">"允许此应用接收Android Beam当前传输内容的相关信息"</string>
     <string name="permlab_removeDrmCertificates" msgid="7044888287209892751">"移除DRM证书"</string>
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"允许应用移除DRM证书。普通应用绝不需要此权限。"</string>
-    <!-- no translation found for permlab_bindCarrierMessagingService (1490229371796969158) -->
-    <skip />
-    <!-- no translation found for permdesc_bindCarrierMessagingService (2762882888502113944) -->
-    <skip />
+    <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"绑定到运营商消息传递服务"</string>
+    <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"允许应用绑定到运营商消息传递服务的顶级接口。普通应用绝不需要此权限。"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"设置密码规则"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"控制屏幕解锁密码所允许的长度和字符。"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"监视屏幕解锁尝试次数"</string>
@@ -1904,4 +1906,20 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"到下次闹钟时间(<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>)"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"到下次闹钟时间"</string>
     <string name="muted_by" msgid="6147073845094180001">"已被<xliff:g id="THIRD_PARTY">%1$s</xliff:g>设为静音"</string>
+    <!-- no translation found for system_error_wipe_data (6608165524785354962) -->
+    <skip />
+    <!-- no translation found for system_error_manufacturer (8086872414744210668) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 1759445..8e888da 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"允許應用程式設定及連接 WiFi Display。"</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"控制 WiFi Display"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"允許應用程式控制 WiFi Display 的低階功能。"</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"控制虛擬私人網絡"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"允許應用程式控制虛擬私人網絡的低層級功能。"</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"擷取音頻輸出"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"允許應用程式擷取及重新導向音頻輸出。"</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"啟動字詞偵測"</string>
@@ -833,8 +835,8 @@
     <string name="permdesc_handoverStatus" msgid="4788144087245714948">"允許應用程式接收 Android Beam 目前傳送的資料"</string>
     <string name="permlab_removeDrmCertificates" msgid="7044888287209892751">"移除 DRM 憑證"</string>
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"允許應用程式移除 DRM 憑證 (一般應用程式並不需要)。"</string>
-    <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"綁定到流動網絡供應商短訊服務"</string>
-    <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"允許持有人綁定到流動網絡供應商短訊服務頂層介面 (一般應用程式不需要)。"</string>
+    <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"繫結至流動網絡供應商短訊服務"</string>
+    <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"允許應用程式繫結至流動網絡供應商短訊服務的頂層介面 (不建議一般應用程式使用)。"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"設定密碼規則"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"控制螢幕解鎖密碼所允許的長度和字元。"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"監控螢幕解鎖嘗試次數"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"直到下一個在 <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> 的鬧鐘"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"直到下一個鬧鐘"</string>
     <string name="muted_by" msgid="6147073845094180001">"靜音設定者:<xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"您裝置的系統發生問題,回復原廠設定後即可解決該問題。"</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"您裝置的系統發生問題,請聯絡您的製造商瞭解詳情。"</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index cde2929..bccdd48 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"允許應用程式設定及連接 Wi-Fi 顯示裝置。"</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"控制 Wi-Fi 顯示裝置"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"允許應用程式控制 Wi-Fi 顯示裝置的低階功能。"</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"控制虛擬私人網路"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"允許應用程式控制虛擬私人網路的低階功能。"</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"擷取音訊輸出"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"允許應用程式擷取及重新導向音訊輸出。"</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"啟動字詞偵測"</string>
@@ -833,8 +835,8 @@
     <string name="permdesc_handoverStatus" msgid="4788144087245714948">"允許應用程式接收 Android Beam 目前傳輸的資訊"</string>
     <string name="permlab_removeDrmCertificates" msgid="7044888287209892751">"移除 DRM 憑證"</string>
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"允許應用程式移除 DRM 憑證 (一般應用程式並不需要)。"</string>
-    <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"繫結至行動通訊業者簡訊服務"</string>
-    <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"允許應用程式繫結至行動通訊業者簡訊服務的頂層介面 (一般應用程式並不需要)。"</string>
+    <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"與行動通訊業者簡訊服務繫結"</string>
+    <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"允許應用程式與行動通訊業者簡訊服務的頂層介面繫結 (一般應用程式並不需要)。"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"設定密碼規則"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"控制螢幕解鎖密碼所允許的長度和字元。"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"監視螢幕解鎖嘗試次數"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"直到下次鬧鐘鈴響:<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"直到下次鬧鐘鈴響"</string>
     <string name="muted_by" msgid="6147073845094180001">"由 <xliff:g id="THIRD_PARTY">%1$s</xliff:g> 設為靜音"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"您的裝置內部發生問題,必須讓裝置恢復原廠設定才能解除不穩定的狀態。"</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"您的裝置內部發生問題,詳情請洽詢裝置製造商。"</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 50a3008..116b2a6 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -564,6 +564,8 @@
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Ivumela uhlelo lokusebenza ukulungisa nokuxhuma ekubukisweni kwe-Wi-Fi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"lawula ukubukwa kwe-Wi-Fi"</string>
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Uvumela uhlelo lokusebenza ukulawula izici zeleveli ephansi zokuboniswa kwe-Wi-Fi."</string>
+    <string name="permlab_controlVpn" msgid="2618442789397588200">"lawula Amanethiwekhi Wemfihlo Abonakalayo"</string>
+    <string name="permdesc_controlVpn" msgid="762852603315861214">"Ivumela uhlelo lokusebenza ukulawula izici zeleveli ephansi Zamanethiwekhi Wemfihlo Abonakalayo."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"shutha okukhipha umsindo"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Kuvumela uhlelo lokusebenza ukuba lushuthe futhi luqondise kabusha okukhipha umsindo."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Ukutholwa kwe-Hotword"</string>
@@ -1902,4 +1904,18 @@
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Kuze kube yi-alamu elandelayo ngo-<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Kuze kube yi-alamu elandelayo"</string>
     <string name="muted_by" msgid="6147073845094180001">"Ithuliswe ngu-<xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Kukhona inkinga yangaphakathi ngedivayisi yakho, futhi ingase ibe engazinzile kuze kube yilapho usetha kabusha yonke idatha."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Kukhona inkinga yangaphakathi ngedivayisi yakho. Xhumana nomkhiqizi wakho ukuze uthole imininingwane."</string>
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 4f8acdb..2fd7d30 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2639,8 +2639,8 @@
              to allow the children to draw outside of their bounds. The default value of
              this property is true. -->
         <attr name="clipChildren" format="boolean" />
-        <!-- Defines whether the ViewGroup will clip its drawing surface so as to exclude
-             the padding area. This property is set to true by default. -->
+        <!-- Defines whether the ViewGroup will clip its children to its padding, if
+             padding is not zero. This property is set to true by default. -->
         <attr name="clipToPadding" format="boolean" />
         <!-- Defines the layout animation to use the first time the ViewGroup is laid out.
              Layout animations can also be started manually after the first layout. -->
@@ -4662,6 +4662,11 @@
         <attr name="weekDayTextAppearance" format="reference" />
         <!-- The text appearance for the calendar dates. -->
         <attr name="dateTextAppearance" format="reference" />
+        <!-- The number of weeks to be shown. -->
+        <attr name="calendarViewMode">
+            <enum name="holo" value="0" />
+            <enum name="material" value="1" />
+        </attr>
     </declare-styleable>
 
     <declare-styleable name="NumberPicker">
@@ -5660,6 +5665,10 @@
             <enum name="right" value="0x05" />
             <!-- Slide to and from the bottom edge of the Scene. -->
             <enum name="bottom" value="0x50" />
+            <!-- Slide to and from the x-axis position at the start of the Scene root. -->
+            <enum name="start" value="0x00800003"/>
+            <!-- Slide to and from the x-axis position at the end of the Scene root. -->
+            <enum name="end" value="0x00800005"/>
         </attr>
     </declare-styleable>
 
@@ -7215,6 +7224,8 @@
         <attr name="goIcon" format="reference" />
         <!-- Search icon -->
         <attr name="searchIcon" format="reference" />
+        <!-- Search icon displayed as a text field hint -->
+        <attr name="searchHintIcon" format="reference" />
         <!-- Voice button icon -->
         <attr name="voiceIcon" format="reference" />
         <!-- Commit icon shown in the query suggestion row -->
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index 46ec838..a8fd8d4 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">#ffe0e0e0</color>
+    <color name="primary_material_light">#ffefefef</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 cbdb256..6e635f3 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1942,4 +1942,8 @@
     <string-array translatable="false" name="config_sms_convert_destination_number_support">
         <item>false</item>
     </string-array>
+
+    <!-- The maximum bitmap size that can be written to a MediaMetadata object. This value
+         is the max width/height allowed in dips.-->
+    <dimen name="config_mediaMetadataBitmapMaxSize">320dp</dimen>
 </resources>
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index 4a2119b..e3672c8 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -91,6 +91,10 @@
     <!-- Default rounded corner for controls -->
     <dimen name="control_corner_material">2dp</dimen>
 
+    <dimen name="edit_text_inset_horizontal_material">4dp</dimen>
+    <dimen name="edit_text_inset_top_material">4dp</dimen>
+    <dimen name="edit_text_inset_bottom_material">8dp</dimen>
+
     <dimen name="dialog_padding_material">24dp</dimen>
     <dimen name="dialog_padding_top_material">18dp</dimen>
 </resources>
diff --git a/core/res/res/values/integers.xml b/core/res/res/values/integers.xml
index 0343cfa..8e27226 100644
--- a/core/res/res/values/integers.xml
+++ b/core/res/res/values/integers.xml
@@ -22,4 +22,5 @@
     <integer name="button_pressed_animation_duration">100</integer>
     <integer name="button_pressed_animation_delay">100</integer>
     <integer name="disabled_alpha_animation_duration">100</integer>
+    <integer name="dock_enter_exit_duration">250</integer>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index c661c33..c01d406 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2600,5 +2600,6 @@
     <public type="attr" name="accessibilityTraversalBefore" />
     <public type="attr" name="accessibilityTraversalAfter" />
     <public type="attr" name="dialogPreferredPadding" />
+    <public type="attr" name="searchHintIcon" />
 
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index b97be6e..7bc24c3 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -212,6 +212,12 @@
     <!-- Displayed to tell the user that all service is blocked by access control. -->
     <string name="RestrictedOnAll">All voice/data/SMS services are blocked.</string>
 
+    <!-- Displayed to tell the user that peer changed TTY mode -->
+    <string name="peerTtyModeFull">Peer requested TTY Mode FULL</string>
+    <string name="peerTtyModeHco">Peer requested TTY Mode HCO</string>
+    <string name="peerTtyModeVco">Peer requested TTY Mode VCO</string>
+    <string name="peerTtyModeOff">Peer requested TTY Mode OFF</string>
+
     <!-- Mappings between TS 27.007 +CFCC/+CLCK "service classes" and human-readable strings--> <skip />
     <!-- Example: Service was enabled for: Voice, Data -->
     <string name="serviceClassVoice">Voice</string>
@@ -3306,6 +3312,8 @@
     <!-- This is the default button label in the system-wide search UI.
          It is also used by the home screen's search "widget". It should be short -->
     <string name="search_go">Search</string>
+    <!-- Default hint text for the system-wide search UI's text field. [CHAR LIMIT=30] -->
+    <string name="search_hint">Search…</string>
     <!-- SearchView accessibility description for search button [CHAR LIMIT=NONE] -->
     <string name="searchview_description_search">Search</string>
     <!-- SearchView accessibility description for search text field [CHAR LIMIT=NONE] -->
@@ -5077,7 +5085,7 @@
     <string name="lock_to_app_unlock_password">Ask for password before unpinning</string>
 
     <!-- [CHAR_LIMIT=NONE] Battery saver: Feature description -->
-    <string name="battery_saver_description">To help improve battery life, battery saver reduces your device’s performance and limits vibration and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging.</string>
+    <string name="battery_saver_description">To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services, and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging.</string>
 
     <!-- [CHAR_LIMIT=NONE] Zen mode: Condition summary for built-in downtime condition, if active -->
     <string name="downtime_condition_summary">Until your downtime ends at <xliff:g id="formattedTime" example="10:00 PM">%1$s</xliff:g></string>
@@ -5132,4 +5140,13 @@
     <!-- Error message shown when there is a system error which can be solved by the manufacturer. [CHAR LIMIT=NONE] -->
     <string name="system_error_manufacturer">There\'s an internal problem with your device. Contact your manufacturer for details.</string>
 
+    <!-- Displayed when the USSD/SS request is modified by STK CC to a
+    different request. This will be displayed in a toast. -->
+    <string name="stk_cc_ussd_to_dial">USSD request is modified to DIAL request.</string>
+    <string name="stk_cc_ussd_to_ss">USSD request is modified to SS request.</string>
+    <string name="stk_cc_ussd_to_ussd">USSD request is modified to new USSD request.</string>
+    <string name="stk_cc_ss_to_dial">SS request is modified to DIAL request.</string>
+    <string name="stk_cc_ss_to_ussd">SS request is modified to USSD request.</string>
+    <string name="stk_cc_ss_to_ss">SS request is modified to new SS request.</string>
+
 </resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 5a59afe..c520a46 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -565,6 +565,7 @@
         <item name="selectedDateVerticalBar">@drawable/day_picker_week_view_dayline_holo</item>
         <item name="weekDayTextAppearance">@style/TextAppearance.Small.CalendarViewWeekDayView</item>
         <item name="dateTextAppearance">?attr/textAppearanceSmall</item>
+        <item name="calendarViewMode">holo</item>
     </style>
 
     <style name="Widget.NumberPicker">
diff --git a/core/res/res/values/styles_holo.xml b/core/res/res/values/styles_holo.xml
index c7d2db1..41b8b25 100644
--- a/core/res/res/values/styles_holo.xml
+++ b/core/res/res/values/styles_holo.xml
@@ -358,6 +358,7 @@
         <item name="submitBackground">@drawable/textfield_searchview_right_holo_dark</item>
         <item name="closeIcon">@drawable/ic_clear_holo_dark</item>
         <item name="searchIcon">@drawable/ic_search_api_holo_dark</item>
+        <item name="searchHintIcon">@drawable/ic_search_api_holo_dark</item>
         <item name="goIcon">@drawable/ic_go_search_api_holo_dark</item>
         <item name="voiceIcon">@drawable/ic_voice_search_api_holo_dark</item>
         <item name="commitIcon">@drawable/ic_commit_search_api_holo_dark</item>
@@ -444,6 +445,7 @@
         <item name="weekSeparatorLineColor">#19FFFFFF</item>
         <item name="selectedDateVerticalBar">@drawable/day_picker_week_view_dayline_holo</item>
         <item name="weekDayTextAppearance">@style/TextAppearance.Holo.CalendarViewWeekDayView</item>
+        <item name="calendarViewMode">holo</item>
     </style>
 
     <style name="Widget.Holo.ImageButton" parent="Widget.ImageButton">
@@ -881,6 +883,7 @@
         <item name="weekNumberColor">#7F080021</item>
         <item name="weekSeparatorLineColor">#7F08002A</item>
         <item name="weekDayTextAppearance">@style/TextAppearance.Holo.Light.CalendarViewWeekDayView</item>
+        <item name="calendarViewMode">holo</item>
     </style>
 
     <style name="Widget.Holo.Light.NumberPicker" parent="Widget.Holo.NumberPicker" />
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index e04d901..6749441 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -517,12 +517,20 @@
         <item name="submitBackground">@drawable/textfield_search_material</item>
         <item name="closeIcon">@drawable/ic_clear_material</item>
         <item name="searchIcon">@drawable/ic_search_api_material</item>
+        <item name="searchHintIcon">@drawable/ic_search_api_material</item>
         <item name="goIcon">@drawable/ic_go_search_api_material</item>
         <item name="voiceIcon">@drawable/ic_voice_search_api_material</item>
         <item name="commitIcon">@drawable/ic_commit_search_api_material</item>
         <item name="suggestionRowLayout">@layout/search_dropdown_item_icons_2line</item>
     </style>
 
+    <style name="Widget.Material.SearchView.ActionBar">
+        <item name="queryBackground">@empty</item>
+        <item name="submitBackground">@empty</item>
+        <item name="searchHintIcon">@empty</item>
+        <item name="queryHint">@string/search_hint</item>
+    </style>
+
     <style name="Widget.Material.SegmentedButton" parent="SegmentedButton">
         <item name="background">@drawable/btn_group_holo_dark</item>
     </style>
@@ -612,6 +620,7 @@
         <item name="weekSeparatorLineColor">#19FFFFFF</item>
         <item name="selectedDateVerticalBar">@drawable/day_picker_week_view_dayline_holo</item>
         <item name="weekDayTextAppearance">@style/TextAppearance.Material.CalendarViewWeekDayView</item>
+        <item name="calendarViewMode">material</item>
     </style>
 
     <style name="Widget.Material.ImageButton" parent="Widget.ImageButton">
@@ -961,6 +970,7 @@
     <style name="Widget.Material.Light.ButtonBar" parent="Widget.Material.ButtonBar"/>
     <style name="Widget.Material.Light.ButtonBar.AlertDialog" parent="Widget.Material.ButtonBar.AlertDialog"/>
     <style name="Widget.Material.Light.SearchView" parent="Widget.Material.SearchView"/>
+    <style name="Widget.Material.Light.SearchView.ActionBar" parent="Widget.Material.SearchView.ActionBar"/>
 
     <style name="Widget.Material.Light.SegmentedButton" parent="Widget.Material.SegmentedButton">
         <item name="background">@drawable/btn_group_holo_light</item>
@@ -999,6 +1009,7 @@
         <item name="weekNumberColor">#7F080021</item>
         <item name="weekSeparatorLineColor">#7F08002A</item>
         <item name="weekDayTextAppearance">@style/TextAppearance.Material.CalendarViewWeekDayView</item>
+        <item name="calendarViewMode">material</item>
     </style>
 
     <style name="Widget.Material.Light.NumberPicker" parent="Widget.Material.NumberPicker"/>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 702d5ed..cbc379b 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -202,6 +202,7 @@
   <java-symbol type="id" name="status_bar_latest_event_content" />
   <java-symbol type="id" name="action_divider" />
   <java-symbol type="id" name="overflow_divider" />
+  <java-symbol type="id" name="notification_main_column" />
   <java-symbol type="id" name="sms_short_code_confirm_message" />
   <java-symbol type="id" name="sms_short_code_detail_layout" />
   <java-symbol type="id" name="sms_short_code_detail_message" />
@@ -715,6 +716,10 @@
   <java-symbol type="string" name="perms_description_app" />
   <java-symbol type="string" name="perms_new_perm_prefix" />
   <java-symbol type="string" name="petabyteShort" />
+  <java-symbol type="string" name="peerTtyModeFull" />
+  <java-symbol type="string" name="peerTtyModeHco" />
+  <java-symbol type="string" name="peerTtyModeVco" />
+  <java-symbol type="string" name="peerTtyModeOff" />
   <java-symbol type="string" name="phoneTypeAssistant" />
   <java-symbol type="string" name="phoneTypeCallback" />
   <java-symbol type="string" name="phoneTypeCar" />
@@ -918,6 +923,12 @@
   <java-symbol type="string" name="default_audio_route_name_dock_speakers" />
   <java-symbol type="string" name="default_media_route_name_hdmi" />
   <java-symbol type="string" name="default_audio_route_category_name" />
+  <java-symbol type="string" name="stk_cc_ss_to_dial" />
+  <java-symbol type="string" name="stk_cc_ss_to_ss" />
+  <java-symbol type="string" name="stk_cc_ss_to_ussd" />
+  <java-symbol type="string" name="stk_cc_ussd_to_dial" />
+  <java-symbol type="string" name="stk_cc_ussd_to_ss" />
+  <java-symbol type="string" name="stk_cc_ussd_to_ussd" />
   <java-symbol type="string" name="safe_media_volume_warning" />
   <java-symbol type="string" name="media_route_status_scanning" />
   <java-symbol type="string" name="media_route_status_connecting" />
@@ -1799,6 +1810,8 @@
   <java-symbol type="color" name="notification_progress_background_color" />
   <java-symbol type="id" name="media_actions" />
 
+  <java-symbol type="dimen" name="config_mediaMetadataBitmapMaxSize" />
+
     <!-- From SystemUI -->
   <java-symbol type="anim" name="push_down_in" />
   <java-symbol type="anim" name="push_down_out" />
@@ -1848,6 +1861,7 @@
   <java-symbol type="string" name="usb_storage_stop_title" />
   <java-symbol type="string" name="usb_storage_title" />
   <java-symbol type="style" name="Animation.RecentApplications" />
+  <java-symbol type="integer" name="dock_enter_exit_duration" />
 
   <!-- ImfTest -->
   <java-symbol type="layout" name="auto_complete_list" />
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index b320ae5..3f2062d 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -828,6 +828,7 @@
          secondary text color, with the primary text color. -->
     <style name="ThemeOverlay.Material.ActionBar">
         <item name="colorControlNormal">?attr/textColorPrimary</item>
+        <item name="searchViewStyle">@style/Widget.Material.Light.SearchView.ActionBar</item>
     </style>
 
     <!-- Theme overlay that replaces colors with their dark versions and replaces the normal
@@ -835,6 +836,7 @@
          text color. -->
     <style name="ThemeOverlay.Material.Dark.ActionBar">
         <item name="colorControlNormal">?attr/textColorPrimary</item>
+        <item name="searchViewStyle">@style/Widget.Material.SearchView.ActionBar</item>
     </style>
 
     <!-- Variant of the material (dark) theme with no action bar. -->
diff --git a/docs/html/auto/images/logos/apps/TextMe.png b/docs/html/auto/images/logos/apps/TextMe.png
new file mode 100644
index 0000000..b96f81a
--- /dev/null
+++ b/docs/html/auto/images/logos/apps/TextMe.png
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/soundcloud.png b/docs/html/auto/images/logos/apps/soundcloud.png
new file mode 100644
index 0000000..a5bdbe3
--- /dev/null
+++ b/docs/html/auto/images/logos/apps/soundcloud.png
Binary files differ
diff --git a/docs/html/auto/index.jd b/docs/html/auto/index.jd
index ddb265b..129478a 100644
--- a/docs/html/auto/index.jd
+++ b/docs/html/auto/index.jd
@@ -223,34 +223,25 @@
           </div>
           <div class="landing-body">
           <div class="cols">
-
             <div class="col-4">
-              <img src="/auto/images/logos/apps/kik.png"
-                   width="120" height="120" class="img-logo" style="margin-top:20px"/>
-            </div>
-            <div class="col-4">
-              <img src="/auto/images/logos/apps/textplus.png"
-                   width="120" height="24" class="img-logo" style="margin-top:70px" />
-            </div>
-            <div class="col-4">
-              <img src="/auto/images/logos/apps/iheartradio.png"
+              <img src="{@docRoot}auto/images/logos/apps/iheartradio.png"
                    width="160" height="160" class="img-logo" />
             </div>
             <div class="col-4">
-              <img src="/auto/images/logos/apps/spotify.png"
-                   width="160" height="160" class="img-logo" />
-            </div>
-          </div>
-          <div class="cols">
-
-            <div class="col-4">
               <img src="{@docRoot}auto/images/logos/apps/joyride.png"
                    width="160" height="160" class="img-logo" />
             </div>
             <div class="col-4">
+              <img src="{@docRoot}auto/images/logos/apps/kik.png"
+                   width="120" height="120" class="img-logo" style="margin-top:30px" />
+            </div>
+            <div class="col-4">
               <img src="{@docRoot}auto/images/logos/apps/mlb.png"
                    width="160" height="160" class="img-logo" />
             </div>
+          </div>
+
+          <div class="cols">
             <div class="col-4">
               <img src="{@docRoot}auto/images/logos/apps/pandora.png"
                    width="160" height="160" class="img-logo" />
@@ -259,25 +250,47 @@
               <img src="{@docRoot}auto/images/logos/apps/pocketcasts.png"
                    width="160" height="160" class="img-logo" />
             </div>
-          </div>
-          <div class="cols">
             <div class="col-4">
               <img src="{@docRoot}auto/images/logos/apps/songza.png"
                    width="160" height="160" class="img-logo" />
             </div>
             <div class="col-4">
+              <img src="/auto/images/logos/apps/soundcloud.png"
+                   width="100" height="100" class="img-logo"
+                   style="margin-top:30px" />
+            </div>
+          </div>
+
+          <div class="cols">
+            <div class="col-4">
+              <img src="/auto/images/logos/apps/spotify.png"
+                   width="160" height="160" class="img-logo" />
+            </div>
+            <div class="col-4">
               <img src="{@docRoot}auto/images/logos/apps/stitcher.png"
                    width="160" height="160" class="img-logo" />
             </div>
             <div class="col-4">
+              <img src="/auto/images/logos/apps/TextMe.png"
+                   width="100" height="100" class="img-logo" style="margin-top:30px" />
+            </div>
+            <div class="col-4">
+              <img src="/auto/images/logos/apps/textplus.png"
+                   width="120" height="24" class="img-logo" style="margin-top:70px" />
+            </div>
+          </div>
+
+          <div class="cols">
+            <div class="col-4">
               <img src="{@docRoot}auto/images/logos/apps/tunein.png"
-                   width="160" height="160" class="img-logo" />
+                   width="160" height="160" class="img-logo" style="margin-left:160px" />
             </div>
             <div class="col-4">
               <img src="{@docRoot}auto/images/logos/apps/umano.png"
-                   width="160" height="160" class="img-logo" />
+                   width="160" height="160" class="img-logo" style="margin-left:370px" />
             </div>
           </div>
+
           <div class="cols" style="margin-top:40px">
               <div class="col-4">
                 <img src="/auto/images/logos/apps/whatsapp.png"
@@ -292,6 +305,7 @@
                 user-friendly and highly safety-minded."</em></p>
               </div>
           </div>
+
           <div class="cols" style="margin-top:60px">
 
               <div class="col-4">
diff --git a/docs/html/distribute/essentials/quality/auto.jd b/docs/html/distribute/essentials/quality/auto.jd
index 55b02a0..757305e 100644
--- a/docs/html/distribute/essentials/quality/auto.jd
+++ b/docs/html/distribute/essentials/quality/auto.jd
@@ -19,9 +19,9 @@
       Core App Quality</a></li>
     <li><a href="{@docRoot}distribute/essentials/optimizing-your-app.html">
       Optimize Your App</a></li>
-    <li><a href="{@docRoot}/shareables/auto/AndroidAuto-media-apps.pdf">Android Auto UX Guidelines
+    <li><a href="{@docRoot}shareables/auto/AndroidAuto-media-apps.pdf">Android Auto UX Guidelines
       for Media Applications</a></li>
-    <li><a href="{@docRoot}/shareables/auto/AndroidAuto-messaging-apps.pdf">Android Auto UX Guidelines
+    <li><a href="{@docRoot}shareables/auto/AndroidAuto-messaging-apps.pdf">Android Auto UX Guidelines
       for Messaging Applications</a></li>
   </ol>
 </div>
@@ -310,7 +310,7 @@
     <p style="margin-bottom:.5em;">
      App has no more than four primary actions plus one optional action overflow toggle (or five if
      no action overflow is used). For more information, see details on the media control card in the
-     <a href="{@docRoot}/shareables/auto/AndroidAuto-media-apps.pdf">Android Auto UX Guidelines
+     <a href="{@docRoot}shareables/auto/AndroidAuto-media-apps.pdf">Android Auto UX Guidelines
       for Media Applications</a>.
     </p>
   </td>
@@ -324,7 +324,7 @@
     <p style="margin-bottom:.5em;">
      App has no more than four optional secondary actions plus one action overflow toggle. For more
      information, see details on the media control card in the
-     <a href="{@docRoot}/shareables/auto/AndroidAuto-media-apps.pdf">Android Auto UX Guidelines
+     <a href="{@docRoot}shareables/auto/AndroidAuto-media-apps.pdf">Android Auto UX Guidelines
       for Media Applications</a>.
     </p>
   </td>
diff --git a/docs/html/guide/components/intents-common.jd b/docs/html/guide/components/intents-common.jd
index d4b033a..adba1cd 100644
--- a/docs/html/guide/components/intents-common.jd
+++ b/docs/html/guide/components/intents-common.jd
@@ -2282,6 +2282,14 @@
     <li>"search for cat videos on myvideoapp"</li>
   </ul>
 </div>
+<!-- Video box -->
+<a class="notice-developers-video"
+   href="https://www.youtube.com/watch?v=PS1FbB5qWEI">
+<div>
+    <h3>Video</h3>
+    <p>Voice search in your app</p>
+</div>
+</a>
 
 <p>To support search within the context of your app, declare an intent filter in your app with
 the <code>SEARCH_ACTION</code> action, as shown in the example intent filter below.</p>
diff --git a/docs/html/training/auto/audio/index.jd b/docs/html/training/auto/audio/index.jd
index 2656b96..aa25769 100644
--- a/docs/html/training/auto/audio/index.jd
+++ b/docs/html/training/auto/audio/index.jd
@@ -301,31 +301,30 @@
 public BrowserRoot onGetRoot(String clientPackageName, int clientUid,
     Bundle rootHints) {
 
-    // Check the calling client to make sure it's one you approve.
-    // For example, to limit access to just Auto, the Auto emulator,
-    // and this app:
-
-    if (!clientPackageName.equals("com.google.android.projection.gearhead") &amp;&amp;
-            !clientPackageName.equals("com.example.android.media") &amp;&amp;
-            !clientPackageName.equals(getApplication().getPackageName()) {
-
+    // To ensure you are not allowing any arbitrary app to browse your app's
+    // contents, you need to check the origin:
+    if (!PackageValidator.isCallerAllowed(this, clientPackageName, clientUid)) {
         // If the request comes from an untrusted package, return null.
         // No further calls will be made to other media browsing methods.
+        LogHelper.w(TAG, "OnGetRoot: IGNORING request from untrusted package "
+                + clientPackageName);
         return null;
-        }
-
-        // Return a BrowserRoot. If you wish, you could have multiple BrowserRoot
-        // objects and return different ones depending on the calling client.
-        // In this example, there's just a single BrowserRoot.
-        return new BrowserRoot(MEDIA_BROWSER_ROOT, null);
     }
+    if (ANDROID_AUTO_PACKAGE_NAME.equals(clientPackageName)) {
+        // Optional: if your app needs to adapt ads, music library or anything
+        // else that needs to run differently when connected to the car, this
+        // is where you should handle it.
+    }
+    return new BrowserRoot(MEDIA_ID_ROOT, null);
+}
 </pre>
 
 <p>
   The Auto device client builds the top-level menu by calling {@link
-  android.service.media.MediaBrowserService#onLoadChildren onLoadChildren()} with the root node
-  object and getting it's children. The client builds submenus by calling the same method with
-  other child nodes. The following example code shows a simple implementation of {@link
+  android.service.media.MediaBrowserService#onLoadChildren onLoadChildren()}
+  with the root node object and getting it's children. The client builds
+  submenus by calling the same method with other child nodes. The following
+  example code shows a simple implementation of {@link
   android.service.media.MediaBrowserService#onLoadChildren onLoadChildren()} method:
 </p>
 
diff --git a/libs/hwui/AssetAtlas.cpp b/libs/hwui/AssetAtlas.cpp
index fc86e4f..e5a93bd 100644
--- a/libs/hwui/AssetAtlas.cpp
+++ b/libs/hwui/AssetAtlas.cpp
@@ -33,6 +33,8 @@
         return;
     }
 
+    ATRACE_NAME("AssetAtlas::init");
+
     mImage = new Image(buffer);
 
     if (mImage->getTexture()) {
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 952f739..6453206 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -66,6 +66,8 @@
 bool Caches::init() {
     if (mInitialized) return false;
 
+    ATRACE_NAME("Caches::init");
+
     glGenBuffers(1, &meshBuffer);
     glBindBuffer(GL_ARRAY_BUFFER, meshBuffer);
     glBufferData(GL_ARRAY_BUFFER, sizeof(gMeshVertices), gMeshVertices, GL_STATIC_DRAW);
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index b95636b..9aa29ca 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -20,11 +20,18 @@
 
 #include "Caches.h"
 #include "DeferredDisplayList.h"
-#include "RenderState.h"
 #include "Layer.h"
 #include "LayerRenderer.h"
 #include "OpenGLRenderer.h"
 #include "RenderNode.h"
+#include "RenderState.h"
+#include "utils/TraceUtils.h"
+
+#define ATRACE_LAYER_WORK(label) \
+    ATRACE_FORMAT("%s HW Layer DisplayList %s %ux%u", \
+            label, \
+            (renderNode.get() != NULL) ? renderNode->getName() : "", \
+            getWidth(), getHeight())
 
 namespace android {
 namespace uirenderer {
@@ -223,6 +230,8 @@
 }
 
 void Layer::defer(const OpenGLRenderer& rootRenderer) {
+    ATRACE_LAYER_WORK("Optimize");
+
     updateLightPosFromRenderer(rootRenderer);
     const float width = layer.getWidth();
     const float height = layer.getHeight();
@@ -260,6 +269,9 @@
 void Layer::flush() {
     // renderer is checked as layer may be destroyed/put in layer cache with flush scheduled
     if (deferredList && renderer) {
+        ATRACE_LAYER_WORK("Issue");
+        renderer->startMark((renderNode.get() != NULL) ? renderNode->getName() : "Layer");
+
         renderer->setViewport(layer.getWidth(), layer.getHeight());
         renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
                 !isBlend());
@@ -270,10 +282,14 @@
 
         dirtyRect.setEmpty();
         renderNode = NULL;
+
+        renderer->endMark();
     }
 }
 
 void Layer::render(const OpenGLRenderer& rootRenderer) {
+    ATRACE_LAYER_WORK("Direct-Issue");
+
     updateLightPosFromRenderer(rootRenderer);
     renderer->setViewport(layer.getWidth(), layer.getHeight());
     renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 394c647..83f9c6a 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -27,6 +27,7 @@
 #include "Matrix.h"
 #include "Properties.h"
 #include "Rect.h"
+#include "utils/TraceUtils.h"
 
 namespace android {
 namespace uirenderer {
@@ -185,7 +186,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 Layer* LayerRenderer::createRenderLayer(RenderState& renderState, uint32_t width, uint32_t height) {
-    ATRACE_CALL();
+    ATRACE_FORMAT("Allocate %ux%u HW Layer", width, height);
     LAYER_RENDERER_LOGD("Requesting new render layer %dx%d", width, height);
 
     Caches& caches = Caches::getInstance();
@@ -310,7 +311,7 @@
 
 void LayerRenderer::destroyLayer(Layer* layer) {
     if (layer) {
-        ATRACE_CALL();
+        ATRACE_FORMAT("Destroy %ux%u HW Layer", layer->getWidth(), layer->getHeight());
         LAYER_RENDERER_LOGD("Recycling layer, %dx%d fbo = %d",
                 layer->getWidth(), layer->getHeight(), layer->getFbo());
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index d570b0d..80b4c2a 100755
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -42,6 +42,7 @@
 #include "ShadowTessellator.h"
 #include "SkiaShader.h"
 #include "utils/GLUtils.h"
+#include "utils/TraceUtils.h"
 #include "Vector.h"
 #include "VertexBuffer.h"
 
@@ -51,21 +52,6 @@
     #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 {
 
@@ -466,8 +452,6 @@
 bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) {
     if (layer->deferredUpdateScheduled && layer->renderer
             && layer->renderNode.get() && layer->renderNode->isRenderable()) {
-        ATRACE_CALL();
-
         Rect& dirty = layer->dirtyRect;
 
         if (inFrame) {
@@ -525,20 +509,10 @@
     int count = mLayerUpdates.size();
     if (count > 0) {
         startMark("Apply Layer Updates");
-        char layerName[12];
 
         // Note: it is very important to update the layers in order
         for (int i = 0; i < count; i++) {
-            Layer* layer = mLayerUpdates.itemAt(i).get();
-
-            sprintf(layerName, "Layer #%d", i);
-            startMark(layerName);
-            ATRACE_FORMAT_BEGIN("flushLayer %ux%u", layer->getWidth(), layer->getHeight());
-
-            layer->flush();
-
-            ATRACE_END();
-            endMark();
+            mLayerUpdates.itemAt(i)->flush();
         }
 
         mLayerUpdates.clear();
@@ -575,7 +549,7 @@
 }
 
 void OpenGLRenderer::flushLayerUpdates() {
-    ATRACE_CALL();
+    ATRACE_NAME("Update HW Layers");
     syncState();
     updateLayers();
     flushLayers();
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index 9ba8854..6f48e4d 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -255,7 +255,7 @@
 
 PathTexture* PathCache::addTexture(const PathDescription& entry, const SkPath *path,
         const SkPaint* paint) {
-    ATRACE_CALL();
+    ATRACE_NAME("Generate Path Texture");
 
     float left, top, offset;
     uint32_t width, height;
diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp
index 0dad0dc..e6fd2dc 100644
--- a/libs/hwui/Program.cpp
+++ b/libs/hwui/Program.cpp
@@ -132,7 +132,7 @@
 }
 
 GLuint Program::buildShader(const char* source, GLenum type) {
-    ATRACE_CALL();
+    ATRACE_NAME("Build GL Shader");
 
     GLuint shader = glCreateShader(type);
     glShaderSource(shader, 1, &source, 0);
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 13c5499..eb0948f 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -25,7 +25,6 @@
 #include <SkCanvas.h>
 #include <algorithm>
 
-#include <utils/Trace.h>
 
 #include "DamageAccumulator.h"
 #include "Debug.h"
@@ -34,6 +33,7 @@
 #include "LayerRenderer.h"
 #include "OpenGLRenderer.h"
 #include "utils/MathUtils.h"
+#include "utils/TraceUtils.h"
 #include "renderthread/CanvasContext.h"
 
 namespace android {
@@ -426,6 +426,10 @@
                 clipFlags = 0; // all clipping done by saveLayer
             }
 
+            ATRACE_FORMAT("%s alpha caused %ssaveLayer %ux%u",
+                    getName(), clipFlags ? "" : "unclipped ",
+                    layerBounds.getWidth(), layerBounds.getHeight());
+
             SaveLayerOp* op = new (handler.allocator()) SaveLayerOp(
                     layerBounds.left, layerBounds.top, layerBounds.right, layerBounds.bottom,
                     properties().getAlpha() * 255, saveFlags);
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 3b8a9a4..5fcb194 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -26,6 +26,7 @@
 #include "Caches.h"
 #include "TextureCache.h"
 #include "Properties.h"
+#include "utils/TraceUtils.h"
 
 namespace android {
 namespace uirenderer {
@@ -266,7 +267,7 @@
         return;
     }
 
-    ATRACE_CALL();
+    ATRACE_FORMAT("Upload %ux%u Texture", bitmap->width(), bitmap->height());
 
     // We could also enable mipmapping if both bitmap dimensions are powers
     // of 2 but we'd have to deal with size changes. Let's keep this simple
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
index ba878ba..af39f16 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -363,7 +363,7 @@
 }
 
 void Font::precache(const SkPaint* paint, const char* text, int numGlyphs) {
-    ATRACE_NAME("precacheText");
+    ATRACE_NAME("Precache Glyphs");
 
     if (numGlyphs == 0 || text == NULL) {
         return;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 6c3637d..39528be 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -71,6 +71,8 @@
 }
 
 void CanvasContext::setSurface(ANativeWindow* window) {
+    ATRACE_CALL();
+
     mNativeWindow = window;
 
     if (mEglSurface != EGL_NO_SURFACE) {
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 9bd6f41..378cf61 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -82,6 +82,8 @@
 void EglManager::initialize() {
     if (hasEglContext()) return;
 
+    ATRACE_NAME("Creating EGLContext");
+
     mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY,
             "Failed to get EGL_DEFAULT_DISPLAY! err=%s", egl_error_str());
diff --git a/libs/hwui/utils/TraceUtils.h b/libs/hwui/utils/TraceUtils.h
new file mode 100644
index 0000000..ff8ccb8
--- /dev/null
+++ b/libs/hwui/utils/TraceUtils.h
@@ -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.
+ */
+#ifndef TRACE_UTILS_H
+#define TRACE_UTILS_H
+
+#include <utils/Trace.h>
+
+#define ATRACE_FORMAT(fmt, ...) \
+    TraceUtils::TraceEnder __traceEnder = (TraceUtils::atraceFormatBegin(fmt, ##__VA_ARGS__), TraceUtils::TraceEnder())
+
+#define ATRACE_FORMAT_BEGIN(fmt, ...) \
+    TraceUtils::atraceFormatBegin(fmt, ##__VA_ARGS__)
+
+namespace android {
+namespace uirenderer {
+
+class TraceUtils {
+public:
+    class TraceEnder {
+    public:
+        ~TraceEnder() { ATRACE_END(); }
+    };
+
+    static void atraceFormatBegin(const char* fmt, ...) {
+        if (CC_UNLIKELY(!ATRACE_ENABLED())) return;
+
+        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);
+    }
+
+}; // class TraceUtils
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* TRACE_UTILS_H */
diff --git a/media/java/android/media/AudioManagerInternal.java b/media/java/android/media/AudioManagerInternal.java
index 7c0d758..a6cc493 100644
--- a/media/java/android/media/AudioManagerInternal.java
+++ b/media/java/android/media/AudioManagerInternal.java
@@ -35,4 +35,7 @@
 
     public abstract void setStreamVolumeForUid(int streamType, int direction, int flags,
             String callingPackage, int uid);
+
+    public abstract void adjustMasterVolumeForUid(int steps, int flags, String callingPackage,
+            int uid);
 }
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 6e14aba..c70ac55 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -50,7 +50,6 @@
 import android.media.MediaPlayer.OnErrorListener;
 import android.media.audiopolicy.AudioMix;
 import android.media.audiopolicy.AudioPolicyConfig;
-import android.media.session.MediaSessionLegacyHelper;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Environment;
@@ -61,7 +60,6 @@
 import android.os.PowerManager;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
@@ -75,12 +73,11 @@
 import android.util.MathUtils;
 import android.util.Slog;
 import android.view.KeyEvent;
+import android.view.OrientationEventListener;
 import android.view.Surface;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityManager;
-import android.view.OrientationEventListener;
 
-import com.android.internal.telephony.ITelephony;
 import com.android.internal.util.XmlUtils;
 import com.android.server.LocalServices;
 
@@ -91,8 +88,6 @@
 import java.io.PrintWriter;
 import java.lang.reflect.Field;
 import java.util.ArrayList;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -100,6 +95,7 @@
 import java.util.NoSuchElementException;
 import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * The implementation of the volume manager service.
@@ -1152,6 +1148,10 @@
 
     /** @see AudioManager#adjustMasterVolume(int, int) */
     public void adjustMasterVolume(int steps, int flags, String callingPackage) {
+        adjustMasterVolume(steps, flags, callingPackage, Binder.getCallingUid());
+    }
+
+    public void adjustMasterVolume(int steps, int flags, String callingPackage, int uid) {
         if (mUseFixedVolume) {
             return;
         }
@@ -1166,7 +1166,7 @@
         }
 
         //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps);
-        setMasterVolume(volume, flags, callingPackage);
+        setMasterVolume(volume, flags, callingPackage, uid);
     }
 
     // StreamVolumeCommand contains the information needed to defer the process of
@@ -1679,18 +1679,24 @@
         }
     }
 
+    @Override
     public int getMasterVolume() {
         if (isMasterMute()) return 0;
         return getLastAudibleMasterVolume();
     }
 
+    @Override
     public void setMasterVolume(int volume, int flags, String callingPackage) {
+        setMasterVolume(volume, flags, callingPackage, Binder.getCallingUid());
+    }
+
+    public void setMasterVolume(int volume, int flags, String callingPackage, int uid) {
         if (mUseFixedVolume) {
             return;
         }
 
-        if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, Binder.getCallingUid(),
-                callingPackage) != AppOpsManager.MODE_ALLOWED) {
+        if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
+                != AppOpsManager.MODE_ALLOWED) {
             return;
         }
 
@@ -5667,6 +5673,12 @@
                 String callingPackage, int uid) {
             setStreamVolume(streamType, direction, flags, callingPackage, uid);
         }
+
+        @Override
+        public void adjustMasterVolumeForUid(int steps, int flags, String callingPackage,
+                int uid) {
+            adjustMasterVolume(steps, flags, callingPackage, uid);
+        }
     }
 
     //==========================================================================================
diff --git a/media/java/android/media/MediaMetadata.java b/media/java/android/media/MediaMetadata.java
index 924078c..754da0e 100644
--- a/media/java/android/media/MediaMetadata.java
+++ b/media/java/android/media/MediaMetadata.java
@@ -16,8 +16,6 @@
 package android.media;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.ContentProviderClient;
 import android.content.ContentResolver;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
@@ -25,16 +23,14 @@
 import android.media.session.MediaController;
 import android.net.Uri;
 import android.os.Bundle;
-import android.os.CancellationSignal;
-import android.os.OperationCanceledException;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
-import android.util.Size;
 import android.util.SparseArray;
 
+import java.util.ArrayList;
 import java.util.Set;
 
 /**
@@ -569,6 +565,29 @@
         }
 
         /**
+         * Create a Builder using a {@link MediaMetadata} instance to set
+         * initial values, but replace bitmaps with a scaled down copy if they
+         * are larger than maxBitmapSize.
+         *
+         * @param source The original metadata to copy.
+         * @param maxBitmapSize The maximum height/width for bitmaps contained
+         *            in the metadata.
+         * @hide
+         */
+        public Builder(MediaMetadata source, int maxBitmapSize) {
+            this(source);
+            for (String key : mBundle.keySet()) {
+                Object value = mBundle.get(key);
+                if (value != null && value instanceof Bitmap) {
+                    Bitmap bmp = (Bitmap) value;
+                    if (bmp.getHeight() > maxBitmapSize || bmp.getWidth() > maxBitmapSize) {
+                        putBitmap(key, scaleBitmap(bmp, maxBitmapSize));
+                    }
+                }
+            }
+        }
+
+        /**
          * Put a CharSequence value into the metadata. Custom keys may be used,
          * but if the METADATA_KEYs defined in this class are used they may only
          * be one of the following:
@@ -707,6 +726,10 @@
          * <li>{@link #METADATA_KEY_ALBUM_ART}</li>
          * <li>{@link #METADATA_KEY_DISPLAY_ICON}</li>
          * </ul>
+         * <p>
+         * Large bitmaps may be scaled down by the system. To pass full
+         * resolution images {@link Uri Uris} should be used with
+         * {@link #putString}.
          *
          * @param key The key for referencing this value
          * @param value The Bitmap to store
@@ -731,5 +754,15 @@
         public MediaMetadata build() {
             return new MediaMetadata(mBundle);
         }
+
+        private Bitmap scaleBitmap(Bitmap bmp, int maxSize) {
+            float maxSizeF = maxSize;
+            float widthScale = maxSizeF / bmp.getWidth();
+            float heightScale = maxSizeF / bmp.getHeight();
+            float scale = Math.min(widthScale, heightScale);
+            int height = (int) (bmp.getHeight() * scale);
+            int width = (int) (bmp.getWidth() * scale);
+            return Bitmap.createScaledBitmap(bmp, width, height, true);
+        }
     }
 }
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 973527f..e13f008 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -104,6 +104,7 @@
     public @interface SessionFlags { }
 
     private final Object mLock = new Object();
+    private final int mMaxBitmapSize;
 
     private final MediaSession.Token mSessionToken;
     private final MediaController mController;
@@ -147,6 +148,8 @@
         if (TextUtils.isEmpty(tag)) {
             throw new IllegalArgumentException("tag cannot be null or empty");
         }
+        mMaxBitmapSize = context.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.config_mediaMetadataBitmapMaxSize);
         mCbStub = new CallbackStub(this);
         MediaSessionManager manager = (MediaSessionManager) context
                 .getSystemService(Context.MEDIA_SESSION_SERVICE);
@@ -409,6 +412,7 @@
      * @param metadata The new metadata
      */
     public void setMetadata(@Nullable MediaMetadata metadata) {
+        metadata = (new MediaMetadata.Builder(metadata, mMaxBitmapSize)).build();
         try {
             mBinder.setMetadata(metadata);
         } catch (RemoteException e) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 1771eac..175b424 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -2620,8 +2620,7 @@
             // Set the preferred network mode to target desired value or Default
             // value defined in RILConstants
             int type;
-            type = SystemProperties.getInt("ro.telephony.default_network",
-                        RILConstants.PREFERRED_NETWORK_MODE);
+            type = RILConstants.PREFERRED_NETWORK_MODE;
             loadSetting(stmt, Settings.Global.PREFERRED_NETWORK_MODE, type);
 
             // Set the preferred cdma subscription source to target desired value or default
diff --git a/packages/SystemUI/res/anim/recents_from_app_enter.xml b/packages/SystemUI/res/anim/recents_from_app_enter.xml
index 6abe8b3..10ddce6 100644
--- a/packages/SystemUI/res/anim/recents_from_app_enter.xml
+++ b/packages/SystemUI/res/anim/recents_from_app_enter.xml
@@ -16,7 +16,7 @@
 ** limitations under the License.
 */
 -->
-
+<!-- Recents Activity -->
 <set xmlns:android="http://schemas.android.com/apk/res/android"
      android:shareInterpolator="false"
      android:zAdjustment="top">
diff --git a/packages/SystemUI/res/anim/recents_from_app_exit.xml b/packages/SystemUI/res/anim/recents_from_app_exit.xml
index 1447a5a..c98ecf4 100644
--- a/packages/SystemUI/res/anim/recents_from_app_exit.xml
+++ b/packages/SystemUI/res/anim/recents_from_app_exit.xml
@@ -16,7 +16,7 @@
 ** limitations under the License.
 */
 -->
-
+<!-- Incoming Activity -->
 <set xmlns:android="http://schemas.android.com/apk/res/android"
      android:shareInterpolator="false"
      android:zAdjustment="normal">
diff --git a/packages/SystemUI/res/anim/recents_from_search_launcher_enter.xml b/packages/SystemUI/res/anim/recents_from_search_launcher_enter.xml
index 20e7764..7de4460 100644
--- a/packages/SystemUI/res/anim/recents_from_search_launcher_enter.xml
+++ b/packages/SystemUI/res/anim/recents_from_search_launcher_enter.xml
@@ -16,13 +16,13 @@
 ** limitations under the License.
 */
 -->
-
+<!-- Recents Activity -->
 <set xmlns:android="http://schemas.android.com/apk/res/android"
      android:shareInterpolator="false"
      android:zAdjustment="normal">
-  <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+  <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
          android:fillEnabled="true"
          android:fillBefore="true" android:fillAfter="true"
          android:interpolator="@android:interpolator/linear"
-         android:duration="50"/>
+         android:duration="1"/>
 </set>
diff --git a/packages/SystemUI/res/anim/recents_from_search_launcher_exit.xml b/packages/SystemUI/res/anim/recents_from_search_launcher_exit.xml
index 92a8882..e0e2fc8 100644
--- a/packages/SystemUI/res/anim/recents_from_search_launcher_exit.xml
+++ b/packages/SystemUI/res/anim/recents_from_search_launcher_exit.xml
@@ -16,14 +16,13 @@
 ** limitations under the License.
 */
 -->
-
+<!-- Launcher Activity -->
 <set xmlns:android="http://schemas.android.com/apk/res/android"
      android:shareInterpolator="false"
      android:zAdjustment="top">
   <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
-  		 android:startOffset="50"
          android:fillEnabled="true"
          android:fillBefore="true" android:fillAfter="true"
          android:interpolator="@android:interpolator/linear_out_slow_in"
-         android:duration="100"/>
+         android:duration="@integer/recents_enter_from_home_transition_duration"/>
 </set>
diff --git a/packages/SystemUI/res/anim/recents_to_search_launcher_enter.xml b/packages/SystemUI/res/anim/recents_to_search_launcher_enter.xml
index 4e1d66d..ea82835 100644
--- a/packages/SystemUI/res/anim/recents_to_search_launcher_enter.xml
+++ b/packages/SystemUI/res/anim/recents_to_search_launcher_enter.xml
@@ -16,7 +16,7 @@
 ** limitations under the License.
 */
 -->
-
+<!-- Launcher Activity -->
 <set xmlns:android="http://schemas.android.com/apk/res/android"
      android:shareInterpolator="false"
      android:zAdjustment="normal">
diff --git a/packages/SystemUI/res/anim/recents_to_search_launcher_exit.xml b/packages/SystemUI/res/anim/recents_to_search_launcher_exit.xml
index d7a12a4..a8bdc8e 100644
--- a/packages/SystemUI/res/anim/recents_to_search_launcher_exit.xml
+++ b/packages/SystemUI/res/anim/recents_to_search_launcher_exit.xml
@@ -16,14 +16,13 @@
 ** limitations under the License.
 */
 -->
-
+<!-- Recents Activity -->
 <set xmlns:android="http://schemas.android.com/apk/res/android"
      android:shareInterpolator="false"
      android:zAdjustment="top">
-  <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
-  		 android:startOffset="100"
+  <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
          android:fillEnabled="true"
          android:fillBefore="true" android:fillAfter="true"
          android:interpolator="@android:interpolator/linear"
-         android:duration="50"/>
+         android:duration="100"/>
 </set>
diff --git a/packages/SystemUI/res/drawable-hdpi/btn_fab_recents.png b/packages/SystemUI/res/drawable-hdpi/btn_fab_recents.png
deleted file mode 100644
index b95fde5..0000000
--- a/packages/SystemUI/res/drawable-hdpi/btn_fab_recents.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/btn_fab_recents.png b/packages/SystemUI/res/drawable-mdpi/btn_fab_recents.png
deleted file mode 100644
index 6bbed06..0000000
--- a/packages/SystemUI/res/drawable-mdpi/btn_fab_recents.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/btn_fab_recents.png b/packages/SystemUI/res/drawable-xhdpi/btn_fab_recents.png
deleted file mode 100644
index 4cdd0aa..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/btn_fab_recents.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/btn_fab_recents.png b/packages/SystemUI/res/drawable-xxhdpi/btn_fab_recents.png
deleted file mode 100644
index 2220d60..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/btn_fab_recents.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/recents_lock_to_task_button_bg.xml b/packages/SystemUI/res/drawable/recents_lock_to_task_button_bg.xml
index 6424a65..8a8164a 100644
--- a/packages/SystemUI/res/drawable/recents_lock_to_task_button_bg.xml
+++ b/packages/SystemUI/res/drawable/recents_lock_to_task_button_bg.xml
@@ -16,5 +16,11 @@
 
 <ripple xmlns:android="http://schemas.android.com/apk/res/android"
      android:color="#ff9cdfd9">
-    <item android:drawable="@drawable/btn_fab_recents" />
+     <item>
+          <shape android:shape="oval">
+               <solid android:color="#9cc8c4" />
+               <size android:width="@dimen/recents_lock_to_app_size"
+                     android:height="@dimen/recents_lock_to_app_size" />
+          </shape>
+     </item>
 </ripple>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml b/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
index 5c776e6..456d2f9 100644
--- a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
+++ b/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
@@ -57,6 +57,7 @@
                 android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
                 android:layout_height="match_parent"
                 android:src="@drawable/ic_sysbar_back"
+                android:scaleType="centerInside"
                 systemui:keyCode="4"
                 android:layout_weight="0"
                 android:contentDescription="@string/accessibility_back"
@@ -65,6 +66,7 @@
                 android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
                 android:layout_height="match_parent"
                 android:src="@drawable/ic_sysbar_home"
+                android:scaleType="centerInside"
                 systemui:keyCode="3"
                 systemui:keyRepeat="true"
                 android:layout_weight="0"
@@ -74,6 +76,7 @@
                 android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
                 android:layout_height="match_parent"
                 android:src="@drawable/ic_sysbar_recent"
+                android:scaleType="centerInside"
                 android:layout_weight="0"
                 android:contentDescription="@string/accessibility_recent"
                 />
@@ -91,6 +94,7 @@
                     android:layout_width="@dimen/navigation_extra_key_width"
                     android:layout_height="match_parent"
                     android:src="@drawable/ic_sysbar_menu"
+                    android:scaleType="centerInside"
                     android:layout_marginEnd="2dp"
                     systemui:keyCode="82"
                     android:visibility="invisible"
@@ -198,6 +202,7 @@
                 android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
                 android:layout_height="match_parent"
                 android:src="@drawable/ic_sysbar_back"
+                android:scaleType="centerInside"
                 systemui:keyCode="4"
                 android:layout_weight="0"
                 android:contentDescription="@string/accessibility_back"
@@ -206,6 +211,7 @@
                 android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
                 android:layout_height="match_parent"
                 android:src="@drawable/ic_sysbar_home"
+                android:scaleType="centerInside"
                 systemui:keyCode="3"
                 systemui:keyRepeat="true"
                 android:layout_weight="0"
@@ -215,6 +221,7 @@
                 android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
                 android:layout_height="match_parent"
                 android:src="@drawable/ic_sysbar_recent"
+                android:scaleType="centerInside"
                 android:layout_weight="0"
                 android:contentDescription="@string/accessibility_recent"
                 />
@@ -233,6 +240,7 @@
                     android:layout_height="match_parent"
                     android:layout_marginEnd="2dp"
                     android:src="@drawable/ic_sysbar_menu"
+                    android:scaleType="centerInside"
                     systemui:keyCode="82"
                     android:visibility="invisible"
                     android:contentDescription="@string/accessibility_menu" />
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index d1d3828..9c6f67c 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -29,8 +29,8 @@
         <include layout="@layout/recents_task_view_header" />
         <FrameLayout
             android:id="@+id/lock_to_app_fab"
-            android:layout_width="48dp"
-            android:layout_height="48dp"
+            android:layout_width="@dimen/recents_lock_to_app_size"
+            android:layout_height="@dimen/recents_lock_to_app_size"
             android:layout_gravity="bottom|right"
             android:layout_marginRight="15dp"
             android:layout_marginBottom="15dp"
@@ -38,8 +38,8 @@
             android:contentDescription="@string/recents_lock_to_app_button_label"
             android:background="@drawable/recents_lock_to_task_button_bg">
             <ImageView
-                android:layout_width="24dp"
-                android:layout_height="24dp"
+                android:layout_width="@dimen/recents_lock_to_app_icon_size"
+                android:layout_height="@dimen/recents_lock_to_app_icon_size"
                 android:layout_gravity="center"
                 android:src="@drawable/recents_lock_to_app_pin" />
         </FrameLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
index ef85847..4526af5 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
@@ -32,6 +32,7 @@
         />
 
     <LinearLayout
+        android:id="@+id/content"
         android:layout_width="match_parent"
         android:layout_height="match_parent">
         <TextView
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 44e0fd1..1152eea 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -144,42 +144,61 @@
 
     <!-- The duration in seconds to wait before the dismiss buttons are shown. -->
     <integer name="recents_task_bar_dismiss_delay_seconds">1</integer>
+
     <!-- The min animation duration for animating views that are currently visible. -->
     <integer name="recents_filter_animate_current_views_duration">250</integer>
+
     <!-- The min animation duration for animating views that are newly visible. -->
     <integer name="recents_filter_animate_new_views_duration">250</integer>
-    <!-- The min animation duration for animating the task bar in. -->
-    <integer name="recents_animate_task_bar_enter_duration">225</integer>
-    <!-- The animation delay for animating the first task in. This should roughly be the animation
-     duration of the transition in to recents. -->
-    <integer name="recents_animate_task_bar_enter_delay">275</integer>
-    <!-- The min animation duration for animating the task bar out. -->
-    <integer name="recents_animate_task_exit_to_home_duration">225</integer>
-    <!-- The min animation duration for animating the task bar out. -->
-    <integer name="recents_animate_task_bar_exit_duration">125</integer>
-    <!-- The animation delay for animating the first task in. This should roughly be the animation
-     duration of the transition in to recents from home. -->
-    <integer name="recents_animate_task_enter_from_home_delay">150</integer>
-    <!-- The min animation duration for animating the task in when transitioning from home. -->
-    <integer name="recents_animate_task_enter_from_home_duration">250</integer>
-    <!-- The animation stagger to apply to each task animation when transitioning from home. -->
-    <integer name="recents_animate_task_enter_from_home_stagger_delay">12</integer>
-    <!-- The short duration when animating in/out the lock to app button. -->
-    <integer name="recents_animate_lock_to_app_button_short_duration">150</integer>
-    <!-- The long duration when animating in/out the lock to app button. -->
-    <integer name="recents_animate_lock_to_app_button_long_duration">300</integer>
+
+    <!-- The duration of the window transition when coming to Recents from an app.
+         In order to defer the in-app animations until after the transition is complete,
+         we also need to use this value as the starting delay when animating the first
+         task decorations in. -->
+    <integer name="recents_enter_from_app_transition_duration">325</integer>
+
+    <!-- The duration for animating the task decorations in after transitioning from an app. -->
+    <integer name="recents_task_enter_from_app_duration">200</integer>
+
+    <!-- The duration for animating the task decorations out before transitioning to an app. -->
+    <integer name="recents_task_exit_to_app_duration">125</integer>
+
+    <!-- The duration of the window transition when coming to Recents from the Launcher.
+         In order to defer the in-app animations until after the transition is complete,
+         we also need to use this value as the starting delay when animating the task views
+         in from the bottom of the screen. -->
+    <integer name="recents_enter_from_home_transition_duration">100</integer>
+
+    <!-- The duration for animating the task from the bottom of the screen when transitioning
+     from home. -->
+    <integer name="recents_task_enter_from_home_duration">225</integer>
+
+    <!-- The stagger for each task when animating the task from the bottom of the screen when 
+     transitioning from home. -->
+    <integer name="recents_task_enter_from_home_stagger_delay">12</integer>
+
+    <!-- The duration of the animation of the tasks to the bottom of the screen when leaving
+     Recents to go back to the Launcher. -->
+    <integer name="recents_task_exit_to_home_duration">225</integer>
+
     <!-- The min animation duration for animating the nav bar scrim in. -->
     <integer name="recents_nav_bar_scrim_enter_duration">400</integer>
+
     <!-- The animation duration for animating the removal of a task view. -->
     <integer name="recents_animate_task_view_remove_duration">250</integer>
+
     <!-- The animation duration for scrolling the stack to a particular item. -->
     <integer name="recents_animate_task_stack_scroll_duration">225</integer>
+
     <!-- The minimum alpha for the dim applied to cards that go deeper into the stack. -->
     <integer name="recents_max_task_stack_view_dim">96</integer>
+
     <!-- The delay to enforce between each alt-tab key press. -->
     <integer name="recents_alt_tab_key_delay">200</integer>
+
     <!-- Transposes the search bar layout in landscape. -->
     <bool name="recents_has_transposed_search_bar">true</bool>
+
     <!-- Transposes the nav bar in landscape (only used for purposes of layout). -->
     <bool name="recents_has_transposed_nav_bar">true</bool>
     <!-- Svelte specific logic, see RecentsConfiguration.SVELTE_* constants. -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 3d9f723..1143553 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -226,9 +226,6 @@
     <!-- The amount of highlight to make on each task view. -->
     <dimen name="recents_task_view_highlight">1.5dp</dimen>
 
-    <!-- The height of the lock-to-app button. -->
-    <dimen name="recents_task_view_lock_to_app_button_height">48dp</dimen>
-
     <!-- The amount to offset when animating into an affiliate group. -->
     <dimen name="recents_task_view_affiliate_group_enter_offset">64dp</dimen>
 
@@ -257,6 +254,12 @@
     <!-- The min alpha to apply to a task affiliation group color. -->
     <item name="recents_task_affiliation_color_min_alpha_percentage" format="float" type="dimen">0.6</item>
 
+    <!-- The size of the lock-to-app button. -->
+    <dimen name="recents_lock_to_app_size">56dp</dimen>
+
+    <!-- The size of the lock-to-app button icon. -->
+    <dimen name="recents_lock_to_app_icon_size">28dp</dimen>
+
     <!-- Space reserved for the cards behind the top card in the top stack -->
     <dimen name="top_stack_peek_amount">12dp</dimen>
 
diff --git a/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java b/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java
new file mode 100644
index 0000000..2ff8f8a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.Paint;
+import android.view.View;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+
+import com.android.systemui.statusbar.phone.NotificationPanelView;
+
+/**
+ * Helper to invert the colors of views and fade between the states.
+ */
+public class ViewInvertHelper {
+
+    private final Paint mDarkPaint = new Paint();
+    private final Interpolator mLinearOutSlowInInterpolator;
+    private final View mTarget;
+    private final ColorMatrix mMatrix = new ColorMatrix();
+    private final ColorMatrix mGrayscaleMatrix = new ColorMatrix();
+    private final long mFadeDuration;
+
+    public ViewInvertHelper(View target, long fadeDuration) {
+        mTarget = target;
+        mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(mTarget.getContext(),
+                android.R.interpolator.linear_out_slow_in);
+        mFadeDuration = fadeDuration;
+    }
+
+    public void fade(final boolean invert, long delay) {
+        float startIntensity = invert ? 0f : 1f;
+        float endIntensity = invert ? 1f : 0f;
+        ValueAnimator animator = ValueAnimator.ofFloat(startIntensity, endIntensity);
+        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                updateInvertPaint((Float) animation.getAnimatedValue());
+                mTarget.setLayerType(View.LAYER_TYPE_HARDWARE, mDarkPaint);
+            }
+        });
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                if (!invert) {
+                    mTarget.setLayerType(View.LAYER_TYPE_NONE, null);
+                }
+            }
+        });
+        animator.setDuration(mFadeDuration);
+        animator.setInterpolator(mLinearOutSlowInInterpolator);
+        animator.setStartDelay(delay);
+        animator.start();
+    }
+
+    public void update(boolean invert) {
+        if (invert) {
+            updateInvertPaint(1f);
+            mTarget.setLayerType(View.LAYER_TYPE_HARDWARE, mDarkPaint);
+        } else {
+            mTarget.setLayerType(View.LAYER_TYPE_NONE, null);
+        }
+    }
+
+    public View getTarget() {
+        return mTarget;
+    }
+
+    private void updateInvertPaint(float intensity) {
+        float components = 1 - 2 * intensity;
+        final float[] invert = {
+                components, 0f,         0f,         0f, 255f * intensity,
+                0f,         components, 0f,         0f, 255f * intensity,
+                0f,         0f,         components, 0f, 255f * intensity,
+                0f,         0f,         0f,         1f, 0f
+        };
+        mMatrix.set(invert);
+        mGrayscaleMatrix.setSaturation(1 - intensity);
+        mMatrix.preConcat(mGrayscaleMatrix);
+        mDarkPaint.setColorFilter(new ColorMatrixColorFilter(mMatrix));
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java b/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java
index 0ab6626..4f812bc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java
@@ -26,24 +26,26 @@
 
 /** Helper for managing a secure setting. **/
 public abstract class SecureSetting extends ContentObserver implements Listenable {
+    private static final int DEFAULT = 0;
+
     private final Context mContext;
     private final String mSettingName;
 
     private boolean mListening;
     private int mUserId;
+    private int mObservedValue = DEFAULT;
 
-    protected abstract void handleValueChanged(int value);
+    protected abstract void handleValueChanged(int value, boolean observedChange);
 
     public SecureSetting(Context context, Handler handler, String settingName) {
         super(handler);
         mContext = context;
         mSettingName = settingName;
         mUserId = ActivityManager.getCurrentUser();
-        setListening(true);
     }
 
     public int getValue() {
-        return Secure.getIntForUser(mContext.getContentResolver(), mSettingName, 0, mUserId);
+        return Secure.getIntForUser(mContext.getContentResolver(), mSettingName, DEFAULT, mUserId);
     }
 
     public void setValue(int value) {
@@ -52,18 +54,23 @@
 
     @Override
     public void setListening(boolean listening) {
+        if (listening == mListening) return;
         mListening = listening;
         if (listening) {
+            mObservedValue = getValue();
             mContext.getContentResolver().registerContentObserver(
                     Secure.getUriFor(mSettingName), false, this, mUserId);
         } else {
             mContext.getContentResolver().unregisterContentObserver(this);
+            mObservedValue = DEFAULT;
         }
     }
 
     @Override
     public void onChange(boolean selfChange) {
-        handleValueChanged(getValue());
+        final int value = getValue();
+        handleValueChanged(value, value != mObservedValue);
+        mObservedValue = value;
     }
 
     public void setUserId(int userId) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 4d77348..1bc1d77 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -77,6 +77,10 @@
 
     @Override
     protected void handleSecondaryClick() {
+        if (!mState.value) {
+            mState.value = true;
+            mController.setBluetoothEnabled(true);
+        }
         showDetail(true);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 178590b..80ddd4a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -29,7 +29,8 @@
 import com.android.systemui.qs.QSTileView;
 import com.android.systemui.qs.SignalTileView;
 import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.NetworkController.DataUsageInfo;
+import com.android.systemui.statusbar.policy.NetworkController.MobileDataController;
+import com.android.systemui.statusbar.policy.NetworkController.MobileDataController.DataUsageInfo;
 import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
 
 /** Quick settings tile: Cellular **/
@@ -38,11 +39,13 @@
             "com.android.settings", "com.android.settings.Settings$DataUsageSummaryActivity"));
 
     private final NetworkController mController;
+    private final MobileDataController mDataController;
     private final CellularDetailAdapter mDetailAdapter;
 
     public CellularTile(Host host) {
         super(host);
         mController = host.getNetworkController();
+        mDataController = mController.getMobileDataController();
         mDetailAdapter = new CellularDetailAdapter();
     }
 
@@ -72,7 +75,7 @@
 
     @Override
     protected void handleClick() {
-        if (mController.isMobileDataSupported()) {
+        if (mDataController.isMobileDataSupported()) {
             showDetail(true);
         } else {
             mHost.startSettingsActivity(CELLULAR_SETTINGS);
@@ -199,7 +202,8 @@
 
         @Override
         public Boolean getToggleState() {
-            return mController.isMobileDataSupported() ? mController.isMobileDataEnabled() : null;
+            return mDataController.isMobileDataSupported()
+                    ? mDataController.isMobileDataEnabled() : null;
         }
 
         @Override
@@ -209,7 +213,7 @@
 
         @Override
         public void setToggleState(boolean state) {
-            mController.setMobileDataEnabled(state);
+            mDataController.setMobileDataEnabled(state);
         }
 
         @Override
@@ -217,7 +221,7 @@
             final DataUsageDetailView v = (DataUsageDetailView) (convertView != null
                     ? convertView
                     : LayoutInflater.from(mContext).inflate(R.layout.data_usage, parent, false));
-            final DataUsageInfo info = mController.getDataUsageInfo();
+            final DataUsageInfo info = mDataController.getDataUsageInfo();
             if (info == null) return v;
             v.bind(info);
             return v;
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 b565afa..5963a45 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -41,8 +41,10 @@
         mSetting = new SecureSetting(mContext, mHandler,
                 Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED) {
             @Override
-            protected void handleValueChanged(int value) {
-                mUsageTracker.trackUsage();
+            protected void handleValueChanged(int value, boolean observedChange) {
+                if (value != 0 || observedChange) {
+                    mUsageTracker.trackUsage();
+                }
                 if (mListening) {
                     handleRefreshState(value);
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
index 7bdb58f..eb816b7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
@@ -20,7 +20,6 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.util.AttributeSet;
-import android.util.TypedValue;
 import android.view.View;
 import android.widget.LinearLayout;
 import android.widget.TextView;
@@ -61,7 +60,7 @@
                 R.dimen.qs_data_usage_text_size);
     }
 
-    public void bind(NetworkController.DataUsageInfo info) {
+    public void bind(NetworkController.MobileDataController.DataUsageInfo info) {
         final Resources res = mContext.getResources();
         final int titleId;
         final long bytes;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 7aa884e..4fb1189 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -31,7 +31,8 @@
 import com.android.systemui.qs.QSTileView;
 import com.android.systemui.qs.SignalTileView;
 import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.NetworkController.AccessPoint;
+import com.android.systemui.statusbar.policy.NetworkController.AccessPointController;
+import com.android.systemui.statusbar.policy.NetworkController.AccessPointController.AccessPoint;
 import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
 
 /** Quick settings tile: Wifi **/
@@ -39,12 +40,14 @@
     private static final Intent WIFI_SETTINGS = new Intent(Settings.ACTION_WIFI_SETTINGS);
 
     private final NetworkController mController;
+    private final AccessPointController mWifiController;
     private final WifiDetailAdapter mDetailAdapter;
     private final QSTile.SignalState mStateBeforeClick = newTileState();
 
     public WifiTile(Host host) {
         super(host);
         mController = host.getNetworkController();
+        mWifiController = mController.getAccessPointController();
         mDetailAdapter = new WifiDetailAdapter();
     }
 
@@ -62,10 +65,10 @@
     public void setListening(boolean listening) {
         if (listening) {
             mController.addNetworkSignalChangedCallback(mCallback);
-            mController.addAccessPointCallback(mDetailAdapter);
+            mWifiController.addAccessPointCallback(mDetailAdapter);
         } else {
             mController.removeNetworkSignalChangedCallback(mCallback);
-            mController.removeAccessPointCallback(mDetailAdapter);
+            mWifiController.removeAccessPointCallback(mDetailAdapter);
         }
     }
 
@@ -87,7 +90,7 @@
 
     @Override
     protected void handleSecondaryClick() {
-        if (!mController.canConfigWifi()) {
+        if (!mWifiController.canConfigWifi()) {
             mHost.startSettingsActivity(new Intent(Settings.ACTION_WIFI_SETTINGS));
             return;
         }
@@ -231,7 +234,7 @@
     };
 
     private final class WifiDetailAdapter implements DetailAdapter,
-            NetworkController.AccessPointCallback, QSDetailItems.Callback {
+            NetworkController.AccessPointController.AccessPointCallback, QSDetailItems.Callback {
 
         private QSDetailItems mItems;
         private AccessPoint[] mAccessPoints;
@@ -261,7 +264,7 @@
         public View createDetailView(Context context, View convertView, ViewGroup parent) {
             if (DEBUG) Log.d(TAG, "createDetailView convertView=" + (convertView != null));
             mAccessPoints = null;
-            mController.scanForAccessPoints();
+            mWifiController.scanForAccessPoints();
             fireScanStateChanged(true);
             mItems = QSDetailItems.convertOrInflate(context, convertView, parent);
             mItems.setTagSuffix("Wifi");
@@ -287,7 +290,7 @@
             if (item == null || item.tag == null) return;
             final AccessPoint ap = (AccessPoint) item.tag;
             if (!ap.isConnected) {
-                if (mController.connect(ap)) {
+                if (mWifiController.connect(ap)) {
                     mHost.collapsePanels();
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index d1eadd8..676f1ab 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -431,8 +431,6 @@
         // Update if we are getting a configuration change
         if (savedInstanceState != null) {
             // Update RecentsConfiguration
-            mConfig = RecentsConfiguration.reinitialize(this,
-                    RecentsTaskLoader.getInstance().getSystemServicesProxy());
             mConfig.updateOnConfigurationChange();
             // Trigger the enter animation
             onEnterAnimationTriggered();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 43d9dc1..2b33d14 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -86,11 +86,15 @@
     public float taskStackWidthPaddingPct;
     public float taskStackOverscrollPct;
 
+    /** Transitions */
+    public int transitionEnterFromAppDelay;
+    public int transitionEnterFromHomeDelay;
+
     /** Task view animation and styles */
-    public int taskViewEnterFromHomeDelay;
+    public int taskViewEnterFromAppDuration;
     public int taskViewEnterFromHomeDuration;
     public int taskViewEnterFromHomeStaggerDelay;
-    public int taskViewEnterFromHomeStaggerDuration;
+    public int taskViewExitToAppDuration;
     public int taskViewExitToHomeDuration;
     public int taskViewRemoveAnimDuration;
     public int taskViewRemoveAnimTranslationXPx;
@@ -110,16 +114,8 @@
 
     /** Task bar size & animations */
     public int taskBarHeight;
-    public int taskBarEnterAnimDuration;
-    public int taskBarEnterAnimDelay;
-    public int taskBarExitAnimDuration;
     public int taskBarDismissDozeDelaySeconds;
 
-    /** Lock to app */
-    public int taskViewLockToAppButtonHeight;
-    public int taskViewLockToAppShortAnimDuration;
-    public int taskViewLockToAppLongAnimDuration;
-
     /** Nav bar scrim */
     public int navBarScrimEnterDuration;
 
@@ -226,15 +222,23 @@
         taskStackMaxDim = res.getInteger(R.integer.recents_max_task_stack_view_dim);
         taskStackTopPaddingPx = res.getDimensionPixelSize(R.dimen.recents_stack_top_padding);
 
+        // Transition
+        transitionEnterFromAppDelay =
+                res.getInteger(R.integer.recents_enter_from_app_transition_duration);
+        transitionEnterFromHomeDelay =
+                res.getInteger(R.integer.recents_enter_from_home_transition_duration);
+
         // Task view animation and styles
-        taskViewEnterFromHomeDelay =
-                res.getInteger(R.integer.recents_animate_task_enter_from_home_delay);
+        taskViewEnterFromAppDuration =
+                res.getInteger(R.integer.recents_task_enter_from_app_duration);
         taskViewEnterFromHomeDuration =
-                res.getInteger(R.integer.recents_animate_task_enter_from_home_duration);
+                res.getInteger(R.integer.recents_task_enter_from_home_duration);
         taskViewEnterFromHomeStaggerDelay =
-                res.getInteger(R.integer.recents_animate_task_enter_from_home_stagger_delay);
+                res.getInteger(R.integer.recents_task_enter_from_home_stagger_delay);
+        taskViewExitToAppDuration =
+                res.getInteger(R.integer.recents_task_exit_to_app_duration);
         taskViewExitToHomeDuration =
-                res.getInteger(R.integer.recents_animate_task_exit_to_home_duration);
+                res.getInteger(R.integer.recents_task_exit_to_home_duration);
         taskViewRemoveAnimDuration =
                 res.getInteger(R.integer.recents_animate_task_view_remove_duration);
         taskViewRemoveAnimTranslationXPx =
@@ -265,23 +269,9 @@
 
         // Task bar size & animations
         taskBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height);
-        taskBarEnterAnimDuration =
-                res.getInteger(R.integer.recents_animate_task_bar_enter_duration);
-        taskBarEnterAnimDelay =
-                res.getInteger(R.integer.recents_animate_task_bar_enter_delay);
-        taskBarExitAnimDuration =
-                res.getInteger(R.integer.recents_animate_task_bar_exit_duration);
         taskBarDismissDozeDelaySeconds =
                 res.getInteger(R.integer.recents_task_bar_dismiss_delay_seconds);
 
-        // Lock to app
-        taskViewLockToAppButtonHeight =
-                res.getDimensionPixelSize(R.dimen.recents_task_view_lock_to_app_button_height);
-        taskViewLockToAppShortAnimDuration =
-                res.getInteger(R.integer.recents_animate_lock_to_app_button_short_duration);
-        taskViewLockToAppLongAnimDuration =
-                res.getInteger(R.integer.recents_animate_lock_to_app_button_long_duration);
-
         // Nav bar scrim
         navBarScrimEnterDuration =
                 res.getInteger(R.integer.recents_nav_bar_scrim_enter_duration);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index 67a36b9..ba2903a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -170,65 +170,65 @@
             } else {
                 RecentsConfiguration config = RecentsConfiguration.getInstance();
                 SystemServicesProxy ssp = mSystemServicesProxy;
-                // If we've stopped the loader, then fall thorugh to the above logic to wait on
+                // If we've stopped the loader, then fall through to the above logic to wait on
                 // the load thread
-                if (ssp == null) continue;
+                if (ssp != null) {
+                    // Load the next item from the queue
+                    final Task t = mLoadQueue.nextTask();
+                    if (t != null) {
+                        Drawable cachedIcon = mApplicationIconCache.get(t.key);
+                        Bitmap cachedThumbnail = mThumbnailCache.get(t.key);
 
-                // Load the next item from the queue
-                final Task t = mLoadQueue.nextTask();
-                if (t != null) {
-                    Drawable cachedIcon = mApplicationIconCache.get(t.key);
-                    Bitmap cachedThumbnail = mThumbnailCache.get(t.key);
-
-                    // Load the application icon if it is stale or we haven't cached one yet
-                    if (cachedIcon == null) {
-                        cachedIcon = getTaskDescriptionIcon(t.key, t.icon, t.iconFilename, ssp,
-                                mContext.getResources());
-
+                        // Load the application icon if it is stale or we haven't cached one yet
                         if (cachedIcon == null) {
-                            ActivityInfo info = ssp.getActivityInfo(t.key.baseIntent.getComponent(),
-                                    t.key.userId);
-                            if (info != null) {
-                                if (DEBUG) Log.d(TAG, "Loading icon: " + t.key);
-                                cachedIcon = ssp.getActivityIcon(info, t.key.userId);
+                            cachedIcon = getTaskDescriptionIcon(t.key, t.icon, t.iconFilename, ssp,
+                                    mContext.getResources());
+
+                            if (cachedIcon == null) {
+                                ActivityInfo info = ssp.getActivityInfo(
+                                        t.key.baseIntent.getComponent(), t.key.userId);
+                                if (info != null) {
+                                    if (DEBUG) Log.d(TAG, "Loading icon: " + t.key);
+                                    cachedIcon = ssp.getActivityIcon(info, t.key.userId);
+                                }
                             }
-                        }
 
-                        if (cachedIcon == null) {
-                            cachedIcon = mDefaultApplicationIcon;
-                        }
+                            if (cachedIcon == null) {
+                                cachedIcon = mDefaultApplicationIcon;
+                            }
 
-                        // At this point, even if we can't load the icon, we will set the default
-                        // icon.
-                        mApplicationIconCache.put(t.key, cachedIcon);
-                    }
-                    // Load the thumbnail if it is stale or we haven't cached one yet
-                    if (cachedThumbnail == null) {
-                        if (config.svelteLevel < RecentsConfiguration.SVELTE_DISABLE_LOADING) {
-                            if (DEBUG) Log.d(TAG, "Loading thumbnail: " + t.key);
-                            cachedThumbnail = ssp.getTaskThumbnail(t.key.id);
+                            // At this point, even if we can't load the icon, we will set the
+                            // default icon.
+                            mApplicationIconCache.put(t.key, cachedIcon);
                         }
+                        // Load the thumbnail if it is stale or we haven't cached one yet
                         if (cachedThumbnail == null) {
-                            cachedThumbnail = mDefaultThumbnail;
-                        }
-                        // When svelte, we trim the memory to just the visible thumbnails when
-                        // leaving, so don't thrash the cache as the user scrolls (just load them
-                        // from scratch each time)
-                        if (config.svelteLevel < RecentsConfiguration.SVELTE_LIMIT_CACHE) {
-                            mThumbnailCache.put(t.key, cachedThumbnail);
-                        }
-                    }
-                    if (!mCancelled) {
-                        // Notify that the task data has changed
-                        final Drawable newIcon = cachedIcon;
-                        final Bitmap newThumbnail = cachedThumbnail == mDefaultThumbnail
-                                ? null : cachedThumbnail;
-                        mMainThreadHandler.post(new Runnable() {
-                            @Override
-                            public void run() {
-                                t.notifyTaskDataLoaded(newThumbnail, newIcon);
+                            if (config.svelteLevel < RecentsConfiguration.SVELTE_DISABLE_LOADING) {
+                                if (DEBUG) Log.d(TAG, "Loading thumbnail: " + t.key);
+                                cachedThumbnail = ssp.getTaskThumbnail(t.key.id);
                             }
-                        });
+                            if (cachedThumbnail == null) {
+                                cachedThumbnail = mDefaultThumbnail;
+                            }
+                            // When svelte, we trim the memory to just the visible thumbnails when
+                            // leaving, so don't thrash the cache as the user scrolls (just load
+                            // them from scratch each time)
+                            if (config.svelteLevel < RecentsConfiguration.SVELTE_LIMIT_CACHE) {
+                                mThumbnailCache.put(t.key, cachedThumbnail);
+                            }
+                        }
+                        if (!mCancelled) {
+                            // Notify that the task data has changed
+                            final Drawable newIcon = cachedIcon;
+                            final Bitmap newThumbnail = cachedThumbnail == mDefaultThumbnail
+                                    ? null : cachedThumbnail;
+                            mMainThreadHandler.post(new Runnable() {
+                                @Override
+                                public void run() {
+                                    t.notifyTaskDataLoaded(newThumbnail, newIcon);
+                                }
+                            });
+                        }
                     }
                 }
 
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 5f8f3f2..fb05c01 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.recents.views;
 
-import android.animation.ObjectAnimator;
 import android.graphics.Outline;
 import android.graphics.Rect;
 import android.view.View;
@@ -35,8 +34,6 @@
     float mAlpha = 1f;
     final float mMinAlpha = 0.25f;
 
-    ObjectAnimator mClipBottomAnimator;
-
     public AnimateableViewBounds(TaskView source, int cornerRadius) {
         mConfig = RecentsConfiguration.getInstance();
         mSourceView = source;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
index 162897e..1086160 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
@@ -64,7 +64,9 @@
             mStatusBarScrimView.setTranslationY(-mStatusBarScrimView.getMeasuredHeight());
             mStatusBarScrimView.animate()
                     .translationY(0)
-                    .setStartDelay(mConfig.taskBarEnterAnimDelay)
+                    .setStartDelay(mConfig.launchedFromHome ?
+                            mConfig.transitionEnterFromHomeDelay :
+                            mConfig.transitionEnterFromAppDelay)
                     .setDuration(mConfig.navBarScrimEnterDuration)
                     .setInterpolator(mConfig.quintOutInterpolator)
                     .withStartAction(new Runnable() {
@@ -79,7 +81,9 @@
             mNavBarScrimView.setTranslationY(mNavBarScrimView.getMeasuredHeight());
             mNavBarScrimView.animate()
                     .translationY(0)
-                    .setStartDelay(mConfig.taskBarEnterAnimDelay)
+                    .setStartDelay(mConfig.launchedFromHome ?
+                            mConfig.transitionEnterFromHomeDelay :
+                            mConfig.transitionEnterFromAppDelay)
                     .setDuration(mConfig.navBarScrimEnterDuration)
                     .setInterpolator(mConfig.quintOutInterpolator)
                     .withStartAction(new Runnable() {
@@ -101,7 +105,7 @@
             mStatusBarScrimView.animate()
                     .translationY(-mStatusBarScrimView.getMeasuredHeight())
                     .setStartDelay(0)
-                    .setDuration(mConfig.taskBarExitAnimDuration)
+                    .setDuration(mConfig.taskViewExitToAppDuration)
                     .setInterpolator(mConfig.fastOutSlowInInterpolator)
                     .start();
         }
@@ -109,7 +113,7 @@
             mNavBarScrimView.animate()
                     .translationY(mNavBarScrimView.getMeasuredHeight())
                     .setStartDelay(0)
-                    .setDuration(mConfig.taskBarExitAnimDuration)
+                    .setDuration(mConfig.taskViewExitToAppDuration)
                     .setInterpolator(mConfig.fastOutSlowInInterpolator)
                     .start();
         }
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 1731d38..5732879 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -186,6 +186,7 @@
             mUIDozeTrigger.stopDozing();
             mUIDozeTrigger.resetTrigger();
         }
+        mStackScroller.reset();
     }
 
     /** Requests that the views be synchronized with the model */
@@ -659,9 +660,10 @@
         // If this is the first layout, then scroll to the front of the stack and synchronize the
         // stack views immediately to load all the views
         if (mAwaitingFirstLayout) {
-            mStackScroller.setStackScrollToInitialState();
-            requestSynchronizeStackViewsWithModel();
-            synchronizeStackViewsWithModel();
+            if (mStackScroller.setStackScrollToInitialState()) {
+                requestSynchronizeStackViewsWithModel();
+                synchronizeStackViewsWithModel();
+            }
         }
 
         // Measure each of the TaskViews
@@ -915,7 +917,7 @@
             TaskView frontTv = getChildViewForTask(newFrontMostTask);
             if (frontTv != null) {
                 frontTv.onTaskBound(newFrontMostTask);
-                frontTv.fadeInActionButton(false);
+                frontTv.fadeInActionButton(0, mConfig.taskViewEnterFromAppDuration);
             }
         }
 
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 04f7c6f..f7067be 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
@@ -48,6 +48,11 @@
         setStackScroll(getStackScroll());
     }
 
+    /** Resets the task scroller. */
+    void reset() {
+        mStackScrollP = 0f;
+    }
+
     /** Sets the callbacks */
     void setCallbacks(TaskStackViewScrollerCallbacks cb) {
         mCb = cb;
@@ -71,9 +76,14 @@
         mStackScrollP = s;
     }
 
-    /** Sets the current stack scroll to the initial state when you first enter recents */
-    public void setStackScrollToInitialState() {
+    /**
+     * Sets the current stack scroll to the initial state when you first enter recents.
+     * @return whether the stack progress changed.
+     */
+    public boolean setStackScrollToInitialState() {
+        float prevStackScrollP = mStackScrollP;
         setStackScroll(getBoundedStackScroll(mLayoutAlgorithm.mInitialScrollP));
+        return Float.compare(prevStackScrollP, mStackScrollP) != 0;
     }
 
     /** Bounds the current scroll if necessary */
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 27d2fda..d42fa15 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -24,7 +24,6 @@
 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;
@@ -271,24 +270,25 @@
                 if (Constants.DebugFlags.App.EnableThumbnailAlphaOnFrontmost) {
                     // Animate the thumbnail alpha before the dim animation (to prevent updating the
                     // hardware layer)
-                    mThumbnailView.startEnterRecentsAnimation(mConfig.taskBarEnterAnimDelay,
+                    mThumbnailView.startEnterRecentsAnimation(mConfig.transitionEnterFromAppDelay,
                             new Runnable() {
                                 @Override
                                 public void run() {
-                                    animateDimToProgress(0, mConfig.taskBarEnterAnimDuration,
+                                    animateDimToProgress(0, mConfig.taskViewEnterFromAppDuration,
                                             ctx.postAnimationTrigger.decrementOnAnimationEnd());
                                 }
                             });
                 } else {
                     // Immediately start the dim animation
-                    animateDimToProgress(mConfig.taskBarEnterAnimDelay,
-                            mConfig.taskBarEnterAnimDuration,
+                    animateDimToProgress(mConfig.transitionEnterFromAppDelay,
+                            mConfig.taskViewEnterFromAppDuration,
                             ctx.postAnimationTrigger.decrementOnAnimationEnd());
                 }
                 ctx.postAnimationTrigger.increment();
 
                 // Animate the action button in
-                fadeInActionButton(true);
+                fadeInActionButton(mConfig.transitionEnterFromAppDelay,
+                        mConfig.taskViewEnterFromAppDuration);
             } else {
                 // Animate the task up if it was occluding the launch target
                 if (ctx.currentTaskOccludesLaunchTarget) {
@@ -296,7 +296,7 @@
                     setAlpha(0f);
                     animate().alpha(1f)
                             .translationY(transform.translationY)
-                            .setStartDelay(mConfig.taskBarEnterAnimDelay)
+                            .setStartDelay(mConfig.transitionEnterFromAppDelay)
                             .setUpdateListener(null)
                             .setInterpolator(mConfig.fastOutSlowInInterpolator)
                             .setDuration(mConfig.taskViewEnterFromHomeDuration)
@@ -311,12 +311,12 @@
                     ctx.postAnimationTrigger.increment();
                 }
             }
-            startDelay = mConfig.taskBarEnterAnimDelay;
+            startDelay = mConfig.transitionEnterFromAppDelay;
 
         } else if (mConfig.launchedFromHome) {
             // Animate the tasks up
             int frontIndex = (ctx.currentStackViewCount - ctx.currentStackViewIndex - 1);
-            int delay = mConfig.taskViewEnterFromHomeDelay +
+            int delay = mConfig.transitionEnterFromHomeDelay +
                     frontIndex * mConfig.taskViewEnterFromHomeStaggerDelay;
 
             setScaleX(transform.scale);
@@ -353,19 +353,17 @@
         }, (startDelay / 2));
     }
 
-    public void fadeInActionButton(boolean withDelay) {
+    public void fadeInActionButton(int delay, int duration) {
         // Hide the action button
         mActionButtonView.setAlpha(0f);
 
         // Animate the action button in
-        ViewPropertyAnimator animator = mActionButtonView.animate().alpha(1f)
-                .setDuration(mConfig.taskBarEnterAnimDuration)
+        mActionButtonView.animate().alpha(1f)
+                .setStartDelay(delay)
+                .setDuration(duration)
                 .setInterpolator(PhoneStatusBar.ALPHA_IN)
-                .withLayer();
-        if (withDelay) {
-            animator.setStartDelay(mConfig.taskBarEnterAnimDelay);
-        }
-        animator.start();
+                .withLayer()
+                .start();
     }
 
     /** Animates this task view as it leaves recents by pressing home. */
@@ -391,7 +389,7 @@
             // Animate the dim
             if (mDimAlpha > 0) {
                 ObjectAnimator anim = ObjectAnimator.ofInt(this, "dim", 0);
-                anim.setDuration(mConfig.taskBarExitAnimDuration);
+                anim.setDuration(mConfig.taskViewExitToAppDuration);
                 anim.setInterpolator(mConfig.fastOutLinearInInterpolator);
                 anim.start();
             }
@@ -406,7 +404,7 @@
             mActionButtonView.animate()
                     .alpha(0f)
                     .setStartDelay(0)
-                    .setDuration(mConfig.taskBarExitAnimDuration)
+                    .setDuration(mConfig.taskViewExitToAppDuration)
                     .setInterpolator(mConfig.fastOutLinearInInterpolator)
                     .withLayer()
                     .start();
@@ -421,7 +419,7 @@
                     .setStartDelay(0)
                     .setUpdateListener(null)
                     .setInterpolator(mConfig.fastOutLinearInInterpolator)
-                    .setDuration(mConfig.taskBarExitAnimDuration)
+                    .setDuration(mConfig.taskViewExitToAppDuration)
                     .start();
             }
         }
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 5de84bd..1e5d9fc 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -235,7 +235,7 @@
                     .alpha(0f)
                     .setStartDelay(0)
                     .setInterpolator(mConfig.fastOutSlowInInterpolator)
-                    .setDuration(mConfig.taskBarExitAnimDuration)
+                    .setDuration(mConfig.taskViewExitToAppDuration)
                     .withLayer()
                     .start();
         }
@@ -249,7 +249,7 @@
                 .alpha(1f)
                 .setStartDelay(0)
                 .setInterpolator(mConfig.fastOutLinearInInterpolator)
-                .setDuration(mConfig.taskBarEnterAnimDuration)
+                .setDuration(mConfig.taskViewEnterFromAppDuration)
                 .withLayer()
                 .start();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index c83248e..117a7d3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -237,12 +237,12 @@
     /** Animates this task thumbnail as it enters Recents. */
     void startEnterRecentsAnimation(int delay, Runnable postAnimRunnable) {
         startFadeAnimation(mConfig.taskViewThumbnailAlpha, delay,
-                mConfig.taskBarEnterAnimDuration, postAnimRunnable);
+                mConfig.taskViewEnterFromAppDuration, postAnimRunnable);
     }
 
     /** Animates this task thumbnail as it exits Recents. */
     void startLaunchTaskAnimation(Runnable postAnimRunnable) {
-        startFadeAnimation(1f, 0, mConfig.taskBarExitAnimDuration, postAnimRunnable);
+        startFadeAnimation(1f, 0, mConfig.taskViewExitToAppDuration, postAnimRunnable);
     }
 
     /** Starts a new thumbnail alpha animation. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 02b9378..7b60307 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -43,6 +43,7 @@
 import android.view.animation.PathInterpolator;
 
 import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
 
 /**
  * Base class for both {@link ExpandableNotificationRow} and {@link NotificationOverflowContainer}
@@ -53,6 +54,7 @@
     private static final long DOUBLETAP_TIMEOUT_MS = 1200;
     private static final int BACKGROUND_ANIMATION_LENGTH_MS = 220;
     private static final int ACTIVATE_ANIMATION_LENGTH = 220;
+    private static final int DARK_ANIMATION_LENGTH = 170;
 
     /**
      * The amount of width, which is kept in the end when performing a disappear animation (also
@@ -84,6 +86,11 @@
      */
     private static final float VERTICAL_ANIMATION_START = 1.0f;
 
+    /**
+     * Scale for the background to animate from when exiting dark mode.
+     */
+    private static final float DARK_EXIT_SCALE_START = 0.93f;
+
     private static final Interpolator ACTIVATE_INVERSE_INTERPOLATOR
             = new PathInterpolator(0.6f, 0, 0.5f, 1);
     private static final Interpolator ACTIVATE_INVERSE_ALPHA_INTERPOLATOR
@@ -94,7 +101,6 @@
 
     private boolean mDimmed;
     private boolean mDark;
-    private final Paint mDarkPaint = createDarkPaint();
 
     private int mBgTint = 0;
     private final int mRoundedRectCornerRadius;
@@ -332,40 +338,32 @@
         if (mDimmed != dimmed) {
             mDimmed = dimmed;
             if (fade) {
-                fadeBackground();
+                fadeDimmedBackground();
             } else {
                 updateBackground();
             }
         }
     }
 
-    public void setDark(boolean dark, boolean fade) {
-        // TODO implement fade
-        if (mDark != dark) {
-            mDark = dark;
-            if (mDark) {
-                setLayerType(View.LAYER_TYPE_HARDWARE, mDarkPaint);
-            } else {
-                setLayerType(View.LAYER_TYPE_NONE, null);
-            }
+    public void setDark(boolean dark, boolean fade, long delay) {
+        super.setDark(dark, fade, delay);
+        if (mDark == dark) {
+            return;
         }
-    }
-
-    private static Paint createDarkPaint() {
-        final Paint p = new Paint();
-        final float[] invert = {
-            -1f,  0f,  0f, 1f, 1f,
-             0f, -1f,  0f, 1f, 1f,
-             0f,  0f, -1f, 1f, 1f,
-             0f,  0f,  0f, 1f, 0f
-        };
-        final ColorMatrix m = new ColorMatrix(invert);
-        final ColorMatrix grayscale = new ColorMatrix();
-        grayscale.setSaturation(0);
-        m.preConcat(grayscale);
-        p.setColorFilter(new ColorMatrixColorFilter(m));
-        return p;
-    }
+        mDark = dark;
+        if (!dark && fade) {
+            if (mActivated) {
+                mBackgroundDimmed.setVisibility(View.VISIBLE);
+                mBackgroundNormal.setVisibility(View.VISIBLE);
+            } else {
+                mBackgroundDimmed.setVisibility(View.VISIBLE);
+                mBackgroundNormal.setVisibility(View.INVISIBLE);
+            }
+            fadeDarkToDimmed(delay);
+        } else {
+            updateBackground();
+        }
+     }
 
     public void setShowingLegacyBackground(boolean showing) {
         mShowingLegacyBackground = showing;
@@ -402,7 +400,39 @@
         mBackgroundNormal.setRippleColor(rippleColor);
     }
 
-    private void fadeBackground() {
+    /**
+     * Fades the dimmed background when exiting dark mode.
+     */
+    private void fadeDarkToDimmed(long delay) {
+        mBackgroundDimmed.setAlpha(0f);
+        mBackgroundDimmed.setPivotX(mBackgroundDimmed.getWidth() / 2f);
+        mBackgroundDimmed.setPivotY(getActualHeight() / 2f);
+        mBackgroundDimmed.setScaleX(DARK_EXIT_SCALE_START);
+        mBackgroundDimmed.setScaleY(DARK_EXIT_SCALE_START);
+        mBackgroundDimmed.animate()
+                .alpha(1f)
+                .scaleX(1f)
+                .scaleY(1f)
+                .setDuration(DARK_ANIMATION_LENGTH)
+                .setStartDelay(delay)
+                .setInterpolator(mLinearOutSlowInInterpolator)
+                .setListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationCancel(Animator animation) {
+                        // Jump state if we are cancelled
+                        mBackgroundDimmed.setScaleX(1f);
+                        mBackgroundDimmed.setScaleY(1f);
+                        mBackgroundDimmed.setAlpha(1f);
+                    }
+                })
+                .start();
+    }
+
+    /**
+     * Fades the background when the dimmed state changes.
+     */
+    private void fadeDimmedBackground() {
+        mBackgroundDimmed.animate().cancel();
         mBackgroundNormal.animate().cancel();
         if (mDimmed) {
             mBackgroundDimmed.setVisibility(View.VISIBLE);
@@ -443,11 +473,14 @@
     }
 
     private void updateBackground() {
-        if (mDimmed) {
+        cancelFadeAnimations();
+        if (mDark) {
+            mBackgroundDimmed.setVisibility(View.INVISIBLE);
+            mBackgroundNormal.setVisibility(View.INVISIBLE);
+        } else if (mDimmed) {
             mBackgroundDimmed.setVisibility(View.VISIBLE);
             mBackgroundNormal.setVisibility(View.INVISIBLE);
         } else {
-            cancelFadeAnimations();
             mBackgroundDimmed.setVisibility(View.INVISIBLE);
             mBackgroundNormal.setVisibility(View.VISIBLE);
             mBackgroundNormal.setAlpha(1f);
@@ -459,6 +492,7 @@
         if (mBackgroundAnimator != null) {
             mBackgroundAnimator.cancel();
         }
+        mBackgroundDimmed.animate().cancel();
         mBackgroundNormal.animate().cancel();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 7345440..8ad8406 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -207,11 +207,11 @@
     }
 
     @Override
-    public void setDark(boolean dark, boolean fade) {
-        super.setDark(dark, fade);
+    public void setDark(boolean dark, boolean fade, long delay) {
+        super.setDark(dark, fade, delay);
         final NotificationContentView showing = getShowingLayout();
         if (showing != null) {
-            showing.setDark(dark, fade);
+            showing.setDark(dark, fade, delay);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index bf1e78e..ebc663c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -39,6 +39,7 @@
     private int mActualHeight;
     protected int mClipTopAmount;
     private boolean mActualHeightInitialized;
+    private boolean mDark;
     private ArrayList<View> mMatchParentViews = new ArrayList<View>();
 
     public ExpandableView(Context context, AttributeSet attrs) {
@@ -185,8 +186,14 @@
      *
      * @param dark Whether the notification should be dark.
      * @param fade Whether an animation should be played to change the state.
+     * @param delay If fading, the delay of the animation.
      */
-    public void setDark(boolean dark, boolean fade) {
+    public void setDark(boolean dark, boolean fade, long delay) {
+        mDark = dark;
+    }
+
+    public boolean isDark() {
+        return mDark;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 99214a0..27da6fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -42,14 +42,14 @@
 public class NotificationContentView extends FrameLayout {
 
     private static final long ANIMATION_DURATION_LENGTH = 170;
-    private static final Paint INVERT_PAINT = createInvertPaint();
-    private static final ColorFilter NO_COLOR_FILTER = new ColorFilter();
 
     private final Rect mClipBounds = new Rect();
 
     private View mContractedChild;
     private View mExpandedChild;
 
+    private NotificationViewWrapper mContractedWrapper;
+
     private int mSmallHeight;
     private int mClipTopAmount;
     private int mActualHeight;
@@ -84,8 +84,8 @@
     }
 
     @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
         updateVisibility();
     }
 
@@ -122,6 +122,7 @@
         sanitizeContractedLayoutParams(child);
         addView(child);
         mContractedChild = child;
+        mContractedWrapper = NotificationViewWrapper.wrap(getContext(), child);
         selectLayout(false /* animate */, true /* force */);
     }
 
@@ -249,38 +250,10 @@
         return mExpandedChild != null;
     }
 
-    public void setDark(boolean dark, boolean fade) {
+    public void setDark(boolean dark, boolean fade, long delay) {
         if (mDark == dark || mContractedChild == null) return;
         mDark = dark;
-        setImageViewDark(dark, fade, com.android.internal.R.id.right_icon);
-        setImageViewDark(dark, fade, com.android.internal.R.id.icon);
-    }
-
-    private void setImageViewDark(boolean dark, boolean fade, int imageViewId) {
-        // TODO: implement fade
-        final ImageView v = (ImageView) mContractedChild.findViewById(imageViewId);
-        if (v == null) return;
-        final Drawable d = v.getBackground();
-        if (dark) {
-            v.setLayerType(LAYER_TYPE_HARDWARE, INVERT_PAINT);
-            if (d != null) {
-                v.setTag(R.id.doze_saved_filter_tag, d.getColorFilter() != null ? d.getColorFilter()
-                        : NO_COLOR_FILTER);
-                d.setColorFilter(getResources().getColor(R.color.doze_small_icon_background_color),
-                        PorterDuff.Mode.SRC_ATOP);
-                v.setImageAlpha(getResources().getInteger(R.integer.doze_small_icon_alpha));
-            }
-        } else {
-            v.setLayerType(LAYER_TYPE_NONE, null);
-            if (d != null)  {
-                final ColorFilter filter = (ColorFilter) v.getTag(R.id.doze_saved_filter_tag);
-                if (filter != null) {
-                    d.setColorFilter(filter == NO_COLOR_FILTER ? null : filter);
-                    v.setTag(R.id.doze_saved_filter_tag, null);
-                }
-                v.setImageAlpha(0xff);
-            }
-        }
+        mContractedWrapper.setDark(dark, fade, delay);
     }
 
     @Override
@@ -290,16 +263,4 @@
         // layout, and saves us some layers.
         return false;
     }
-
-    private static Paint createInvertPaint() {
-        final Paint p = new Paint();
-        final float[] invert = {
-            -1f,  0f,  0f, 1f, 1f,
-             0f, -1f,  0f, 1f, 1f,
-             0f,  0f, -1f, 1f, 1f,
-             0f,  0f,  0f, 1f, 0f
-        };
-        p.setColorFilter(new ColorMatrixColorFilter(new ColorMatrix(invert)));
-        return p;
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationCustomViewWrapper.java
new file mode 100644
index 0000000..045be3e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationCustomViewWrapper.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.view.View;
+
+import com.android.systemui.ViewInvertHelper;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
+
+/**
+ * Wraps a notification containing a custom view.
+ */
+public class NotificationCustomViewWrapper extends NotificationViewWrapper {
+
+    private final ViewInvertHelper mInvertHelper;
+    private boolean mDark;
+
+    protected NotificationCustomViewWrapper(View view) {
+        super(view);
+        mInvertHelper = new ViewInvertHelper(view, NotificationPanelView.DOZE_ANIMATION_DURATION);
+    }
+
+    @Override
+    public void setDark(boolean dark, boolean fade, long delay) {
+        if (mDark != dark) {
+            mDark = dark;
+            if (fade) {
+                mInvertHelper.fade(dark, delay);
+            } else {
+                mInvertHelper.update(dark);
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaViewWrapper.java
new file mode 100644
index 0000000..8f63a79
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaViewWrapper.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.content.Context;
+import android.view.View;
+
+/**
+ * Wraps a media notification.
+ */
+public class NotificationMediaViewWrapper extends NotificationTemplateViewWrapper {
+
+    private boolean mDark;
+
+    protected NotificationMediaViewWrapper(Context ctx, View view) {
+        super(ctx, view);
+    }
+
+    @Override
+    public void setDark(boolean dark, boolean fade, long delay) {
+        if (mDark != dark) {
+            mDark = dark;
+
+            // Only update the large icon, because the rest is already inverted.
+            setPictureGrayscale(dark, fade, delay);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
index edfd205..bfa3aa5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
@@ -21,6 +21,8 @@
 import android.widget.TextView;
 
 import com.android.systemui.R;
+import com.android.systemui.ViewInvertHelper;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
 
 /**
  * Container view for overflowing notification icons on Keyguard.
@@ -28,6 +30,8 @@
 public class NotificationOverflowContainer extends ActivatableNotificationView {
 
     private NotificationOverflowIconsView mIconsView;
+    private ViewInvertHelper mViewInvertHelper;
+    private boolean mDark;
 
     public NotificationOverflowContainer(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -39,6 +43,20 @@
         mIconsView = (NotificationOverflowIconsView) findViewById(R.id.overflow_icons_view);
         mIconsView.setMoreText((TextView) findViewById(R.id.more_text));
         mIconsView.setOverflowIndicator(findViewById(R.id.more_icon_overflow));
+        mViewInvertHelper = new ViewInvertHelper(findViewById(R.id.content),
+                NotificationPanelView.DOZE_ANIMATION_DURATION);
+    }
+
+    @Override
+    public void setDark(boolean dark, boolean fade, long delay) {
+        super.setDark(dark, fade, delay);
+        if (mDark == dark) return;
+        mDark = dark;
+        if (fade) {
+            mViewInvertHelper.fade(dark, delay);
+        } else {
+            mViewInvertHelper.update(dark);
+        }
     }
 
     public NotificationOverflowIconsView getIconsView() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java
new file mode 100644
index 0000000..8dc14b0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.view.View;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.widget.ImageView;
+
+import com.android.systemui.R;
+import com.android.systemui.ViewInvertHelper;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
+
+/**
+ * Wraps a notification view inflated from a template.
+ */
+public class NotificationTemplateViewWrapper extends NotificationViewWrapper {
+
+    private final ViewInvertHelper mInvertHelper;
+    private final ImageView mIcon;
+    protected final ImageView mPicture;
+    private final ColorMatrix mGrayscaleColorMatrix = new ColorMatrix();
+    private final PorterDuffColorFilter mIconColorFilter = new PorterDuffColorFilter(
+            0, PorterDuff.Mode.SRC_ATOP);
+    private final int mIconDarkAlpha;
+    private final int mIconBackgroundColor;
+    private final int mIconBackgroundDarkColor;
+    private final Interpolator mLinearOutSlowInInterpolator;
+
+    private boolean mDark;
+
+    protected NotificationTemplateViewWrapper(Context ctx, View view) {
+        super(view);
+        mIconDarkAlpha = ctx.getResources().getInteger(R.integer.doze_small_icon_alpha);
+        mIconBackgroundDarkColor =
+                ctx.getResources().getColor(R.color.doze_small_icon_background_color);
+        mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(ctx,
+                android.R.interpolator.linear_out_slow_in);
+        View mainColumn = view.findViewById(com.android.internal.R.id.notification_main_column);
+        mInvertHelper = mainColumn != null
+                ? new ViewInvertHelper(mainColumn, NotificationPanelView.DOZE_ANIMATION_DURATION)
+                : null;
+        ImageView largeIcon = (ImageView) view.findViewById(com.android.internal.R.id.icon);
+        ImageView rightIcon = (ImageView) view.findViewById(com.android.internal.R.id.right_icon);
+        mIcon = resolveIcon(largeIcon, rightIcon);
+        mPicture = resolvePicture(largeIcon);
+        mIconBackgroundColor = resolveBackgroundColor(mIcon);
+    }
+
+    private ImageView resolveIcon(ImageView largeIcon, ImageView rightIcon) {
+        return largeIcon != null && largeIcon.getBackground() != null ? largeIcon
+                : rightIcon != null && rightIcon.getBackground() != null ? rightIcon
+                : null;
+    }
+
+    private ImageView resolvePicture(ImageView largeIcon) {
+        return largeIcon != null && largeIcon.getBackground() == null
+                ? largeIcon
+                : null;
+    }
+
+    private int resolveBackgroundColor(ImageView icon) {
+        if (icon != null && icon.getBackground() != null) {
+            ColorFilter filter = icon.getBackground().getColorFilter();
+            if (filter instanceof PorterDuffColorFilter) {
+                return ((PorterDuffColorFilter) filter).getColor();
+            }
+        }
+        return 0;
+    }
+
+    @Override
+    public void setDark(boolean dark, boolean fade, long delay) {
+        if (mDark != dark) {
+            mDark = dark;
+            if (mInvertHelper != null) {
+                if (fade) {
+                    mInvertHelper.fade(dark, delay);
+                } else {
+                    mInvertHelper.update(dark);
+                }
+            }
+            if (mIcon != null) {
+                if (fade) {
+                    fadeIconColorFilter(mIcon, dark, delay);
+                    fadeIconAlpha(mIcon, dark, delay);
+                } else {
+                    updateIconColorFilter(mIcon, dark);
+                    updateIconAlpha(mIcon, dark);
+                }
+            }
+            setPictureGrayscale(dark, fade, delay);
+        }
+    }
+
+    protected void setPictureGrayscale(boolean grayscale, boolean fade, long delay) {
+        if (mPicture != null) {
+            if (fade) {
+                fadeGrayscale(mPicture, grayscale, delay);
+            } else {
+                updateGrayscale(mPicture, grayscale);
+            }
+        }
+    }
+
+    private void startIntensityAnimation(ValueAnimator.AnimatorUpdateListener updateListener,
+            boolean dark, long delay, Animator.AnimatorListener listener) {
+        float startIntensity = dark ? 0f : 1f;
+        float endIntensity = dark ? 1f : 0f;
+        ValueAnimator animator = ValueAnimator.ofFloat(startIntensity, endIntensity);
+        animator.addUpdateListener(updateListener);
+        animator.setDuration(NotificationPanelView.DOZE_ANIMATION_DURATION);
+        animator.setInterpolator(mLinearOutSlowInInterpolator);
+        animator.setStartDelay(delay);
+        if (listener != null) {
+            animator.addListener(listener);
+        }
+        animator.start();
+    }
+
+    private void fadeIconColorFilter(final ImageView target, boolean dark, long delay) {
+        startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                updateIconColorFilter(target, (Float) animation.getAnimatedValue());
+            }
+        }, dark, delay, null /* listener */);
+    }
+
+    private void fadeIconAlpha(final ImageView target, boolean dark, long delay) {
+        startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                float t = (float) animation.getAnimatedValue();
+                target.setImageAlpha((int) (255 * (1f - t) + mIconDarkAlpha * t));
+            }
+        }, dark, delay, null /* listener */);
+    }
+
+    protected void fadeGrayscale(final ImageView target, final boolean dark, long delay) {
+        startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                updateGrayscaleMatrix((float) animation.getAnimatedValue());
+                target.setColorFilter(new ColorMatrixColorFilter(mGrayscaleColorMatrix));
+            }
+        }, dark, delay, new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                if (!dark) {
+                    target.setColorFilter(null);
+                }
+            }
+        });
+    }
+
+    private void updateIconColorFilter(ImageView target, boolean dark) {
+        updateIconColorFilter(target, dark ? 1f : 0f);
+    }
+
+    private void updateIconColorFilter(ImageView target, float intensity) {
+        int color = interpolateColor(mIconBackgroundColor, mIconBackgroundDarkColor, intensity);
+        mIconColorFilter.setColor(color);
+        target.getBackground().mutate().setColorFilter(mIconColorFilter);
+    }
+
+    private void updateIconAlpha(ImageView target, boolean dark) {
+        target.setImageAlpha(dark ? mIconDarkAlpha : 255);
+    }
+
+    protected void updateGrayscale(ImageView target, boolean dark) {
+        if (dark) {
+            updateGrayscaleMatrix(1f);
+            target.setColorFilter(new ColorMatrixColorFilter(mGrayscaleColorMatrix));
+        } else {
+            target.setColorFilter(null);
+        }
+    }
+
+    private void updateGrayscaleMatrix(float intensity) {
+        mGrayscaleColorMatrix.setSaturation(1 - intensity);
+    }
+
+    private static int interpolateColor(int source, int target, float t) {
+        int aSource = Color.alpha(source);
+        int rSource = Color.red(source);
+        int gSource = Color.green(source);
+        int bSource = Color.blue(source);
+        int aTarget = Color.alpha(target);
+        int rTarget = Color.red(target);
+        int gTarget = Color.green(target);
+        int bTarget = Color.blue(target);
+        return Color.argb(
+                (int) (aSource * (1f - t) + aTarget * t),
+                (int) (rSource * (1f - t) + rTarget * t),
+                (int) (gSource * (1f - t) + gTarget * t),
+                (int) (bSource * (1f - t) + bTarget * t));
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java
new file mode 100644
index 0000000..0a02573
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.content.Context;
+import android.view.View;
+
+import com.android.internal.R;
+
+/**
+ * Wraps the actual notification content view; used to implement behaviors which are different for
+ * the individual templates and custom views.
+ */
+public abstract class NotificationViewWrapper {
+
+    protected final View mView;
+
+    public static NotificationViewWrapper wrap(Context ctx, View v) {
+
+        // TODO: Figure out a better way to find out which template the view is.
+        if (v.findViewById(com.android.internal.R.id.media_actions) != null) {
+            return new NotificationMediaViewWrapper(ctx, v);
+        } else if (v.getId() == com.android.internal.R.id.status_bar_latest_event_content) {
+            return new NotificationTemplateViewWrapper(ctx, v);
+        } else {
+            return new NotificationCustomViewWrapper(v);
+        }
+    }
+
+    protected NotificationViewWrapper(View view) {
+        mView = view;
+    }
+
+    /**
+     * In dark mode, we draw as little as possible, assuming a black background.
+     *
+     * @param dark whether we should display ourselves in dark mode
+     * @param fade whether to animate the transition if the mode changes
+     * @param delay if fading, the delay of the animation
+     */
+    public abstract void setDark(boolean dark, boolean fade, long delay);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 9154a48..418c57f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -48,6 +48,7 @@
     private int mMobileStrengthId = 0, mMobileTypeId = 0;
     private boolean mIsAirplaneMode = false;
     private int mAirplaneIconId = 0;
+    private int mAirplaneContentDescription;
     private String mWifiDescription, mMobileDescription, mMobileTypeDescription;
     private boolean mIsMobileTypeIconWide;
 
@@ -160,9 +161,10 @@
     }
 
     @Override
-    public void setIsAirplaneMode(boolean is, int airplaneIconId) {
+    public void setIsAirplaneMode(boolean is, int airplaneIconId, int contentDescription) {
         mIsAirplaneMode = is;
         mAirplaneIconId = airplaneIconId;
+        mAirplaneContentDescription = contentDescription;
 
         apply();
     }
@@ -236,6 +238,8 @@
 
         if (mIsAirplaneMode) {
             mAirplane.setImageResource(mAirplaneIconId);
+            mAirplane.setContentDescription(mAirplaneContentDescription != 0 ?
+                    mContext.getString(mAirplaneContentDescription) : "");
             mAirplane.setVisibility(View.VISIBLE);
         } else {
             mAirplane.setVisibility(View.GONE);
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 3b2d3cb..3fca56d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -79,6 +79,7 @@
 import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationListenerService.RankingMap;
 import android.service.notification.StatusBarNotification;
+import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
@@ -821,7 +822,12 @@
         signalClusterQs.setNetworkController(mNetworkController);
         final boolean isAPhone = mNetworkController.hasVoiceCallingFeature();
         if (isAPhone) {
-            mNetworkController.addEmergencyLabelView(mHeader);
+            mNetworkController.addEmergencyListener(new NetworkControllerImpl.EmergencyListener() {
+                @Override
+                public void setEmergencyCallsOnly(boolean emergencyOnly) {
+                    mHeader.setShowEmergencyCallsOnly(emergencyOnly);
+                }
+            });
         }
 
         mCarrierLabel = (TextView)mStatusBarWindow.findViewById(R.id.carrier_label);
@@ -830,13 +836,19 @@
         if (mShowCarrierInPanel) {
             mCarrierLabel.setVisibility(mCarrierLabelVisible ? View.VISIBLE : View.INVISIBLE);
 
-            // for mobile devices, we always show mobile connection info here (SPN/PLMN)
-            // for other devices, we show whatever network is connected
-            if (mNetworkController.hasMobileDataFeature()) {
-                mNetworkController.addMobileLabelView(mCarrierLabel);
-            } else {
-                mNetworkController.addCombinedLabelView(mCarrierLabel);
-            }
+            mNetworkController.addCarrierLabel(new NetworkControllerImpl.CarrierLabelListener() {
+                @Override
+                public void setCarrierLabel(String label) {
+                    mCarrierLabel.setText(label);
+                    if (mNetworkController.hasMobileDataFeature()) {
+                        if (TextUtils.isEmpty(label)) {
+                            mCarrierLabel.setVisibility(View.GONE);
+                        } else {
+                            mCarrierLabel.setVisibility(View.VISIBLE);
+                        }
+                    }
+                }
+            });
 
             // set up the dynamic hide/show of the label
             // TODO: uncomment, handle this for the Stack scroller aswell
@@ -3696,14 +3708,11 @@
         if (mState != StatusBarState.KEYGUARD && !mNotificationPanel.isDozing()) {
             return;
         }
-        mNotificationPanel.setDozing(mDozing, mDozeScrimController.isPulsing() /*animate*/);
-        if (mDozing) {
-            mStackScroller.setDark(true, false /*animate*/);
-        } else {
-            mStackScroller.setDark(false, false /*animate*/);
-        }
+        boolean animate = !mDozing && mDozeScrimController.isPulsing();
+        mNotificationPanel.setDozing(mDozing, animate);
+        mStackScroller.setDark(mDozing, animate);
         mScrimController.setDozing(mDozing);
-        mDozeScrimController.setDozing(mDozing, mDozeScrimController.isPulsing() /* animate */);
+        mDozeScrimController.setDozing(mDozing, animate);
     }
 
     public void updateStackScrollerState(boolean goingToFullShade) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 45a1386..8ce608c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -122,7 +122,7 @@
                     tile.userSwitch(newUserId);
                 }
                 mSecurity.onUserSwitched(newUserId);
-                mNetwork.onUserSwitched(newUserId);
+                mNetwork.getAccessPointController().onUserSwitched(newUserId);
                 mObserver.register();
             }
         };
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
similarity index 95%
rename from packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointController.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
index 0a385d7..6fec97e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
@@ -36,15 +36,13 @@
 import android.util.Log;
 
 import com.android.systemui.R;
-import com.android.systemui.statusbar.policy.NetworkController.AccessPoint;
-import com.android.systemui.statusbar.policy.NetworkController.AccessPointCallback;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 
-public class AccessPointController {
+public class AccessPointControllerImpl implements NetworkController.AccessPointController {
     private static final String TAG = "AccessPointController";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
@@ -69,7 +67,7 @@
     private boolean mScanning;
     private int mCurrentUser;
 
-    public AccessPointController(Context context) {
+    public AccessPointControllerImpl(Context context) {
         mContext = context;
         mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
@@ -81,25 +79,28 @@
                 new UserHandle(mCurrentUser));
     }
 
-    void onUserSwitched(int newUserId) {
+    public void onUserSwitched(int newUserId) {
         mCurrentUser = newUserId;
     }
 
-    public void addCallback(AccessPointCallback callback) {
+    @Override
+    public void addAccessPointCallback(AccessPointCallback callback) {
         if (callback == null || mCallbacks.contains(callback)) return;
         if (DEBUG) Log.d(TAG, "addCallback " + callback);
         mCallbacks.add(callback);
         mReceiver.setListening(!mCallbacks.isEmpty());
     }
 
-    public void removeCallback(AccessPointCallback callback) {
+    @Override
+    public void removeAccessPointCallback(AccessPointCallback callback) {
         if (callback == null) return;
         if (DEBUG) Log.d(TAG, "removeCallback " + callback);
         mCallbacks.remove(callback);
         mReceiver.setListening(!mCallbacks.isEmpty());
     }
 
-    public void scan() {
+    @Override
+    public void scanForAccessPoints() {
         if (mScanning) return;
         if (DEBUG) Log.d(TAG, "scan!");
         mScanning = mWifiManager.startScan();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityContentDescriptions.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityContentDescriptions.java
index 7ac2a98..b7c74e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityContentDescriptions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityContentDescriptions.java
@@ -33,11 +33,5 @@
         R.string.accessibility_wifi_three_bars,
         R.string.accessibility_wifi_signal_full
     };
-    static final int[] WIMAX_CONNECTION_STRENGTH = {
-        R.string.accessibility_no_wimax,
-        R.string.accessibility_wimax_one_bar,
-        R.string.accessibility_wimax_two_bars,
-        R.string.accessibility_wimax_three_bars,
-        R.string.accessibility_wimax_signal_full
-    };
+    static final int WIFI_NO_CONNECTION = R.string.accessibility_no_wifi;
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java
similarity index 94%
rename from packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataController.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java
index 33d68bf..20f0a83 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java
@@ -38,12 +38,10 @@
 import android.text.format.Time;
 import android.util.Log;
 
-import com.android.systemui.statusbar.policy.NetworkController.DataUsageInfo;
-
 import java.util.Date;
 import java.util.Locale;
 
-public class MobileDataController {
+public class MobileDataControllerImpl implements NetworkController.MobileDataController {
     private static final String TAG = "MobileDataController";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
@@ -61,8 +59,9 @@
 
     private INetworkStatsSession mSession;
     private Callback mCallback;
+    private NetworkControllerImpl mNetworkController;
 
-    public MobileDataController(Context context) {
+    public MobileDataControllerImpl(Context context) {
         mContext = context;
         mTelephonyManager = TelephonyManager.from(context);
         mConnectivityManager = ConnectivityManager.from(context);
@@ -71,6 +70,10 @@
         mPolicyManager = NetworkPolicyManager.from(mContext);
     }
 
+    public void setNetworkController(NetworkControllerImpl networkController) {
+        mNetworkController = networkController;
+    }
+
     private INetworkStatsSession getSession() {
         if (mSession == null) {
             try {
@@ -155,6 +158,9 @@
             } else {
                 usage.warningLevel = DEFAULT_WARNING_LEVEL;
             }
+            if (usage != null) {
+                usage.carrier = mNetworkController.getMobileNetworkName();
+            }
             return usage;
         } catch (RemoteException e) {
             return warn("remote call failed");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index bb29d01..b024f58 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -22,6 +22,8 @@
     void addNetworkSignalChangedCallback(NetworkSignalChangedCallback cb);
     void removeNetworkSignalChangedCallback(NetworkSignalChangedCallback cb);
     void setWifiEnabled(boolean enabled);
+    AccessPointController getAccessPointController();
+    MobileDataController getMobileDataController();
 
     public interface NetworkSignalChangedCallback {
         void onWifiSignalChanged(boolean enabled, boolean connected, int wifiSignalIconId,
@@ -36,38 +38,50 @@
         void onMobileDataEnabled(boolean enabled);
     }
 
-    void addAccessPointCallback(AccessPointCallback callback);
-    void removeAccessPointCallback(AccessPointCallback callback);
-    void scanForAccessPoints();
-    boolean connect(AccessPoint ap);
-    boolean isMobileDataSupported();
-    boolean isMobileDataEnabled();
-    void setMobileDataEnabled(boolean enabled);
-    DataUsageInfo getDataUsageInfo();
-    boolean canConfigWifi();
-    void onUserSwitched(int newUserId);
+    /**
+     * Tracks changes in access points.  Allows listening for changes, scanning for new APs,
+     * and connecting to new ones.
+     */
+    public interface AccessPointController {
+        void addAccessPointCallback(AccessPointCallback callback);
+        void removeAccessPointCallback(AccessPointCallback callback);
+        void scanForAccessPoints();
+        boolean connect(AccessPoint ap);
+        boolean canConfigWifi();
+        void onUserSwitched(int newUserId);
 
-    public interface AccessPointCallback {
-        void onAccessPointsChanged(AccessPoint[] accessPoints);
+        public interface AccessPointCallback {
+            void onAccessPointsChanged(AccessPoint[] accessPoints);
+        }
+
+        public static class AccessPoint {
+            public static final int NO_NETWORK = -1;  // see WifiManager
+
+            public int networkId;
+            public int iconId;
+            public String ssid;
+            public boolean isConnected;
+            public boolean isConfigured;
+            public boolean hasSecurity;
+            public int level;  // 0 - 5
+        }
     }
 
-    public static class AccessPoint {
-        public static final int NO_NETWORK = -1;  // see WifiManager
+    /**
+     * Tracks mobile data support and usage.
+     */
+    public interface MobileDataController {
+        boolean isMobileDataSupported();
+        boolean isMobileDataEnabled();
+        void setMobileDataEnabled(boolean enabled);
+        DataUsageInfo getDataUsageInfo();
 
-        public int networkId;
-        public int iconId;
-        public String ssid;
-        public boolean isConnected;
-        public boolean isConfigured;
-        public boolean hasSecurity;
-        public int level;  // 0 - 5
-    }
-
-    public static class DataUsageInfo {
-        public String carrier;
-        public String period;
-        public long limitLevel;
-        public long warningLevel;
-        public long usageLevel;
+        public static class DataUsageInfo {
+            public String carrier;
+            public String period;
+            public long limitLevel;
+            public long warningLevel;
+            public long usageLevel;
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 07762a4..5a97c75 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -26,7 +26,6 @@
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
-import android.net.wimax.WimaxManagerConstants;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
@@ -37,9 +36,8 @@
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.TelephonyManager;
+import android.text.format.DateFormat;
 import android.util.Log;
-import android.view.View;
-import android.widget.TextView;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.IccCardConstants;
@@ -48,130 +46,66 @@
 import com.android.internal.util.AsyncChannel;
 import com.android.systemui.DemoMode;
 import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.StatusBarHeaderView;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
+import java.util.Objects;
 
 /** Platform implementation of the network controller. **/
 public class NetworkControllerImpl extends BroadcastReceiver
         implements NetworkController, DemoMode {
     // debug
-    static final String TAG = "StatusBar.NetworkController";
-    static final boolean DEBUG = false;
-    static final boolean CHATTY = false; // additional diagnostics, but not logspew
+    static final String TAG = "NetworkController";
+    static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    // additional diagnostics, but not logspew
+    static final boolean CHATTY =  Log.isLoggable(TAG + ".Chat", Log.DEBUG);
+    // Save the previous states of all SignalController state info.
+    static final boolean RECORD_HISTORY = true;
+    // How many to save, must be a power of 2.
+    static final int HISTORY_SIZE = 16;
 
-    // telephony
-    boolean mHspaDataDistinguishable;
-    final TelephonyManager mPhone;
-    boolean mDataConnected;
-    IccCardConstants.State mSimState = IccCardConstants.State.READY;
-    int mPhoneState = TelephonyManager.CALL_STATE_IDLE;
-    int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
-    int mDataState = TelephonyManager.DATA_DISCONNECTED;
-    int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
-    ServiceState mServiceState;
-    SignalStrength mSignalStrength;
-    int[] mDataIconList = TelephonyIcons.DATA_G[0];
-    String mNetworkName;
-    String mNetworkNameDefault;
-    String mNetworkNameSeparator;
-    int mPhoneSignalIconId;
-    int mQSPhoneSignalIconId;
-    int mDataDirectionIconId; // data + data direction on phones
-    int mDataSignalIconId;
-    int mDataTypeIconId;
-    int mQSDataTypeIconId;
-    int mAirplaneIconId;
-    boolean mDataActive;
-    boolean mNoSim;
-    int mLastSignalLevel;
-    boolean mShowPhoneRSSIForData = false;
-    boolean mShowAtLeastThreeGees = false;
-    boolean mAlwaysShowCdmaRssi = false;
+    private static final int INET_CONDITION_THRESHOLD = 50;
 
-    String mContentDescriptionPhoneSignal;
-    String mContentDescriptionWifi;
-    String mContentDescriptionWimax;
-    String mContentDescriptionCombinedSignal;
-    String mContentDescriptionDataType;
+    private final Context mContext;
+    private final TelephonyManager mPhone;
+    private final WifiManager mWifiManager;
+    private final ConnectivityManager mConnectivityManager;
+    private final boolean mHasMobileDataFeature;
 
-    // wifi
-    final WifiManager mWifiManager;
-    AsyncChannel mWifiChannel;
-    boolean mWifiEnabled, mWifiConnected;
-    int mWifiRssi, mWifiLevel;
-    String mWifiSsid;
-    int mWifiIconId = 0;
-    int mQSWifiIconId = 0;
-    int mWifiActivity = WifiManager.DATA_ACTIVITY_NONE;
+    // Subcontrollers.
+    @VisibleForTesting
+    final WifiSignalController mWifiSignalController;
+    @VisibleForTesting
+    final MobileSignalController mMobileSignalController;
+    private final AccessPointController mAccessPoints;
+    private final MobileDataControllerImpl mMobileDataController;
 
     // bluetooth
     private boolean mBluetoothTethered = false;
-    private int mBluetoothTetherIconId =
-        com.android.internal.R.drawable.stat_sys_tether_bluetooth;
-
-    //wimax
-    private boolean mWimaxSupported = false;
-    private boolean mIsWimaxEnabled = false;
-    private boolean mWimaxConnected = false;
-    private boolean mWimaxIdle = false;
-    private int mWimaxIconId = 0;
-    private int mWimaxSignal = 0;
-    private int mWimaxState = 0;
-    private int mWimaxExtraState = 0;
 
     // data connectivity (regardless of state, can we access the internet?)
     // state of inet connection - 0 not connected, 100 connected
     private boolean mConnected = false;
     private int mConnectedNetworkType = ConnectivityManager.TYPE_NONE;
     private String mConnectedNetworkTypeName;
-    private int mLastConnectedNetworkType = ConnectivityManager.TYPE_NONE;
+    private boolean mInetCondition; // Used for Logging and demo.
 
-    private int mInetCondition = 0;
-    private int mLastInetCondition = 0;
-    private static final int INET_CONDITION_THRESHOLD = 50;
-
+    // States that don't belong to a subcontroller.
     private boolean mAirplaneMode = false;
-    private boolean mLastAirplaneMode = true;
-
     private Locale mLocale = null;
-    private Locale mLastLocale = null;
 
-    // our ui
-    Context mContext;
-    ArrayList<TextView> mCombinedLabelViews = new ArrayList<TextView>();
-    ArrayList<TextView> mMobileLabelViews = new ArrayList<TextView>();
-    ArrayList<TextView> mWifiLabelViews = new ArrayList<TextView>();
-    ArrayList<StatusBarHeaderView> mEmergencyViews = new ArrayList<>();
-    ArrayList<SignalCluster> mSignalClusters = new ArrayList<SignalCluster>();
-    ArrayList<NetworkSignalChangedCallback> mSignalsChangedCallbacks =
+    // All the callbacks.
+    private ArrayList<EmergencyListener> mEmergencyListeners = new ArrayList<EmergencyListener>();
+    private ArrayList<CarrierLabelListener> mCarrierListeners =
+            new ArrayList<CarrierLabelListener>();
+    private ArrayList<SignalCluster> mSignalClusters = new ArrayList<SignalCluster>();
+    private ArrayList<NetworkSignalChangedCallback> mSignalsChangedCallbacks =
             new ArrayList<NetworkSignalChangedCallback>();
-    int mLastPhoneSignalIconId = -1;
-    int mLastDataDirectionIconId = -1;
-    int mLastWifiIconId = -1;
-    int mLastWimaxIconId = -1;
-    int mLastCombinedSignalIconId = -1;
-    int mLastDataTypeIconId = -1;
-    String mLastCombinedLabel = "";
-
-    private boolean mHasMobileDataFeature;
-
-    boolean mDataAndWifiStacked = false;
-
-    public interface SignalCluster {
-        void setWifiIndicators(boolean visible, int strengthIcon, String contentDescription);
-        void setMobileDataIndicators(boolean visible, int strengthIcon, int typeIcon,
-                String contentDescription, String typeContentDescription, boolean isTypeIconWide);
-        void setIsAirplaneMode(boolean is, int airplaneIcon);
-    }
-
-    private final AccessPointController mAccessPoints;
-    private final MobileDataController mMobileDataController;
-    private final ConnectivityManager mConnectivityManager;
 
     /**
      * Construct this controller object and register for updates.
@@ -180,70 +114,50 @@
         this(context, (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE),
                 (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE),
                 (WifiManager) context.getSystemService(Context.WIFI_SERVICE),
-                new AccessPointController(context), new MobileDataController(context));
+                Config.readConfig(context), new AccessPointControllerImpl(context),
+                new MobileDataControllerImpl(context));
         registerListeners();
     }
 
     @VisibleForTesting
     NetworkControllerImpl(Context context, ConnectivityManager connectivityManager,
-            TelephonyManager telephonyManager, WifiManager wifiManager,
-            AccessPointController accessPointController,
-            MobileDataController mobileDataController) {
+            TelephonyManager telephonyManager, WifiManager wifiManager, Config config,
+            AccessPointControllerImpl accessPointController,
+            MobileDataControllerImpl mobileDataController) {
         mContext = context;
-        final Resources res = context.getResources();
 
         mConnectivityManager = connectivityManager;
         mHasMobileDataFeature =
                 mConnectivityManager.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
 
-        mShowPhoneRSSIForData = res.getBoolean(R.bool.config_showPhoneRSSIForData);
-        mShowAtLeastThreeGees = res.getBoolean(R.bool.config_showMin3G);
-        mAlwaysShowCdmaRssi = res.getBoolean(
-                com.android.internal.R.bool.config_alwaysUseCdmaRssi);
-
-        // set up the default wifi icon, used when no radios have ever appeared
-        updateWifiIcons();
-        updateWimaxIcons();
-
         // telephony
         mPhone = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
-        mHspaDataDistinguishable = mContext.getResources().getBoolean(
-                R.bool.config_hspa_data_distinguishable);
-        mNetworkNameSeparator = mContext.getString(R.string.status_bar_network_name_separator);
-        mNetworkNameDefault = mContext.getString(
-                com.android.internal.R.string.lockscreen_carrier_default);
-        mNetworkName = mNetworkNameDefault;
 
         // wifi
         mWifiManager = wifiManager;
-        Handler handler = new WifiHandler();
-        mWifiChannel = new AsyncChannel();
-        Messenger wifiMessenger = mWifiManager.getWifiServiceMessenger();
-        if (wifiMessenger != null) {
-            mWifiChannel.connect(mContext, handler, wifiMessenger);
-        }
 
-        // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it
-        updateAirplaneMode();
-
-        mLastLocale = mContext.getResources().getConfiguration().locale;
+        mLocale = mContext.getResources().getConfiguration().locale;
         mAccessPoints = accessPointController;
         mMobileDataController = mobileDataController;
-        mMobileDataController.setCallback(new MobileDataController.Callback() {
+        mMobileDataController.setNetworkController(this);
+        // TODO: Find a way to move this into MobileDataController.
+        mMobileDataController.setCallback(new MobileDataControllerImpl.Callback() {
             @Override
             public void onMobileDataEnabled(boolean enabled) {
                 notifyMobileDataEnabled(enabled);
             }
         });
+        mWifiSignalController = new WifiSignalController(mContext, mHasMobileDataFeature,
+                mSignalsChangedCallbacks, mSignalClusters, this);
+        mMobileSignalController = new MobileSignalController(mContext, config,
+                mHasMobileDataFeature, mPhone, mSignalsChangedCallbacks, mSignalClusters, this);
+
+        // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it
+        updateAirplaneMode(true);
     }
 
     private void registerListeners() {
-        mPhone.listen(mPhoneStateListener,
-                          PhoneStateListener.LISTEN_SERVICE_STATE
-                        | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
-                        | PhoneStateListener.LISTEN_CALL_STATE
-                        | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
-                        | PhoneStateListener.LISTEN_DATA_ACTIVITY);
+        mMobileSignalController.registerListener();
 
         // broadcasts
         IntentFilter filter = new IntentFilter();
@@ -256,29 +170,38 @@
         filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
         filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
         filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
-        mWimaxSupported = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_wimaxEnabled);
-        if(mWimaxSupported) {
-            filter.addAction(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION);
-            filter.addAction(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION);
-            filter.addAction(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION);
-        }
         mContext.registerReceiver(this, filter);
     }
 
-    @Override
-    public boolean canConfigWifi() {
-        return mAccessPoints.canConfigWifi();
+    private void unregisterListeners() {
+        mMobileSignalController.unregisterListener();
+        mContext.unregisterReceiver(this);
     }
 
     @Override
-    public void onUserSwitched(int newUserId) {
-        mAccessPoints.onUserSwitched(newUserId);
+    public AccessPointController getAccessPointController() {
+        return mAccessPoints;
+    }
+
+    @Override
+    public MobileDataController getMobileDataController() {
+        return mMobileDataController;
+    }
+
+    public void addEmergencyListener(EmergencyListener listener) {
+        mEmergencyListeners.add(listener);
+        refreshCarrierLabel();
+    }
+
+    public void addCarrierLabel(CarrierLabelListener listener) {
+        mCarrierListeners.add(listener);
+        refreshCarrierLabel();
     }
 
     private void notifyMobileDataEnabled(boolean enabled) {
-        for (NetworkSignalChangedCallback cb : mSignalsChangedCallbacks) {
-            cb.onMobileDataEnabled(enabled);
+        int length = mSignalsChangedCallbacks.size();
+        for (int i = 0; i < length; i++) {
+            mSignalsChangedCallbacks.get(i).onMobileDataEnabled(enabled);
         }
     }
 
@@ -290,34 +213,40 @@
         return mPhone.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE;
     }
 
+    public String getMobileNetworkName() {
+        return mMobileSignalController.mCurrentState.networkName;
+    }
+
     public boolean isEmergencyOnly() {
-        return (mServiceState != null && mServiceState.isEmergencyOnly());
+        return mMobileSignalController.isEmergencyOnly();
     }
 
-    public void addCombinedLabelView(TextView v) {
-        mCombinedLabelViews.add(v);
-    }
+    /**
+     * Emergency status may have changed (triggered by MobileSignalController),
+     * so we should recheck and send out the state to listeners.
+     */
+    void recalculateEmergency() {
+        final boolean emergencyOnly = isEmergencyOnly();
 
-    public void addMobileLabelView(TextView v) {
-        mMobileLabelViews.add(v);
-    }
-
-    public void addWifiLabelView(TextView v) {
-        mWifiLabelViews.add(v);
-    }
-
-    public void addEmergencyLabelView(StatusBarHeaderView v) {
-        mEmergencyViews.add(v);
+        int length = mEmergencyListeners.size();
+        for (int i = 0; i < length; i++) {
+            mEmergencyListeners.get(i).setEmergencyCallsOnly(emergencyOnly);
+        }
     }
 
     public void addSignalCluster(SignalCluster cluster) {
         mSignalClusters.add(cluster);
-        refreshSignalCluster(cluster);
+        cluster.setIsAirplaneMode(mAirplaneMode, TelephonyIcons.FLIGHT_MODE_ICON,
+                R.string.accessibility_airplane_mode);
+        mWifiSignalController.notifyListeners();
+        mMobileSignalController.notifyListeners();
     }
 
     public void addNetworkSignalChangedCallback(NetworkSignalChangedCallback cb) {
         mSignalsChangedCallbacks.add(cb);
-        notifySignalsChangedCallbacks(cb);
+        cb.onAirplaneModeChanged(mAirplaneMode);
+        mWifiSignalController.notifyListeners();
+        mMobileSignalController.notifyListeners();
     }
 
     public void removeNetworkSignalChangedCallback(NetworkSignalChangedCallback cb) {
@@ -325,26 +254,6 @@
     }
 
     @Override
-    public void addAccessPointCallback(AccessPointCallback callback) {
-        mAccessPoints.addCallback(callback);
-    }
-
-    @Override
-    public void removeAccessPointCallback(AccessPointCallback callback) {
-        mAccessPoints.removeCallback(callback);
-    }
-
-    @Override
-    public void scanForAccessPoints() {
-        mAccessPoints.scan();
-    }
-
-    @Override
-    public boolean connect(AccessPoint ap) {
-        return mAccessPoints.connect(ap);
-    }
-
-    @Override
     public void setWifiEnabled(final boolean enabled) {
         new AsyncTask<Void, Void, Void>() {
             @Override
@@ -352,7 +261,7 @@
                 // Disable tethering if enabling Wifi
                 final int wifiApState = mWifiManager.getWifiApState();
                 if (enabled && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
-                               (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {
+                        (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {
                     mWifiManager.setWifiApEnabled(null, false);
                 }
 
@@ -363,732 +272,79 @@
     }
 
     @Override
-    public DataUsageInfo getDataUsageInfo() {
-        final DataUsageInfo info =  mMobileDataController.getDataUsageInfo();
-        if (info != null) {
-            info.carrier = mNetworkName;
-        }
-        return info;
-    }
-
-    @Override
-    public boolean isMobileDataSupported() {
-        return mMobileDataController.isMobileDataSupported();
-    }
-
-    @Override
-    public boolean isMobileDataEnabled() {
-        return mMobileDataController.isMobileDataEnabled();
-    }
-
-    @Override
-    public void setMobileDataEnabled(boolean enabled) {
-        mMobileDataController.setMobileDataEnabled(enabled);
-    }
-
-    private boolean isTypeIconWide(int iconId) {
-        return TelephonyIcons.ICON_LTE == iconId || TelephonyIcons.ICON_1X == iconId
-                || TelephonyIcons.ICON_3G == iconId || TelephonyIcons.ICON_4G == iconId;
-    }
-
-    private boolean isQsTypeIconWide(int iconId) {
-        return TelephonyIcons.QS_ICON_LTE == iconId || TelephonyIcons.QS_ICON_1X == iconId
-                || TelephonyIcons.QS_ICON_3G == iconId || TelephonyIcons.QS_ICON_4G == iconId;
-    }
-
-    public void refreshSignalCluster(SignalCluster cluster) {
-        if (mDemoMode) return;
-        cluster.setWifiIndicators(
-                // only show wifi in the cluster if connected or if wifi-only
-                mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature),
-                mWifiIconId,
-                mContentDescriptionWifi);
-
-        if (mIsWimaxEnabled && mWimaxConnected) {
-            // wimax is special
-            cluster.setMobileDataIndicators(
-                    true,
-                    mAlwaysShowCdmaRssi ? mPhoneSignalIconId : mWimaxIconId,
-                    mDataTypeIconId,
-                    mContentDescriptionWimax,
-                    mContentDescriptionDataType,
-                    false /* isTypeIconWide */ );
-        } else {
-            // normal mobile data
-            cluster.setMobileDataIndicators(
-                    mHasMobileDataFeature,
-                    mShowPhoneRSSIForData ? mPhoneSignalIconId : mDataSignalIconId,
-                    mDataTypeIconId,
-                    mContentDescriptionPhoneSignal,
-                    mContentDescriptionDataType,
-                    isTypeIconWide(mDataTypeIconId));
-        }
-        cluster.setIsAirplaneMode(mAirplaneMode, mAirplaneIconId);
-    }
-
-    void notifySignalsChangedCallbacks(NetworkSignalChangedCallback cb) {
-        // only show wifi in the cluster if connected or if wifi-only
-        boolean wifiEnabled = mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature);
-        String wifiDesc = wifiEnabled ?
-                mWifiSsid : null;
-        boolean wifiIn = wifiEnabled && mWifiSsid != null
-                && (mWifiActivity == WifiManager.DATA_ACTIVITY_INOUT
-                || mWifiActivity == WifiManager.DATA_ACTIVITY_IN);
-        boolean wifiOut = wifiEnabled && mWifiSsid != null
-                && (mWifiActivity == WifiManager.DATA_ACTIVITY_INOUT
-                || mWifiActivity == WifiManager.DATA_ACTIVITY_OUT);
-        cb.onWifiSignalChanged(mWifiEnabled, mWifiConnected, mQSWifiIconId, wifiIn, wifiOut,
-                mContentDescriptionWifi, wifiDesc);
-
-        boolean mobileIn = mDataConnected && (mDataActivity == TelephonyManager.DATA_ACTIVITY_INOUT
-                || mDataActivity == TelephonyManager.DATA_ACTIVITY_IN);
-        boolean mobileOut = mDataConnected && (mDataActivity == TelephonyManager.DATA_ACTIVITY_INOUT
-                || mDataActivity == TelephonyManager.DATA_ACTIVITY_OUT);
-        if (isEmergencyOnly()) {
-            cb.onMobileDataSignalChanged(false, mQSPhoneSignalIconId,
-                    mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
-                    mContentDescriptionDataType, null, mNoSim, isQsTypeIconWide(mQSDataTypeIconId));
-        } else {
-            if (mIsWimaxEnabled && mWimaxConnected) {
-                // Wimax is special
-                cb.onMobileDataSignalChanged(true, mQSPhoneSignalIconId,
-                        mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
-                        mContentDescriptionDataType, mNetworkName, mNoSim,
-                        isQsTypeIconWide(mQSDataTypeIconId));
-            } else {
-                // Normal mobile data
-                cb.onMobileDataSignalChanged(mHasMobileDataFeature, mQSPhoneSignalIconId,
-                        mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
-                        mContentDescriptionDataType, mNetworkName, mNoSim,
-                        isQsTypeIconWide(mQSDataTypeIconId));
-            }
-        }
-        cb.onAirplaneModeChanged(mAirplaneMode);
-    }
-
-    public void setStackedMode(boolean stacked) {
-        mDataAndWifiStacked = true;
-    }
-
-    @Override
     public void onReceive(Context context, Intent intent) {
+        if (CHATTY) {
+            Log.d(TAG, "onReceive: intent=" + intent);
+        }
         final String action = intent.getAction();
-        if (action.equals(WifiManager.RSSI_CHANGED_ACTION)
-                || action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)
-                || action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
-            updateWifiState(intent);
-            refreshViews();
-        } else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
-            updateSimState(intent);
-            updateDataIcon();
-            refreshViews();
-        } else if (action.equals(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION)) {
-            updateNetworkName(intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false),
-                        intent.getStringExtra(TelephonyIntents.EXTRA_SPN),
-                        intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false),
-                        intent.getStringExtra(TelephonyIntents.EXTRA_PLMN));
-            refreshViews();
-        } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE) ||
-                 action.equals(ConnectivityManager.INET_CONDITION_ACTION)) {
+        if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE) ||
+                action.equals(ConnectivityManager.INET_CONDITION_ACTION)) {
             updateConnectivity(intent);
-            refreshViews();
+            refreshCarrierLabel();
         } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
             refreshLocale();
-            refreshViews();
+            refreshCarrierLabel();
         } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
             refreshLocale();
-            updateAirplaneMode();
-            refreshViews();
-        } else if (action.equals(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION) ||
-                action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION) ||
-                action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) {
-            updateWimaxState(intent);
-            refreshViews();
+            updateAirplaneMode(false);
+            refreshCarrierLabel();
         }
+        mWifiSignalController.handleBroadcast(intent);
+        mMobileSignalController.handleBroadcast(intent);
     }
 
-
-    // ===== Telephony ==============================================================
-
-    PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
-        @Override
-        public void onSignalStrengthsChanged(SignalStrength signalStrength) {
-            if (DEBUG) {
-                Log.d(TAG, "onSignalStrengthsChanged signalStrength=" + signalStrength +
-                    ((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel())));
-            }
-            mSignalStrength = signalStrength;
-            updateTelephonySignalStrength();
-            refreshViews();
+    private void updateAirplaneMode(boolean force) {
+        boolean airplaneMode = (Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_ON, 0) == 1);
+        if (airplaneMode != mAirplaneMode || force) {
+            mAirplaneMode = airplaneMode;
+            mMobileSignalController.setAirplaneMode(mAirplaneMode);
+            notifyAirplaneCallbacks();
+            refreshCarrierLabel();
         }
-
-        @Override
-        public void onServiceStateChanged(ServiceState state) {
-            if (DEBUG) {
-                Log.d(TAG, "onServiceStateChanged voiceState=" + state.getVoiceRegState()
-                        + " dataState=" + state.getDataRegState());
-            }
-            mServiceState = state;
-            updateTelephonySignalStrength();
-            updateDataNetType();
-            updateDataIcon();
-            refreshViews();
-        }
-
-        @Override
-        public void onCallStateChanged(int state, String incomingNumber) {
-            if (DEBUG) {
-                Log.d(TAG, "onCallStateChanged state=" + state);
-            }
-            // In cdma, if a voice call is made, RSSI should switch to 1x.
-            if (isCdma()) {
-                updateTelephonySignalStrength();
-                refreshViews();
-            }
-        }
-
-        @Override
-        public void onDataConnectionStateChanged(int state, int networkType) {
-            if (DEBUG) {
-                Log.d(TAG, "onDataConnectionStateChanged: state=" + state
-                        + " type=" + networkType);
-            }
-            mDataState = state;
-            mDataNetType = networkType;
-            updateDataNetType();
-            updateDataIcon();
-            refreshViews();
-        }
-
-        @Override
-        public void onDataActivity(int direction) {
-            if (DEBUG) {
-                Log.d(TAG, "onDataActivity: direction=" + direction);
-            }
-            mDataActivity = direction;
-            updateDataIcon();
-            refreshViews();
-        }
-    };
-
-    private final void updateSimState(Intent intent) {
-        String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
-        if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
-            mSimState = IccCardConstants.State.ABSENT;
-        }
-        else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
-            mSimState = IccCardConstants.State.READY;
-        }
-        else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
-            final String lockedReason =
-                    intent.getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
-            if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
-                mSimState = IccCardConstants.State.PIN_REQUIRED;
-            }
-            else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
-                mSimState = IccCardConstants.State.PUK_REQUIRED;
-            }
-            else {
-                mSimState = IccCardConstants.State.NETWORK_LOCKED;
-            }
-        } else {
-            mSimState = IccCardConstants.State.UNKNOWN;
-        }
-        if (DEBUG) Log.d(TAG, "updateSimState: mSimState=" + mSimState);
-    }
-
-    private boolean isCdma() {
-        return (mSignalStrength != null) && !mSignalStrength.isGsm();
-    }
-
-    private boolean hasService() {
-        boolean retVal;
-        if (mServiceState != null) {
-            // Consider the device to be in service if either voice or data service is available.
-            // Some SIM cards are marketed as data-only and do not support voice service, and on
-            // these SIM cards, we want to show signal bars for data service as well as the "no
-            // service" or "emergency calls only" text that indicates that voice is not available.
-            switch(mServiceState.getVoiceRegState()) {
-                case ServiceState.STATE_POWER_OFF:
-                    retVal = false;
-                    break;
-                case ServiceState.STATE_OUT_OF_SERVICE:
-                case ServiceState.STATE_EMERGENCY_ONLY:
-                    retVal = mServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE;
-                    break;
-                default:
-                    retVal = true;
-            }
-        } else {
-            retVal = false;
-        }
-        if (DEBUG) Log.d(TAG, "hasService: mServiceState=" + mServiceState + " retVal=" + retVal);
-        return retVal;
-    }
-
-    private void updateAirplaneMode() {
-        mAirplaneMode = (Settings.Global.getInt(mContext.getContentResolver(),
-            Settings.Global.AIRPLANE_MODE_ON, 0) == 1);
     }
 
     private void refreshLocale() {
-        mLocale = mContext.getResources().getConfiguration().locale;
-    }
-
-    private final void updateTelephonySignalStrength() {
-        if (DEBUG) {
-            Log.d(TAG, "updateTelephonySignalStrength: hasService=" + hasService()
-                    + " ss=" + mSignalStrength);
-        }
-        if (!hasService()) {
-            if (CHATTY) Log.d(TAG, "updateTelephonySignalStrength: !hasService()");
-            mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
-            mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal;
-            mDataSignalIconId = R.drawable.stat_sys_signal_null;
-            mContentDescriptionPhoneSignal = mContext.getString(
-                    AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0]);
-        } else {
-            if (mSignalStrength == null) {
-                if (CHATTY) Log.d(TAG, "updateTelephonySignalStrength: mSignalStrength == null");
-                mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
-                mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal;
-                mDataSignalIconId = R.drawable.stat_sys_signal_null;
-                mContentDescriptionPhoneSignal = mContext.getString(
-                        AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0]);
-            } else {
-                int iconLevel;
-                int[] iconList;
-                if (isCdma() && mAlwaysShowCdmaRssi) {
-                    mLastSignalLevel = iconLevel = mSignalStrength.getCdmaLevel();
-                    if (DEBUG) {
-                        Log.d(TAG, "updateTelephonySignalStrength:"
-                            + " mAlwaysShowCdmaRssi=" + mAlwaysShowCdmaRssi
-                            + " set to cdmaLevel=" + mSignalStrength.getCdmaLevel()
-                            + " instead of level=" + mSignalStrength.getLevel());
-                    }
-                } else {
-                    mLastSignalLevel = iconLevel = mSignalStrength.getLevel();
-                }
-
-                if (isRoaming()) {
-                    iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition];
-                } else {
-                    iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition];
-                }
-                mPhoneSignalIconId = iconList[iconLevel];
-                mQSPhoneSignalIconId =
-                        TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[mInetCondition][iconLevel];
-                mContentDescriptionPhoneSignal = mContext.getString(
-                        AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[iconLevel]);
-                mDataSignalIconId = TelephonyIcons.DATA_SIGNAL_STRENGTH[mInetCondition][iconLevel];
-                if (DEBUG) Log.d(TAG, "updateTelephonySignalStrength: iconLevel=" + iconLevel);
-            }
+        Locale current = mContext.getResources().getConfiguration().locale;
+        if (current.equals(mLocale)) {
+            mLocale = current;
+            notifyAllListeners();
         }
     }
 
-    private int inetConditionForNetwork(int networkType) {
-        return (mInetCondition == 1 && mConnectedNetworkType == networkType) ? 1 : 0;
+    /**
+     * Turns inet condition into a boolean indexing for a specific network.
+     * returns 0 for bad connectivity on this network.
+     * returns 1 for good connectivity on this network.
+     */
+    private int inetConditionForNetwork(int networkType, boolean inetCondition) {
+        return (inetCondition && mConnectedNetworkType == networkType) ? 1 : 0;
     }
 
-    private final void updateDataNetType() {
-        int inetCondition;
-        mDataTypeIconId = mQSDataTypeIconId = 0;
-        if (mIsWimaxEnabled && mWimaxConnected) {
-            // wimax is a special 4g network not handled by telephony
-            inetCondition = inetConditionForNetwork(ConnectivityManager.TYPE_WIMAX);
-            mDataIconList = TelephonyIcons.DATA_4G[inetCondition];
-            mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_4g;
-            mQSDataTypeIconId = TelephonyIcons.QS_DATA_4G[inetCondition];
-            mContentDescriptionDataType = mContext.getString(
-                    R.string.accessibility_data_connection_4g);
-        } else {
-            inetCondition = inetConditionForNetwork(ConnectivityManager.TYPE_MOBILE);
-            final boolean showDataTypeIcon = (inetCondition > 0);
-            switch (mDataNetType) {
-                case TelephonyManager.NETWORK_TYPE_UNKNOWN:
-                    if (!mShowAtLeastThreeGees) {
-                        mDataIconList = TelephonyIcons.DATA_G[inetCondition];
-                        mContentDescriptionDataType = "";
-                        break;
-                    } else {
-                        // fall through
-                    }
-                case TelephonyManager.NETWORK_TYPE_EDGE:
-                    if (!mShowAtLeastThreeGees) {
-                        mDataIconList = TelephonyIcons.DATA_E[inetCondition];
-                        mDataTypeIconId = showDataTypeIcon ?
-                                R.drawable.stat_sys_data_fully_connected_e : 0;
-                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_E[inetCondition];
-                        mContentDescriptionDataType = mContext.getString(
-                                R.string.accessibility_data_connection_edge);
-                        break;
-                    } else {
-                        // fall through
-                    }
-                case TelephonyManager.NETWORK_TYPE_UMTS:
-                    mDataIconList = TelephonyIcons.DATA_3G[inetCondition];
-                    mDataTypeIconId = showDataTypeIcon ?
-                                R.drawable.stat_sys_data_fully_connected_3g : 0;
-                    mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[inetCondition];
-                    mContentDescriptionDataType = mContext.getString(
-                            R.string.accessibility_data_connection_3g);
-                    break;
-                case TelephonyManager.NETWORK_TYPE_HSDPA:
-                case TelephonyManager.NETWORK_TYPE_HSUPA:
-                case TelephonyManager.NETWORK_TYPE_HSPA:
-                case TelephonyManager.NETWORK_TYPE_HSPAP:
-                    if (mHspaDataDistinguishable) {
-                        mDataIconList = TelephonyIcons.DATA_H[inetCondition];
-                        mDataTypeIconId = showDataTypeIcon ?
-                                R.drawable.stat_sys_data_fully_connected_h : 0;
-                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_H[inetCondition];
-                        mContentDescriptionDataType = mContext.getString(
-                                R.string.accessibility_data_connection_3_5g);
-                    } else {
-                        mDataIconList = TelephonyIcons.DATA_3G[inetCondition];
-                        mDataTypeIconId = showDataTypeIcon ?
-                                R.drawable.stat_sys_data_fully_connected_3g : 0;
-                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[inetCondition];
-                        mContentDescriptionDataType = mContext.getString(
-                                R.string.accessibility_data_connection_3g);
-                    }
-                    break;
-                case TelephonyManager.NETWORK_TYPE_CDMA:
-                    if (!mShowAtLeastThreeGees) {
-                        // display 1xRTT for IS95A/B
-                        mDataIconList = TelephonyIcons.DATA_1X[inetCondition];
-                        mDataTypeIconId = showDataTypeIcon ?
-                                R.drawable.stat_sys_data_fully_connected_1x : 0;
-                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_1X[inetCondition];
-                        mContentDescriptionDataType = mContext.getString(
-                                R.string.accessibility_data_connection_cdma);
-                        break;
-                    } else {
-                        // fall through
-                    }
-                case TelephonyManager.NETWORK_TYPE_1xRTT:
-                    if (!mShowAtLeastThreeGees) {
-                        mDataIconList = TelephonyIcons.DATA_1X[inetCondition];
-                        mDataTypeIconId = showDataTypeIcon ?
-                                R.drawable.stat_sys_data_fully_connected_1x : 0;
-                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_1X[inetCondition];
-                        mContentDescriptionDataType = mContext.getString(
-                                R.string.accessibility_data_connection_cdma);
-                        break;
-                    } else {
-                        // fall through
-                    }
-                case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
-                case TelephonyManager.NETWORK_TYPE_EVDO_A:
-                case TelephonyManager.NETWORK_TYPE_EVDO_B:
-                case TelephonyManager.NETWORK_TYPE_EHRPD:
-                    mDataIconList = TelephonyIcons.DATA_3G[inetCondition];
-                    mDataTypeIconId = showDataTypeIcon ?
-                                R.drawable.stat_sys_data_fully_connected_3g : 0;
-                    mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[inetCondition];
-                    mContentDescriptionDataType = mContext.getString(
-                            R.string.accessibility_data_connection_3g);
-                    break;
-                case TelephonyManager.NETWORK_TYPE_LTE:
-                    boolean show4GforLTE = mContext.getResources().getBoolean(R.bool.config_show4GForLTE);
-                    if (show4GforLTE) {
-                        mDataIconList = TelephonyIcons.DATA_4G[inetCondition];
-                        mDataTypeIconId = showDataTypeIcon ?
-                                R.drawable.stat_sys_data_fully_connected_4g : 0;
-                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_4G[inetCondition];
-                        mContentDescriptionDataType = mContext.getString(
-                                R.string.accessibility_data_connection_4g);
-                    } else {
-                        mDataIconList = TelephonyIcons.DATA_LTE[inetCondition];
-                        mDataTypeIconId = showDataTypeIcon ? TelephonyIcons.ICON_LTE : 0;
-                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_LTE[inetCondition];
-                        mContentDescriptionDataType = mContext.getString(
-                                R.string.accessibility_data_connection_lte);
-                    }
-                    break;
-                default:
-                    if (!mShowAtLeastThreeGees) {
-                        mDataIconList = TelephonyIcons.DATA_G[inetCondition];
-                        mDataTypeIconId = showDataTypeIcon ?
-                                R.drawable.stat_sys_data_fully_connected_g : 0;
-                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_G[inetCondition];
-                        mContentDescriptionDataType = mContext.getString(
-                                R.string.accessibility_data_connection_gprs);
-                    } else {
-                        mDataIconList = TelephonyIcons.DATA_3G[inetCondition];
-                        mDataTypeIconId = showDataTypeIcon ?
-                                R.drawable.stat_sys_data_fully_connected_3g : 0;
-                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[inetCondition];
-                        mContentDescriptionDataType = mContext.getString(
-                                R.string.accessibility_data_connection_3g);
-                    }
-                    break;
-            }
-        }
+    private void notifyAllListeners() {
+        // Something changed, trigger everything!
+        notifyAirplaneCallbacks();
+        mMobileSignalController.notifyListeners();
+        mWifiSignalController.notifyListeners();
+    }
 
-        if (isRoaming()) {
-            mDataTypeIconId = TelephonyIcons.ROAMING_ICON;
-            mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
+    private void notifyAirplaneCallbacks() {
+        int length = mSignalClusters.size();
+        for (int i = 0; i < length; i++) {
+            mSignalClusters.get(i).setIsAirplaneMode(mAirplaneMode, TelephonyIcons.FLIGHT_MODE_ICON,
+                    R.string.accessibility_airplane_mode);
+        }
+        // update QS
+        int signalsChangedLength = mSignalsChangedCallbacks.size();
+        for (int i = 0; i < signalsChangedLength; i++) {
+            mSignalsChangedCallbacks.get(i).onAirplaneModeChanged(mAirplaneMode);
         }
     }
 
-    boolean isCdmaEri() {
-        if (mServiceState != null) {
-            final int iconIndex = mServiceState.getCdmaEriIconIndex();
-            if (iconIndex != EriInfo.ROAMING_INDICATOR_OFF) {
-                final int iconMode = mServiceState.getCdmaEriIconMode();
-                if (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL
-                        || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    private boolean isRoaming() {
-        if (isCdma()) {
-            return isCdmaEri();
-        } else {
-            return mServiceState != null && mServiceState.getRoaming();
-        }
-    }
-
-    private final void updateDataIcon() {
-        int iconId;
-        boolean visible = true;
-
-        if (!isCdma()) {
-            // GSM case, we have to check also the sim state
-            if (mSimState == IccCardConstants.State.READY ||
-                    mSimState == IccCardConstants.State.UNKNOWN) {
-                mNoSim = false;
-                if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
-                    switch (mDataActivity) {
-                        case TelephonyManager.DATA_ACTIVITY_IN:
-                            iconId = mDataIconList[1];
-                            break;
-                        case TelephonyManager.DATA_ACTIVITY_OUT:
-                            iconId = mDataIconList[2];
-                            break;
-                        case TelephonyManager.DATA_ACTIVITY_INOUT:
-                            iconId = mDataIconList[3];
-                            break;
-                        default:
-                            iconId = mDataIconList[0];
-                            break;
-                    }
-                    mDataDirectionIconId = iconId;
-                } else {
-                    iconId = 0;
-                    visible = false;
-                }
-            } else {
-                iconId = 0;
-                mNoSim = true;
-                visible = false; // no SIM? no data
-            }
-        } else {
-            // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT
-            if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
-                switch (mDataActivity) {
-                    case TelephonyManager.DATA_ACTIVITY_IN:
-                        iconId = mDataIconList[1];
-                        break;
-                    case TelephonyManager.DATA_ACTIVITY_OUT:
-                        iconId = mDataIconList[2];
-                        break;
-                    case TelephonyManager.DATA_ACTIVITY_INOUT:
-                        iconId = mDataIconList[3];
-                        break;
-                    case TelephonyManager.DATA_ACTIVITY_DORMANT:
-                    default:
-                        iconId = mDataIconList[0];
-                        break;
-                }
-            } else {
-                iconId = 0;
-                visible = false;
-            }
-        }
-
-        mDataDirectionIconId = iconId;
-        mDataConnected = visible;
-    }
-
-    void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) {
-        if (false) {
-            Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn
-                    + " showPlmn=" + showPlmn + " plmn=" + plmn);
-        }
-        StringBuilder str = new StringBuilder();
-        boolean something = false;
-        if (showPlmn && plmn != null) {
-            str.append(plmn);
-            something = true;
-        }
-        if (showSpn && spn != null) {
-            if (something) {
-                str.append(mNetworkNameSeparator);
-            }
-            str.append(spn);
-            something = true;
-        }
-        if (something) {
-            mNetworkName = str.toString();
-        } else {
-            mNetworkName = mNetworkNameDefault;
-        }
-    }
-
-    // ===== Wifi ===================================================================
-
-    class WifiHandler extends Handler {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
-                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
-                        mWifiChannel.sendMessage(Message.obtain(this,
-                                AsyncChannel.CMD_CHANNEL_FULL_CONNECTION));
-                    } else {
-                        Log.e(TAG, "Failed to connect to wifi");
-                    }
-                    break;
-                case WifiManager.DATA_ACTIVITY_NOTIFICATION:
-                    if (msg.arg1 != mWifiActivity) {
-                        mWifiActivity = msg.arg1;
-                        refreshViews();
-                    }
-                    break;
-                default:
-                    //Ignore
-                    break;
-            }
-        }
-    }
-
-    private void updateWifiState(Intent intent) {
-        final String action = intent.getAction();
-        if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
-            mWifiEnabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
-                    WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
-
-        } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
-            final NetworkInfo networkInfo = (NetworkInfo)
-                    intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
-            boolean wasConnected = mWifiConnected;
-            mWifiConnected = networkInfo != null && networkInfo.isConnected();
-            // If Connected grab the signal strength and ssid
-            if (mWifiConnected) {
-                // try getting it out of the intent first
-                WifiInfo info = (WifiInfo) intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
-                if (info == null) {
-                    info = mWifiManager.getConnectionInfo();
-                }
-                if (info != null) {
-                    mWifiSsid = huntForSsid(info);
-                } else {
-                    mWifiSsid = null;
-                }
-            } else if (!mWifiConnected) {
-                mWifiSsid = null;
-            }
-        } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
-            mWifiRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
-            mWifiLevel = WifiManager.calculateSignalLevel(
-                    mWifiRssi, WifiIcons.WIFI_LEVEL_COUNT);
-        }
-
-        updateWifiIcons();
-    }
-
-    private void updateWifiIcons() {
-        int inetCondition = inetConditionForNetwork(ConnectivityManager.TYPE_WIFI);
-        if (mWifiConnected) {
-            mWifiIconId = WifiIcons.WIFI_SIGNAL_STRENGTH[inetCondition][mWifiLevel];
-            mQSWifiIconId = WifiIcons.QS_WIFI_SIGNAL_STRENGTH[inetCondition][mWifiLevel];
-            mContentDescriptionWifi = mContext.getString(
-                    AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH[mWifiLevel]);
-        } else {
-            if (mDataAndWifiStacked) {
-                mWifiIconId = 0;
-                mQSWifiIconId = 0;
-            } else {
-                mWifiIconId = mWifiEnabled ? R.drawable.stat_sys_wifi_signal_null : 0;
-                mQSWifiIconId = mWifiEnabled ? R.drawable.ic_qs_wifi_no_network : 0;
-            }
-            mContentDescriptionWifi = mContext.getString(R.string.accessibility_no_wifi);
-        }
-    }
-
-    private String huntForSsid(WifiInfo info) {
-        String ssid = info.getSSID();
-        if (ssid != null) {
-            return ssid;
-        }
-        // OK, it's not in the connectionInfo; we have to go hunting for it
-        List<WifiConfiguration> networks = mWifiManager.getConfiguredNetworks();
-        for (WifiConfiguration net : networks) {
-            if (net.networkId == info.getNetworkId()) {
-                return net.SSID;
-            }
-        }
-        return null;
-    }
-
-
-    // ===== Wimax ===================================================================
-    private final void updateWimaxState(Intent intent) {
-        final String action = intent.getAction();
-        boolean wasConnected = mWimaxConnected;
-        if (action.equals(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION)) {
-            int wimaxStatus = intent.getIntExtra(WimaxManagerConstants.EXTRA_4G_STATE,
-                    WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
-            mIsWimaxEnabled = (wimaxStatus ==
-                    WimaxManagerConstants.NET_4G_STATE_ENABLED);
-        } else if (action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION)) {
-            mWimaxSignal = intent.getIntExtra(WimaxManagerConstants.EXTRA_NEW_SIGNAL_LEVEL, 0);
-        } else if (action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) {
-            mWimaxState = intent.getIntExtra(WimaxManagerConstants.EXTRA_WIMAX_STATE,
-                    WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
-            mWimaxExtraState = intent.getIntExtra(
-                    WimaxManagerConstants.EXTRA_WIMAX_STATE_DETAIL,
-                    WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
-            mWimaxConnected = (mWimaxState ==
-                    WimaxManagerConstants.WIMAX_STATE_CONNECTED);
-            mWimaxIdle = (mWimaxExtraState == WimaxManagerConstants.WIMAX_IDLE);
-        }
-        updateDataNetType();
-        updateWimaxIcons();
-    }
-
-    private void updateWimaxIcons() {
-        if (mIsWimaxEnabled) {
-            if (mWimaxConnected) {
-                int inetCondition = inetConditionForNetwork(ConnectivityManager.TYPE_WIMAX);
-                if (mWimaxIdle)
-                    mWimaxIconId = WimaxIcons.WIMAX_IDLE;
-                else
-                    mWimaxIconId = WimaxIcons.WIMAX_SIGNAL_STRENGTH[inetCondition][mWimaxSignal];
-                mContentDescriptionWimax = mContext.getString(
-                        AccessibilityContentDescriptions.WIMAX_CONNECTION_STRENGTH[mWimaxSignal]);
-            } else {
-                mWimaxIconId = WimaxIcons.WIMAX_DISCONNECTED;
-                mContentDescriptionWimax = mContext.getString(R.string.accessibility_no_wimax);
-            }
-        } else {
-            mWimaxIconId = 0;
-        }
-    }
-
-    // ===== Full or limited Internet connectivity ==================================
-
+    /**
+     * Update the Inet conditions and what network we are connected to.
+     */
     private void updateConnectivity(Intent intent) {
-        if (CHATTY) {
-            Log.d(TAG, "updateConnectivity: intent=" + intent);
-        }
-
         final NetworkInfo info = mConnectivityManager.getActiveNetworkInfo();
 
         // Are we connected at all, by any interface?
@@ -1108,7 +364,7 @@
             Log.d(TAG, "updateConnectivity: connectionStatus=" + connectionStatus);
         }
 
-        mInetCondition = (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0);
+        mInetCondition = connectionStatus > INET_CONDITION_THRESHOLD;
 
         if (info != null && info.getType() == ConnectivityManager.TYPE_BLUETOOTH) {
             mBluetoothTethered = info.isConnected();
@@ -1117,376 +373,68 @@
         }
 
         // We want to update all the icons, all at once, for any condition change
-        updateDataNetType();
-        updateWimaxIcons();
-        updateDataIcon();
-        updateTelephonySignalStrength();
-        updateWifiIcons();
+        mMobileSignalController.setInetCondition(mInetCondition ? 1 : 0,
+                inetConditionForNetwork(mMobileSignalController.getNetworkType(), mInetCondition));
+        mWifiSignalController.setInetCondition(
+                inetConditionForNetwork(mWifiSignalController.getNetworkType(), mInetCondition));
     }
 
-
-    // ===== Update the views =======================================================
-
-    void refreshViews() {
+    /**
+     * Recalculate and update the carrier label.
+     */
+    void refreshCarrierLabel() {
         Context context = mContext;
 
-        int combinedSignalIconId = 0;
-        String combinedLabel = "";
-        String wifiLabel = "";
-        String mobileLabel = "";
-        int N;
-        final boolean emergencyOnly = isEmergencyOnly();
+        WifiSignalController.WifiState wifiState = mWifiSignalController.getState();
+        MobileSignalController.MobileState mobileState = mMobileSignalController.getState();
+        String label = mMobileSignalController.getLabel("", mConnected, mHasMobileDataFeature);
 
-        if (!mHasMobileDataFeature) {
-            mDataSignalIconId = mPhoneSignalIconId = 0;
-            mQSPhoneSignalIconId = 0;
-            mobileLabel = "";
-        } else {
-            // We want to show the carrier name if in service and either:
-            //   - We are connected to mobile data, or
-            //   - We are not connected to mobile data, as long as the *reason* packets are not
-            //     being routed over that link is that we have better connectivity via wifi.
-            // If data is disconnected for some other reason but wifi (or ethernet/bluetooth)
-            // is connected, we show nothing.
-            // Otherwise (nothing connected) we show "No internet connection".
-
-            if (mDataConnected) {
-                mobileLabel = mNetworkName;
-            } else if (mConnected || emergencyOnly) {
-                if (hasService() || emergencyOnly) {
-                    // The isEmergencyOnly test covers the case of a phone with no SIM
-                    mobileLabel = mNetworkName;
-                } else {
-                    // Tablets, basically
-                    mobileLabel = "";
-                }
-            } else {
-                mobileLabel
-                    = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
-            }
-
-            // Now for things that should only be shown when actually using mobile data.
-            if (mDataConnected) {
-                combinedSignalIconId = mDataSignalIconId;
-
-                combinedLabel = mobileLabel;
-                combinedSignalIconId = mDataSignalIconId; // set by updateDataIcon()
-                mContentDescriptionCombinedSignal = mContentDescriptionDataType;
-            }
+        // TODO Simplify this ugliness, some of the flows below shouldn't be possible anymore
+        // but stay for the sake of history.
+        if (mBluetoothTethered && !mHasMobileDataFeature) {
+            label = mContext.getString(R.string.bluetooth_tethered);
         }
 
-        if (mWifiConnected) {
-            if (mWifiSsid == null) {
-                wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_wifi_nossid);
-            } else {
-                wifiLabel = mWifiSsid;
-                if (DEBUG) {
-                    wifiLabel += "xxxxXXXXxxxxXXXX";
-                }
-            }
-
-            combinedLabel = wifiLabel;
-            combinedSignalIconId = mWifiIconId; // set by updateWifiIcons()
-            mContentDescriptionCombinedSignal = mContentDescriptionWifi;
-        } else {
-            if (mHasMobileDataFeature) {
-                wifiLabel = "";
-            } else {
-                wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
-            }
+        final boolean ethernetConnected =
+                (mConnectedNetworkType == ConnectivityManager.TYPE_ETHERNET);
+        if (ethernetConnected && !mHasMobileDataFeature) {
+            label = context.getString(R.string.ethernet_label);
         }
 
-        if (mBluetoothTethered) {
-            combinedLabel = mContext.getString(R.string.bluetooth_tethered);
-            combinedSignalIconId = mBluetoothTetherIconId;
-            mContentDescriptionCombinedSignal = mContext.getString(
-                    R.string.accessibility_bluetooth_tether);
-        }
-
-        final boolean ethernetConnected = (mConnectedNetworkType == ConnectivityManager.TYPE_ETHERNET);
-        if (ethernetConnected) {
-            combinedLabel = context.getString(R.string.ethernet_label);
-        }
-
-        if (mAirplaneMode &&
-                (mServiceState == null || (!hasService() && !mServiceState.isEmergencyOnly()))) {
-            // Only display the flight-mode icon if not in "emergency calls only" mode.
-
-            // look again; your radios are now airplanes
-            mContentDescriptionPhoneSignal = mContext.getString(
-                    R.string.accessibility_airplane_mode);
-            mAirplaneIconId = TelephonyIcons.FLIGHT_MODE_ICON;
-            mPhoneSignalIconId = mDataSignalIconId = mDataTypeIconId = mQSDataTypeIconId = 0;
-            mQSPhoneSignalIconId = 0;
-
+        if (mAirplaneMode && (!mobileState.connected && !mobileState.isEmergency)) {
             // combined values from connected wifi take precedence over airplane mode
-            if (mWifiConnected) {
+            if (wifiState.connected && mHasMobileDataFeature) {
                 // Suppress "No internet connection." from mobile if wifi connected.
-                mobileLabel = "";
+                label = "";
             } else {
-                if (mHasMobileDataFeature) {
-                    // let the mobile icon show "No internet connection."
-                    wifiLabel = "";
-                } else {
-                    wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
-                    combinedLabel = wifiLabel;
-                }
-                mContentDescriptionCombinedSignal = mContentDescriptionPhoneSignal;
-                combinedSignalIconId = mDataSignalIconId;
+                 if (!mHasMobileDataFeature) {
+                      label = context.getString(
+                              R.string.status_bar_settings_signal_meter_disconnected);
+                 }
             }
-        }
-        else if (!mDataConnected && !mWifiConnected && !mBluetoothTethered && !mWimaxConnected && !ethernetConnected) {
-            // pretty much totally disconnected
-
-            combinedLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
-            // On devices without mobile radios, we want to show the wifi icon
-            combinedSignalIconId =
-                mHasMobileDataFeature ? mDataSignalIconId : mWifiIconId;
-            mContentDescriptionCombinedSignal = mHasMobileDataFeature
-                ? mContentDescriptionDataType : mContentDescriptionWifi;
-
-            int inetCondition = inetConditionForNetwork(ConnectivityManager.TYPE_MOBILE);
-
-            mDataTypeIconId = 0;
-            mQSDataTypeIconId = 0;
-            if (isRoaming()) {
-                mDataTypeIconId = TelephonyIcons.ROAMING_ICON;
-                mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
-            }
+        } else if (!mobileState.dataConnected && !wifiState.connected && !mBluetoothTethered &&
+                 !ethernetConnected && !mHasMobileDataFeature) {
+            // Pretty much no connection.
+            label = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
         }
 
-        if (mDemoMode) {
-            mQSWifiIconId = mDemoWifiLevel < 0 ? R.drawable.ic_qs_wifi_no_network
-                    : WifiIcons.QS_WIFI_SIGNAL_STRENGTH[mDemoInetCondition][mDemoWifiLevel];
-            mQSPhoneSignalIconId = mDemoMobileLevel < 0 ? R.drawable.ic_qs_signal_no_signal :
-                    TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[mDemoInetCondition][mDemoMobileLevel];
-            mQSDataTypeIconId = mDemoQSDataTypeIconId;
-        }
-
-        if (DEBUG) {
-            Log.d(TAG, "refreshViews connected={"
-                    + (mWifiConnected?" wifi":"")
-                    + (mDataConnected?" data":"")
-                    + " } level="
-                    + ((mSignalStrength == null)?"??":Integer.toString(mSignalStrength.getLevel()))
-                    + " combinedSignalIconId=0x"
-                    + Integer.toHexString(combinedSignalIconId)
-                    + "/" + getResourceName(combinedSignalIconId)
-                    + " mobileLabel=" + mobileLabel
-                    + " wifiLabel=" + wifiLabel
-                    + " emergencyOnly=" + emergencyOnly
-                    + " combinedLabel=" + combinedLabel
-                    + " mAirplaneMode=" + mAirplaneMode
-                    + " mDataActivity=" + mDataActivity
-                    + " mPhoneSignalIconId=0x" + Integer.toHexString(mPhoneSignalIconId)
-                    + " mQSPhoneSignalIconId=0x" + Integer.toHexString(mQSPhoneSignalIconId)
-                    + " mDataDirectionIconId=0x" + Integer.toHexString(mDataDirectionIconId)
-                    + " mDataSignalIconId=0x" + Integer.toHexString(mDataSignalIconId)
-                    + " mDataTypeIconId=0x" + Integer.toHexString(mDataTypeIconId)
-                    + " mQSDataTypeIconId=0x" + Integer.toHexString(mQSDataTypeIconId)
-                    + " mWifiIconId=0x" + Integer.toHexString(mWifiIconId)
-                    + " mQSWifiIconId=0x" + Integer.toHexString(mQSWifiIconId)
-                    + " mBluetoothTetherIconId=0x" + Integer.toHexString(mBluetoothTetherIconId));
-        }
-
-        // update QS
-        for (NetworkSignalChangedCallback cb : mSignalsChangedCallbacks) {
-            notifySignalsChangedCallbacks(cb);
-        }
-
-        if (mLastPhoneSignalIconId          != mPhoneSignalIconId
-         || mLastWifiIconId                 != mWifiIconId
-         || mLastInetCondition              != mInetCondition
-         || mLastWimaxIconId                != mWimaxIconId
-         || mLastDataTypeIconId             != mDataTypeIconId
-         || mLastAirplaneMode               != mAirplaneMode
-         || mLastLocale                     != mLocale
-         || mLastConnectedNetworkType       != mConnectedNetworkType)
-        {
-            // NB: the mLast*s will be updated later
-            for (SignalCluster cluster : mSignalClusters) {
-                refreshSignalCluster(cluster);
-            }
-        }
-
-        if (mLastAirplaneMode != mAirplaneMode) {
-            mLastAirplaneMode = mAirplaneMode;
-        }
-
-        if (mLastLocale != mLocale) {
-            mLastLocale = mLocale;
-        }
-
-        // the phone icon on phones
-        if (mLastPhoneSignalIconId != mPhoneSignalIconId) {
-            mLastPhoneSignalIconId = mPhoneSignalIconId;
-        }
-
-        // the data icon on phones
-        if (mLastDataDirectionIconId != mDataDirectionIconId) {
-            mLastDataDirectionIconId = mDataDirectionIconId;
-        }
-
-        // the wifi icon on phones
-        if (mLastWifiIconId != mWifiIconId) {
-            mLastWifiIconId = mWifiIconId;
-        }
-
-        if (mLastInetCondition != mInetCondition) {
-            mLastInetCondition = mInetCondition;
-        }
-
-        if (mLastConnectedNetworkType != mConnectedNetworkType) {
-            mLastConnectedNetworkType = mConnectedNetworkType;
-        }
-
-        // the wimax icon on phones
-        if (mLastWimaxIconId != mWimaxIconId) {
-            mLastWimaxIconId = mWimaxIconId;
-        }
-        // the combined data signal icon
-        if (mLastCombinedSignalIconId != combinedSignalIconId) {
-            mLastCombinedSignalIconId = combinedSignalIconId;
-        }
-
-        // the data network type overlay
-        if (mLastDataTypeIconId != mDataTypeIconId) {
-            mLastDataTypeIconId = mDataTypeIconId;
-        }
-
-        // the combinedLabel in the notification panel
-        if (!mLastCombinedLabel.equals(combinedLabel)) {
-            mLastCombinedLabel = combinedLabel;
-            N = mCombinedLabelViews.size();
-            for (int i=0; i<N; i++) {
-                TextView v = mCombinedLabelViews.get(i);
-                v.setText(combinedLabel);
-            }
-        }
-
-        // wifi label
-        N = mWifiLabelViews.size();
-        for (int i=0; i<N; i++) {
-            TextView v = mWifiLabelViews.get(i);
-            v.setText(wifiLabel);
-            if ("".equals(wifiLabel)) {
-                v.setVisibility(View.GONE);
-            } else {
-                v.setVisibility(View.VISIBLE);
-            }
-        }
-
-        // mobile label
-        N = mMobileLabelViews.size();
-        for (int i=0; i<N; i++) {
-            TextView v = mMobileLabelViews.get(i);
-            v.setText(mobileLabel);
-            if ("".equals(mobileLabel)) {
-                v.setVisibility(View.GONE);
-            } else {
-                v.setVisibility(View.VISIBLE);
-            }
-        }
-
-        // e-call label
-        N = mEmergencyViews.size();
-        for (int i=0; i<N; i++) {
-            StatusBarHeaderView v = mEmergencyViews.get(i);
-            v.setShowEmergencyCallsOnly(emergencyOnly);
+        // for mobile devices, we always show mobile connection info here (SPN/PLMN)
+        // for other devices, we show whatever network is connected
+        // This is determined above by references to mHasMobileDataFeature.
+        int length = mCarrierListeners.size();
+        for (int i = 0; i < length; i++) {
+            mCarrierListeners.get(i).setCarrierLabel(label);
         }
     }
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("NetworkController state:");
         pw.println(String.format("  %s network type %d (%s)",
-                mConnected?"CONNECTED":"DISCONNECTED",
+                mConnected ? "CONNECTED" : "DISCONNECTED",
                 mConnectedNetworkType, mConnectedNetworkTypeName));
         pw.println("  - telephony ------");
         pw.print("  hasVoiceCallingFeature()=");
         pw.println(hasVoiceCallingFeature());
-        pw.print("  hasService()=");
-        pw.println(hasService());
-        pw.print("  mHspaDataDistinguishable=");
-        pw.println(mHspaDataDistinguishable);
-        pw.print("  mDataConnected=");
-        pw.println(mDataConnected);
-        pw.print("  mSimState=");
-        pw.println(mSimState);
-        pw.print("  mPhoneState=");
-        pw.println(mPhoneState);
-        pw.print("  mDataState=");
-        pw.println(mDataState);
-        pw.print("  mDataActivity=");
-        pw.println(mDataActivity);
-        pw.print("  mDataNetType=");
-        pw.print(mDataNetType);
-        pw.print("/");
-        pw.println(TelephonyManager.getNetworkTypeName(mDataNetType));
-        pw.print("  mServiceState=");
-        pw.println(mServiceState);
-        pw.print("  mSignalStrength=");
-        pw.println(mSignalStrength);
-        pw.print("  mLastSignalLevel=");
-        pw.println(mLastSignalLevel);
-        pw.print("  mNetworkName=");
-        pw.println(mNetworkName);
-        pw.print("  mNetworkNameDefault=");
-        pw.println(mNetworkNameDefault);
-        pw.print("  mNetworkNameSeparator=");
-        pw.println(mNetworkNameSeparator.replace("\n","\\n"));
-        pw.print("  mPhoneSignalIconId=0x");
-        pw.print(Integer.toHexString(mPhoneSignalIconId));
-        pw.print("/");
-        pw.print("  mQSPhoneSignalIconId=0x");
-        pw.print(Integer.toHexString(mQSPhoneSignalIconId));
-        pw.print("/");
-        pw.println(getResourceName(mPhoneSignalIconId));
-        pw.print("  mDataDirectionIconId=");
-        pw.print(Integer.toHexString(mDataDirectionIconId));
-        pw.print("/");
-        pw.println(getResourceName(mDataDirectionIconId));
-        pw.print("  mDataSignalIconId=");
-        pw.print(Integer.toHexString(mDataSignalIconId));
-        pw.print("/");
-        pw.println(getResourceName(mDataSignalIconId));
-        pw.print("  mDataTypeIconId=");
-        pw.print(Integer.toHexString(mDataTypeIconId));
-        pw.print("/");
-        pw.println(getResourceName(mDataTypeIconId));
-        pw.print("  mQSDataTypeIconId=");
-        pw.print(Integer.toHexString(mQSDataTypeIconId));
-        pw.print("/");
-        pw.println(getResourceName(mQSDataTypeIconId));
-
-        pw.println("  - wifi ------");
-        pw.print("  mWifiEnabled=");
-        pw.println(mWifiEnabled);
-        pw.print("  mWifiConnected=");
-        pw.println(mWifiConnected);
-        pw.print("  mWifiRssi=");
-        pw.println(mWifiRssi);
-        pw.print("  mWifiLevel=");
-        pw.println(mWifiLevel);
-        pw.print("  mWifiSsid=");
-        pw.println(mWifiSsid);
-        pw.println(String.format("  mWifiIconId=0x%08x/%s",
-                    mWifiIconId, getResourceName(mWifiIconId)));
-        pw.println(String.format("  mQSWifiIconId=0x%08x/%s",
-                    mQSWifiIconId, getResourceName(mQSWifiIconId)));
-        pw.print("  mWifiActivity=");
-        pw.println(mWifiActivity);
-
-        if (mWimaxSupported) {
-            pw.println("  - wimax ------");
-            pw.print("  mIsWimaxEnabled="); pw.println(mIsWimaxEnabled);
-            pw.print("  mWimaxConnected="); pw.println(mWimaxConnected);
-            pw.print("  mWimaxIdle="); pw.println(mWimaxIdle);
-            pw.println(String.format("  mWimaxIconId=0x%08x/%s",
-                        mWimaxIconId, getResourceName(mWimaxIconId)));
-            pw.println(String.format("  mWimaxSignal=%d", mWimaxSignal));
-            pw.println(String.format("  mWimaxState=%d", mWimaxState));
-            pw.println(String.format("  mWimaxExtraState=%d", mWimaxExtraState));
-        }
 
         pw.println("  - Bluetooth ----");
         pw.print("  mBtReverseTethered=");
@@ -1495,143 +443,1079 @@
         pw.println("  - connectivity ------");
         pw.print("  mInetCondition=");
         pw.println(mInetCondition);
+        pw.print("  mAirplaneMode=");
+        pw.println(mAirplaneMode);
+        pw.print("  mLocale=");
+        pw.println(mLocale);
 
-        pw.println("  - icons ------");
-        pw.print("  mLastPhoneSignalIconId=0x");
-        pw.print(Integer.toHexString(mLastPhoneSignalIconId));
-        pw.print("/");
-        pw.println(getResourceName(mLastPhoneSignalIconId));
-        pw.print("  mLastDataDirectionIconId=0x");
-        pw.print(Integer.toHexString(mLastDataDirectionIconId));
-        pw.print("/");
-        pw.println(getResourceName(mLastDataDirectionIconId));
-        pw.print("  mLastWifiIconId=0x");
-        pw.print(Integer.toHexString(mLastWifiIconId));
-        pw.print("/");
-        pw.println(getResourceName(mLastWifiIconId));
-        pw.print("  mLastCombinedSignalIconId=0x");
-        pw.print(Integer.toHexString(mLastCombinedSignalIconId));
-        pw.print("/");
-        pw.println(getResourceName(mLastCombinedSignalIconId));
-        pw.print("  mLastDataTypeIconId=0x");
-        pw.print(Integer.toHexString(mLastDataTypeIconId));
-        pw.print("/");
-        pw.println(getResourceName(mLastDataTypeIconId));
-        pw.print("  mLastCombinedLabel=");
-        pw.print(mLastCombinedLabel);
-        pw.println("");
-    }
-
-    private String getResourceName(int resId) {
-        if (resId != 0) {
-            final Resources res = mContext.getResources();
-            try {
-                return res.getResourceName(resId);
-            } catch (android.content.res.Resources.NotFoundException ex) {
-                return "(unknown)";
-            }
-        } else {
-            return "(null)";
-        }
+        mMobileSignalController.dump(pw);
+        mWifiSignalController.dump(pw);
     }
 
     private boolean mDemoMode;
     private int mDemoInetCondition;
-    private int mDemoWifiLevel;
-    private int mDemoDataTypeIconId;
-    private int mDemoQSDataTypeIconId;
-    private int mDemoMobileLevel;
+    private WifiSignalController.WifiState mDemoWifiState;
+    private MobileSignalController.MobileState mDemoMobileState;
 
     @Override
     public void dispatchDemoCommand(String command, Bundle args) {
         if (!mDemoMode && command.equals(COMMAND_ENTER)) {
+            if (DEBUG) Log.d(TAG, "Entering demo mode");
+            unregisterListeners();
             mDemoMode = true;
-            mDemoWifiLevel = mWifiLevel;
-            mDemoInetCondition = mInetCondition;
-            mDemoDataTypeIconId = mDataTypeIconId;
-            mDemoQSDataTypeIconId = mQSDataTypeIconId;
-            mDemoMobileLevel = mLastSignalLevel;
+            mDemoInetCondition = mInetCondition ? 1 : 0;
+            mDemoWifiState = mWifiSignalController.getState();
+            mDemoMobileState = mMobileSignalController.getState();
         } else if (mDemoMode && command.equals(COMMAND_EXIT)) {
+            if (DEBUG) Log.d(TAG, "Exiting demo mode");
             mDemoMode = false;
-            for (SignalCluster cluster : mSignalClusters) {
-                refreshSignalCluster(cluster);
-            }
-            refreshViews();
+            mWifiSignalController.resetLastState();
+            mMobileSignalController.resetLastState();
+            registerListeners();
+            notifyAllListeners();
+            refreshCarrierLabel();
         } else if (mDemoMode && command.equals(COMMAND_NETWORK)) {
             String airplane = args.getString("airplane");
             if (airplane != null) {
                 boolean show = airplane.equals("show");
-                for (SignalCluster cluster : mSignalClusters) {
-                    cluster.setIsAirplaneMode(show, TelephonyIcons.FLIGHT_MODE_ICON);
+                int length = mSignalClusters.size();
+                for (int i = 0; i < length; i++) {
+                    mSignalClusters.get(i).setIsAirplaneMode(show, TelephonyIcons.FLIGHT_MODE_ICON,
+                            R.string.accessibility_airplane_mode);
                 }
             }
             String fully = args.getString("fully");
             if (fully != null) {
                 mDemoInetCondition = Boolean.parseBoolean(fully) ? 1 : 0;
+                mWifiSignalController.setInetCondition(mDemoInetCondition);
+                mMobileSignalController.setInetCondition(mDemoInetCondition, mDemoInetCondition);
             }
             String wifi = args.getString("wifi");
             if (wifi != null) {
                 boolean show = wifi.equals("show");
                 String level = args.getString("level");
                 if (level != null) {
-                    mDemoWifiLevel = level.equals("null") ? -1
+                    mDemoWifiState.level = level.equals("null") ? -1
                             : Math.min(Integer.parseInt(level), WifiIcons.WIFI_LEVEL_COUNT - 1);
+                    mDemoWifiState.connected = mDemoWifiState.level >= 0;
                 }
-                int iconId = mDemoWifiLevel < 0 ? R.drawable.stat_sys_wifi_signal_null
-                        : WifiIcons.WIFI_SIGNAL_STRENGTH[mDemoInetCondition][mDemoWifiLevel];
-                for (SignalCluster cluster : mSignalClusters) {
-                    cluster.setWifiIndicators(
-                            show,
-                            iconId,
-                            "Demo");
-                }
-                refreshViews();
+                mDemoWifiState.enabled = show;
+                mWifiSignalController.notifyListeners();
             }
             String mobile = args.getString("mobile");
             if (mobile != null) {
                 boolean show = mobile.equals("show");
                 String datatype = args.getString("datatype");
                 if (datatype != null) {
-                    mDemoDataTypeIconId =
-                            datatype.equals("1x") ? TelephonyIcons.ICON_1X :
-                            datatype.equals("3g") ? TelephonyIcons.ICON_3G :
-                            datatype.equals("4g") ? TelephonyIcons.ICON_4G :
-                            datatype.equals("e") ? R.drawable.stat_sys_data_fully_connected_e :
-                            datatype.equals("g") ? R.drawable.stat_sys_data_fully_connected_g :
-                            datatype.equals("h") ? R.drawable.stat_sys_data_fully_connected_h :
-                            datatype.equals("lte") ? TelephonyIcons.ICON_LTE :
-                            datatype.equals("roam") ? TelephonyIcons.ROAMING_ICON :
-                            0;
-                    mDemoQSDataTypeIconId =
-                            datatype.equals("1x") ? TelephonyIcons.QS_ICON_1X :
-                            datatype.equals("3g") ? TelephonyIcons.QS_ICON_3G :
-                            datatype.equals("4g") ? TelephonyIcons.QS_ICON_4G :
-                            datatype.equals("e") ? R.drawable.ic_qs_signal_e :
-                            datatype.equals("g") ? R.drawable.ic_qs_signal_g :
-                            datatype.equals("h") ? R.drawable.ic_qs_signal_h :
-                            datatype.equals("lte") ? TelephonyIcons.QS_ICON_LTE :
-                            datatype.equals("roam") ? R.drawable.ic_qs_signal_r :
-                            0;
+                    mDemoMobileState.iconGroup =
+                            datatype.equals("1x") ? TelephonyIcons.ONE_X :
+                            datatype.equals("3g") ? TelephonyIcons.THREE_G :
+                            datatype.equals("4g") ? TelephonyIcons.FOUR_G :
+                            datatype.equals("e") ? TelephonyIcons.E :
+                            datatype.equals("g") ? TelephonyIcons.G :
+                            datatype.equals("h") ? TelephonyIcons.H :
+                            datatype.equals("lte") ? TelephonyIcons.LTE :
+                            datatype.equals("roam") ? TelephonyIcons.ROAMING :
+                            TelephonyIcons.UNKNOWN;
                 }
                 int[][] icons = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH;
                 String level = args.getString("level");
                 if (level != null) {
-                    mDemoMobileLevel = level.equals("null") ? -1
+                    mDemoMobileState.level = level.equals("null") ? -1
                             : Math.min(Integer.parseInt(level), icons[0].length - 1);
+                    mDemoMobileState.connected = mDemoMobileState.level >= 0;
                 }
-                int iconId = mDemoMobileLevel < 0 ? R.drawable.stat_sys_signal_null :
-                        icons[mDemoInetCondition][mDemoMobileLevel];
-                for (SignalCluster cluster : mSignalClusters) {
-                    cluster.setMobileDataIndicators(
-                            show,
-                            iconId,
-                            mDemoDataTypeIconId,
-                            "Demo",
-                            "Demo",
-                            isTypeIconWide(mDemoDataTypeIconId));
-                }
-                refreshViews();
+                mDemoMobileState.enabled = show;
+                mMobileSignalController.notifyListeners();
             }
+            refreshCarrierLabel();
+        }
+    }
+
+    static class WifiSignalController extends
+            SignalController<WifiSignalController.WifiState, SignalController.IconGroup> {
+        private final WifiManager mWifiManager;
+        private final AsyncChannel mWifiChannel;
+        private final boolean mHasMobileData;
+
+        public WifiSignalController(Context context, boolean hasMobileData,
+                List<NetworkSignalChangedCallback> signalCallbacks,
+                List<SignalCluster> signalClusters, NetworkControllerImpl networkController) {
+            super("WifiSignalController", context, ConnectivityManager.TYPE_WIFI, signalCallbacks,
+                    signalClusters, networkController);
+            mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+            mHasMobileData = hasMobileData;
+            Handler handler = new WifiHandler();
+            mWifiChannel = new AsyncChannel();
+            Messenger wifiMessenger = mWifiManager.getWifiServiceMessenger();
+            if (wifiMessenger != null) {
+                mWifiChannel.connect(context, handler, wifiMessenger);
+            }
+            // WiFi only has one state.
+            mCurrentState.iconGroup = mLastState.iconGroup = new IconGroup(
+                    "Wi-Fi Icons",
+                    WifiIcons.WIFI_SIGNAL_STRENGTH,
+                    WifiIcons.QS_WIFI_SIGNAL_STRENGTH,
+                    AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH,
+                    WifiIcons.WIFI_NO_NETWORK,
+                    WifiIcons.QS_WIFI_NO_NETWORK,
+                    WifiIcons.WIFI_NO_NETWORK,
+                    WifiIcons.QS_WIFI_NO_NETWORK,
+                    AccessibilityContentDescriptions.WIFI_NO_CONNECTION
+                    );
+        }
+
+        @Override
+        public WifiState cleanState() {
+            return new WifiState();
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public void notifyListeners() {
+            // only show wifi in the cluster if connected or if wifi-only
+            boolean wifiEnabled = mCurrentState.enabled
+                    && (mCurrentState.connected || !mHasMobileData);
+            String wifiDesc = wifiEnabled ? mCurrentState.ssid : null;
+            boolean ssidPresent = wifiEnabled && mCurrentState.ssid != null;
+            String contentDescription = getStringIfExists(getContentDescription());
+            int length = mSignalsChangedCallbacks.size();
+            for (int i = 0; i < length; i++) {
+                mSignalsChangedCallbacks.get(i).onWifiSignalChanged(mCurrentState.enabled,
+                        mCurrentState.connected, getQsCurrentIconId(),
+                        ssidPresent && mCurrentState.activityIn,
+                        ssidPresent && mCurrentState.activityOut, contentDescription, wifiDesc);
+            }
+
+            int signalClustersLength = mSignalClusters.size();
+            for (int i = 0; i < signalClustersLength; i++) {
+                mSignalClusters.get(i).setWifiIndicators(
+                        // only show wifi in the cluster if connected or if wifi-only
+                        mCurrentState.enabled && (mCurrentState.connected || !mHasMobileData),
+                        getCurrentIconId(), contentDescription);
+            }
+        }
+
+        /**
+         * Extract wifi state directly from broadcasts about changes in wifi state.
+         */
+        public void handleBroadcast(Intent intent) {
+            String action = intent.getAction();
+            if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
+                mCurrentState.enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
+                        WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
+            } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
+                final NetworkInfo networkInfo = (NetworkInfo)
+                        intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
+                mCurrentState.connected = networkInfo != null && networkInfo.isConnected();
+                // If Connected grab the signal strength and ssid.
+                if (mCurrentState.connected) {
+                    // try getting it out of the intent first
+                    WifiInfo info = intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO) != null
+                            ? (WifiInfo) intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO)
+                            : mWifiManager.getConnectionInfo();
+                    if (info != null) {
+                        mCurrentState.ssid = huntForSsid(info);
+                    } else {
+                        mCurrentState.ssid = null;
+                    }
+                } else if (!mCurrentState.connected) {
+                    mCurrentState.ssid = null;
+                }
+            } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
+                mCurrentState.rssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
+                mCurrentState.level = WifiManager.calculateSignalLevel(
+                        mCurrentState.rssi, WifiIcons.WIFI_LEVEL_COUNT);
+            }
+
+            notifyListenersIfNecessary();
+        }
+
+        private String huntForSsid(WifiInfo info) {
+            String ssid = info.getSSID();
+            if (ssid != null) {
+                return ssid;
+            }
+            // OK, it's not in the connectionInfo; we have to go hunting for it
+            List<WifiConfiguration> networks = mWifiManager.getConfiguredNetworks();
+            int length = networks.size();
+            for (int i = 0; i < length; i++) {
+                if (networks.get(i).networkId == info.getNetworkId()) {
+                    return networks.get(i).SSID;
+                }
+            }
+            return null;
+        }
+
+        @VisibleForTesting
+        void setActivity(int wifiActivity) {
+            mCurrentState.activityIn = wifiActivity == WifiManager.DATA_ACTIVITY_INOUT
+                    || wifiActivity == WifiManager.DATA_ACTIVITY_IN;
+            mCurrentState.activityOut = wifiActivity == WifiManager.DATA_ACTIVITY_INOUT
+                    || wifiActivity == WifiManager.DATA_ACTIVITY_OUT;
+            notifyListenersIfNecessary();
+        }
+
+        /**
+         * Handler to receive the data activity on wifi.
+         */
+        class WifiHandler extends Handler {
+            @Override
+            public void handleMessage(Message msg) {
+                switch (msg.what) {
+                    case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
+                        if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
+                            mWifiChannel.sendMessage(Message.obtain(this,
+                                    AsyncChannel.CMD_CHANNEL_FULL_CONNECTION));
+                        } else {
+                            Log.e(mTag, "Failed to connect to wifi");
+                        }
+                        break;
+                    case WifiManager.DATA_ACTIVITY_NOTIFICATION:
+                        setActivity(msg.arg1);
+                        break;
+                    default:
+                        // Ignore
+                        break;
+                }
+            }
+        }
+
+        static class WifiState extends SignalController.State {
+            String ssid;
+
+            @Override
+            public void copyFrom(State s) {
+                WifiState state = (WifiState) s;
+                ssid = state.ssid;
+                super.copyFrom(s);
+            }
+
+            @Override
+            protected void toString(StringBuilder builder) {
+                builder.append("ssid=").append(ssid).append(',');
+                super.toString(builder);
+            }
+
+            @Override
+            public boolean equals(Object o) {
+                return super.equals(o)
+                        && Objects.equals(((WifiState) o).ssid, ssid);
+            }
+        }
+    }
+
+    static class MobileSignalController extends SignalController<MobileSignalController.MobileState,
+            MobileSignalController.MobileIconGroup> {
+        private final Config mConfig;
+        private final TelephonyManager mPhone;
+        private final String mNetworkNameDefault;
+        private final String mNetworkNameSeparator;
+
+        // @VisibleForDemoMode
+        Map<Integer, MobileIconGroup> mNetworkToIconLookup;
+
+        // Since some pieces of the phone state are interdependent we store it locally,
+        // this could potentially become part of MobileState for simplification/complication
+        // of code.
+        private IccCardConstants.State mSimState = IccCardConstants.State.READY;
+        private int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+        private int mDataState = TelephonyManager.DATA_DISCONNECTED;
+        private ServiceState mServiceState;
+        private SignalStrength mSignalStrength;
+        private MobileIconGroup mDefaultIcons;
+
+        // TODO: Reduce number of vars passed in, if we have the NetworkController, probably don't
+        // need listener lists anymore.
+        public MobileSignalController(Context context, Config config, boolean hasMobileData,
+                TelephonyManager phone, List<NetworkSignalChangedCallback> signalCallbacks,
+                List<SignalCluster> signalClusters, NetworkControllerImpl networkController) {
+            super("MobileSignalController", context, ConnectivityManager.TYPE_MOBILE,
+                    signalCallbacks, signalClusters, networkController);
+            mConfig = config;
+            mPhone = phone;
+            mNetworkNameSeparator = getStringIfExists(R.string.status_bar_network_name_separator);
+            mNetworkNameDefault = getStringIfExists(
+                    com.android.internal.R.string.lockscreen_carrier_default);
+
+            mapIconSets();
+
+            mLastState.networkName = mCurrentState.networkName = mNetworkNameDefault;
+            mLastState.enabled = mCurrentState.enabled = hasMobileData;
+            mLastState.iconGroup = mCurrentState.iconGroup = mDefaultIcons;
+        }
+
+        /**
+         * Get (the mobile parts of) the carrier string.
+         *
+         * @param currentLabel can be used for concatenation, currently just empty
+         * @param connected whether the device has connection to the internet at all
+         * @param isMobileLabel whether to always return the network or just when data is connected
+         */
+        public String getLabel(String currentLabel, boolean connected, boolean isMobileLabel) {
+            if (!mCurrentState.enabled) {
+                return "";
+            } else {
+                String mobileLabel = "";
+                // We want to show the carrier name if in service and either:
+                // - We are connected to mobile data, or
+                // - We are not connected to mobile data, as long as the *reason* packets are not
+                //   being routed over that link is that we have better connectivity via wifi.
+                // If data is disconnected for some other reason but wifi (or ethernet/bluetooth)
+                // is connected, we show nothing.
+                // Otherwise (nothing connected) we show "No internet connection".
+                if (mCurrentState.dataConnected) {
+                    mobileLabel = mCurrentState.networkName;
+                } else if (connected || mCurrentState.isEmergency) {
+                    if (mCurrentState.connected || mCurrentState.isEmergency) {
+                        // The isEmergencyOnly test covers the case of a phone with no SIM
+                        mobileLabel = mCurrentState.networkName;
+                    }
+                } else {
+                    mobileLabel = mContext
+                            .getString(R.string.status_bar_settings_signal_meter_disconnected);
+                }
+
+                // Now for things that should only be shown when actually using mobile data.
+                if (isMobileLabel) {
+                    return mobileLabel;
+                } else {
+                    return mCurrentState.dataConnected ? mobileLabel : currentLabel;
+                }
+            }
+        }
+
+        public int getDataContentDescription() {
+            return getIcons().mDataContentDescription;
+        }
+
+        public void setAirplaneMode(boolean airplaneMode) {
+            mCurrentState.airplaneMode = airplaneMode;
+            notifyListenersIfNecessary();
+        }
+
+        public void setInetCondition(int inetCondition, int inetConditionForNetwork) {
+            // For mobile data, use general inet condition for phone signal indexing,
+            // and network specific for data indexing (I think this might be a bug, but
+            // keeping for now).
+            // TODO: Update with explanation of why.
+            mCurrentState.inetForNetwork = inetConditionForNetwork;
+            setInetCondition(inetCondition);
+        }
+
+        /**
+         * Start listening for phone state changes.
+         */
+        public void registerListener() {
+            mPhone.listen(mPhoneStateListener,
+                    PhoneStateListener.LISTEN_SERVICE_STATE
+                            | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
+                            | PhoneStateListener.LISTEN_CALL_STATE
+                            | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
+                            | PhoneStateListener.LISTEN_DATA_ACTIVITY);
+        }
+
+        /**
+         * Stop listening for phone state changes.
+         */
+        public void unregisterListener() {
+            mPhone.listen(mPhoneStateListener, 0);
+        }
+
+        /**
+         * Produce a mapping of data network types to icon groups for simple and quick use in
+         * updateTelephony.
+         *
+         * TODO: See if config can change with locale, this may need to be regenerated on Locale
+         * change.
+         */
+        private void mapIconSets() {
+            mNetworkToIconLookup = new HashMap<Integer, MobileIconGroup>();
+
+            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_0, TelephonyIcons.THREE_G);
+            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_A, TelephonyIcons.THREE_G);
+            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_B, TelephonyIcons.THREE_G);
+            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EHRPD, TelephonyIcons.THREE_G);
+            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UMTS, TelephonyIcons.THREE_G);
+
+            if (!mConfig.showAtLeastThreeGees) {
+                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UNKNOWN,
+                        TelephonyIcons.UNKNOWN);
+                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EDGE, TelephonyIcons.E);
+                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_CDMA, TelephonyIcons.ONE_X);
+                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_1xRTT, TelephonyIcons.ONE_X);
+
+                mDefaultIcons = TelephonyIcons.G;
+            } else {
+                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UNKNOWN,
+                        TelephonyIcons.THREE_G);
+                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EDGE,
+                        TelephonyIcons.THREE_G);
+                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_CDMA,
+                        TelephonyIcons.THREE_G);
+                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_1xRTT,
+                        TelephonyIcons.THREE_G);
+                mDefaultIcons = TelephonyIcons.THREE_G;
+            }
+
+            MobileIconGroup hGroup = TelephonyIcons.THREE_G;
+            if (mConfig.hspaDataDistinguishable) {
+                hGroup = TelephonyIcons.H;
+            }
+            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSDPA, hGroup);
+            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSUPA, hGroup);
+            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPA, hGroup);
+            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPAP, hGroup);
+
+            if (mConfig.show4gForLte) {
+                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.FOUR_G);
+            } else {
+                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.LTE);
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public void notifyListeners() {
+            MobileIconGroup icons = getIcons();
+
+            String contentDescription = getStringIfExists(getContentDescription());
+            String dataContentDescription = getStringIfExists(icons.mDataContentDescription);
+            int qsTypeIcon = icons.mQsDataType[mCurrentState.inetForNetwork];
+            int length = mSignalsChangedCallbacks.size();
+            for (int i = 0; i < length; i++) {
+                mSignalsChangedCallbacks.get(i).onMobileDataSignalChanged(mCurrentState.enabled
+                        && !mCurrentState.isEmergency && !mCurrentState.airplaneMode,
+                        getQsCurrentIconId(), contentDescription,
+                        qsTypeIcon,
+                        mCurrentState.dataConnected && mCurrentState.activityIn,
+                        mCurrentState.dataConnected && mCurrentState.activityOut,
+                        dataContentDescription,
+                        mCurrentState.isEmergency ? null : mCurrentState.networkName,
+                        mCurrentState.noSim,
+                        // Only wide if actually showing something.
+                        icons.mIsWide && qsTypeIcon != 0);
+            }
+            boolean showDataIcon = mCurrentState.inetForNetwork != 0
+                    || mCurrentState.iconGroup == TelephonyIcons.ROAMING;
+            int typeIcon = showDataIcon ? icons.mDataType : 0;
+            int signalClustersLength = mSignalClusters.size();
+            for (int i = 0; i < signalClustersLength; i++) {
+                mSignalClusters.get(i).setMobileDataIndicators(
+                        mCurrentState.enabled && !mCurrentState.airplaneMode,
+                        getCurrentIconId(),
+                        typeIcon,
+                        contentDescription,
+                        dataContentDescription,
+                        // Only wide if actually showing something.
+                        icons.mIsWide && typeIcon != 0);
+            }
+        }
+
+        @Override
+        public MobileState cleanState() {
+            return new MobileState();
+        }
+
+        private boolean hasService() {
+            if (mServiceState != null) {
+                // Consider the device to be in service if either voice or data
+                // service is available. Some SIM cards are marketed as data-only
+                // and do not support voice service, and on these SIM cards, we
+                // want to show signal bars for data service as well as the "no
+                // service" or "emergency calls only" text that indicates that voice
+                // is not available.
+                switch (mServiceState.getVoiceRegState()) {
+                    case ServiceState.STATE_POWER_OFF:
+                        return false;
+                    case ServiceState.STATE_OUT_OF_SERVICE:
+                    case ServiceState.STATE_EMERGENCY_ONLY:
+                        return mServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE;
+                    default:
+                        return true;
+                }
+            } else {
+                return false;
+            }
+        }
+
+        private boolean isCdma() {
+            return (mSignalStrength != null) && !mSignalStrength.isGsm();
+        }
+
+        public boolean isEmergencyOnly() {
+            return (mServiceState != null && mServiceState.isEmergencyOnly());
+        }
+
+        private boolean isRoaming() {
+            if (isCdma()) {
+                final int iconMode = mServiceState.getCdmaEriIconMode();
+                return mServiceState.getCdmaEriIconIndex() != EriInfo.ROAMING_INDICATOR_OFF
+                        && (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL
+                            || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH);
+            } else {
+                return mServiceState != null && mServiceState.getRoaming();
+            }
+        }
+
+        public void handleBroadcast(Intent intent) {
+            String action = intent.getAction();
+            if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
+                String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
+                final String lockedReason =
+                        intent.getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
+                updateSimState(stateExtra, lockedReason);
+                updateTelephony();
+            } else if (action.equals(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION)) {
+                updateNetworkName(intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false),
+                        intent.getStringExtra(TelephonyIntents.EXTRA_SPN),
+                        intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false),
+                        intent.getStringExtra(TelephonyIntents.EXTRA_PLMN));
+                notifyListenersIfNecessary();
+            }
+        }
+
+        /**
+         * Determines the current sim state, based on a TelephonyIntents.ACTION_SIM_STATE_CHANGED
+         * broadcast.
+         */
+        private final void updateSimState(String stateExtra, String lockedReason) {
+            if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
+                mSimState = IccCardConstants.State.ABSENT;
+            } else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
+                mSimState = IccCardConstants.State.READY;
+            } else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
+                if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
+                    mSimState = IccCardConstants.State.PIN_REQUIRED;
+                } else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
+                    mSimState = IccCardConstants.State.PUK_REQUIRED;
+                } else {
+                    mSimState = IccCardConstants.State.NETWORK_LOCKED;
+                }
+            } else {
+                mSimState = IccCardConstants.State.UNKNOWN;
+            }
+            if (DEBUG) Log.d(TAG, "updateSimState: mSimState=" + mSimState);
+        }
+
+        /**
+         * Updates the network's name based on incoming spn and plmn.
+         */
+        void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) {
+            if (CHATTY) {
+                Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn
+                        + " showPlmn=" + showPlmn + " plmn=" + plmn);
+            }
+            StringBuilder str = new StringBuilder();
+            if (showPlmn && plmn != null) {
+                str.append(plmn);
+            }
+            if (showSpn && spn != null) {
+                if (str.length() != 0) {
+                    str.append(mNetworkNameSeparator);
+                }
+                str.append(spn);
+            }
+            if (str.length() != 0) {
+                mCurrentState.networkName = str.toString();
+            } else {
+                mCurrentState.networkName = mNetworkNameDefault;
+            }
+        }
+
+        /**
+         * Updates the current state based on mServiceState, mSignalStrength, mDataNetType,
+         * mDataState, and mSimState.  It should be called any time one of these is updated.
+         * This will call listeners if necessary.
+         */
+        private final void updateTelephony() {
+            if (DEBUG) {
+                Log.d(TAG, "updateTelephonySignalStrength: hasService=" + hasService()
+                        + " ss=" + mSignalStrength);
+            }
+            mCurrentState.connected = hasService() && mSignalStrength != null;
+            if (mCurrentState.connected) {
+                if (!mSignalStrength.isGsm() && mConfig.alwaysShowCdmaRssi) {
+                    mCurrentState.level = mSignalStrength.getCdmaLevel();
+                } else {
+                    mCurrentState.level = mSignalStrength.getLevel();
+                }
+            }
+            if (mNetworkToIconLookup.containsKey(mDataNetType)) {
+                mCurrentState.iconGroup = mNetworkToIconLookup.get(mDataNetType);
+            } else {
+                mCurrentState.iconGroup = mDefaultIcons;
+            }
+            mCurrentState.dataConnected = mCurrentState.connected
+                    && mDataState == TelephonyManager.DATA_CONNECTED;
+            if (!isCdma()) {
+                if (mSimState == IccCardConstants.State.READY ||
+                        mSimState == IccCardConstants.State.UNKNOWN) {
+                    mCurrentState.noSim = false;
+                } else {
+                    mCurrentState.noSim = true;
+                    // No sim, no data.
+                    mCurrentState.dataConnected = false;
+                }
+            }
+
+            if (isRoaming()) {
+                mCurrentState.iconGroup = TelephonyIcons.ROAMING;
+            }
+            if (isEmergencyOnly() != mCurrentState.isEmergency) {
+                mCurrentState.isEmergency = isEmergencyOnly();
+                mNetworkController.recalculateEmergency();
+            }
+            notifyListenersIfNecessary();
+        }
+
+        @VisibleForTesting
+        void setActivity(int activity) {
+            mCurrentState.activityIn = activity == TelephonyManager.DATA_ACTIVITY_INOUT
+                    || activity == TelephonyManager.DATA_ACTIVITY_IN;
+            mCurrentState.activityOut = activity == TelephonyManager.DATA_ACTIVITY_INOUT
+                    || activity == TelephonyManager.DATA_ACTIVITY_OUT;
+            notifyListenersIfNecessary();
+        }
+
+        @Override
+        public void dump(PrintWriter pw) {
+            super.dump(pw);
+            pw.println("  mServiceState=" + mServiceState + ",");
+            pw.println("  mSignalStrength=" + mSignalStrength + ",");
+            pw.println("  mDataState=" + mDataState + ",");
+            pw.println("  mDataNetType=" + mDataNetType + ",");
+        }
+
+        PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+            @Override
+            public void onSignalStrengthsChanged(SignalStrength signalStrength) {
+                if (DEBUG) {
+                    Log.d(TAG, "onSignalStrengthsChanged signalStrength=" + signalStrength +
+                            ((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel())));
+                }
+                mSignalStrength = signalStrength;
+                updateTelephony();
+            }
+
+            @Override
+            public void onServiceStateChanged(ServiceState state) {
+                if (DEBUG) {
+                    Log.d(TAG, "onServiceStateChanged voiceState=" + state.getVoiceRegState()
+                            + " dataState=" + state.getDataRegState());
+                }
+                mServiceState = state;
+                updateTelephony();
+            }
+
+            @Override
+            public void onDataConnectionStateChanged(int state, int networkType) {
+                if (DEBUG) {
+                    Log.d(TAG, "onDataConnectionStateChanged: state=" + state
+                            + " type=" + networkType);
+                }
+                mDataState = state;
+                mDataNetType = networkType;
+                updateTelephony();
+            }
+
+            @Override
+            public void onDataActivity(int direction) {
+                if (DEBUG) {
+                    Log.d(TAG, "onDataActivity: direction=" + direction);
+                }
+                setActivity(direction);
+            }
+        };
+
+        static class MobileIconGroup extends SignalController.IconGroup {
+            final int mDataContentDescription; // mContentDescriptionDataType
+            final int mDataType;
+            final boolean mIsWide;
+            final int[] mQsDataType;
+
+            public MobileIconGroup(String name, int[][] sbIcons, int[][] qsIcons, int[] contentDesc,
+                    int sbNullState, int qsNullState, int sbDiscState, int qsDiscState,
+                    int discContentDesc, int dataContentDesc, int dataType, boolean isWide,
+                    int[] qsDataType) {
+                super(name, sbIcons, qsIcons, contentDesc, sbNullState, qsNullState, sbDiscState,
+                        qsDiscState, discContentDesc);
+                mDataContentDescription = dataContentDesc;
+                mDataType = dataType;
+                mIsWide = isWide;
+                mQsDataType = qsDataType;
+            }
+        }
+
+        static class MobileState extends SignalController.State {
+            String networkName;
+            boolean noSim;
+            boolean dataConnected;
+            boolean isEmergency;
+            boolean airplaneMode;
+            int inetForNetwork;
+
+            @Override
+            public void copyFrom(State s) {
+                MobileState state = (MobileState) s;
+                noSim = state.noSim;
+                networkName = state.networkName;
+                dataConnected = state.dataConnected;
+                inetForNetwork = state.inetForNetwork;
+                isEmergency = state.isEmergency;
+                airplaneMode = state.airplaneMode;
+                super.copyFrom(s);
+            }
+
+            @Override
+            protected void toString(StringBuilder builder) {
+                builder.append("noSim=").append(noSim).append(',');
+                builder.append("networkName=").append(networkName).append(',');
+                builder.append("dataConnected=").append(dataConnected).append(',');
+                builder.append("inetForNetwork=").append(inetForNetwork).append(',');
+                builder.append("isEmergency=").append(isEmergency).append(',');
+                builder.append("airplaneMode=").append(airplaneMode).append(',');
+                super.toString(builder);
+            }
+
+            @Override
+            public boolean equals(Object o) {
+                return super.equals(o)
+                        && Objects.equals(((MobileState) o).networkName, networkName)
+                        && ((MobileState) o).noSim == noSim
+                        && ((MobileState) o).dataConnected == dataConnected
+                        && ((MobileState) o).isEmergency == isEmergency
+                        && ((MobileState) o).airplaneMode == airplaneMode
+                        && ((MobileState) o).inetForNetwork == inetForNetwork;
+            }
+        }
+    }
+
+    /**
+     * Common base class for handling signal for both wifi and mobile data.
+     */
+    static abstract class SignalController<T extends SignalController.State,
+            I extends SignalController.IconGroup> {
+        protected final String mTag;
+        protected final T mCurrentState;
+        protected final T mLastState;
+        protected final int mNetworkType;
+        protected final Context mContext;
+        // The owner of the SignalController (i.e. NetworkController will maintain the following
+        // lists and call notifyListeners whenever the list has changed to ensure everyone
+        // is aware of current state.
+        protected final List<NetworkSignalChangedCallback> mSignalsChangedCallbacks;
+        protected final List<SignalCluster> mSignalClusters;
+        protected final NetworkControllerImpl mNetworkController;
+
+        // Save the previous HISTORY_SIZE states for logging.
+        private final State[] mHistory;
+        // Where to copy the next state into.
+        private int mHistoryIndex;
+
+        public SignalController(String tag, Context context, int type,
+                List<NetworkSignalChangedCallback> signalCallbacks,
+                List<SignalCluster> signalClusters, NetworkControllerImpl networkController) {
+            mTag = TAG + "::" + tag;
+            mNetworkController = networkController;
+            mNetworkType = type;
+            mContext = context;
+            mSignalsChangedCallbacks = signalCallbacks;
+            mSignalClusters = signalClusters;
+            mCurrentState = cleanState();
+            mLastState = cleanState();
+            if (RECORD_HISTORY) {
+                mHistory = new State[HISTORY_SIZE];
+                for (int i = 0; i < HISTORY_SIZE; i++) {
+                    mHistory[i] = cleanState();
+                }
+            }
+        }
+
+        public T getState() {
+            return mCurrentState;
+        }
+
+        public int getNetworkType() {
+            return mNetworkType;
+        }
+
+        public void setInetCondition(int inetCondition) {
+            mCurrentState.inetCondition = inetCondition;
+            notifyListenersIfNecessary();
+        }
+
+        // @VisibleForDemoMode
+        /**
+         * Used at the end of demo mode to clear out any ugly state that it has created.
+         * Since we haven't had any callbacks, then isDirty will not have been triggered,
+         * so we can just take the last good state directly from there.
+         */
+        void resetLastState() {
+            mCurrentState.copyFrom(mLastState);
+        }
+
+        /**
+         * Determines if the state of this signal controller has changed and
+         * needs to trigger callbacks related to it.
+         */
+        public boolean isDirty() {
+            if (!mLastState.equals(mCurrentState)) {
+                if (DEBUG) {
+                    Log.d(mTag, "Change in state from: " + mLastState + "\n"
+                            + "\tto: " + mCurrentState);
+                }
+                return true;
+            }
+            return false;
+        }
+
+        public void saveLastState() {
+            if (RECORD_HISTORY) {
+                recordLast();
+            }
+            // Updates the current time.
+            mCurrentState.time = System.currentTimeMillis();
+            mLastState.copyFrom(mCurrentState);
+        }
+
+        /**
+         * Gets the signal icon for QS based on current state of connected, enabled, and level.
+         */
+        public int getQsCurrentIconId() {
+            if (mCurrentState.connected) {
+                return getIcons().mQsIcons[mCurrentState.inetCondition][mCurrentState.level];
+            } else if (mCurrentState.enabled) {
+                return getIcons().mQsDiscState;
+            } else {
+                return getIcons().mQsNullState;
+            }
+        }
+
+        /**
+         * Gets the signal icon for SB based on current state of connected, enabled, and level.
+         */
+        public int getCurrentIconId() {
+            if (mCurrentState.connected) {
+                return getIcons().mSbIcons[mCurrentState.inetCondition][mCurrentState.level];
+            } else if (mCurrentState.enabled) {
+                return getIcons().mSbDiscState;
+            } else {
+                return getIcons().mSbNullState;
+            }
+        }
+
+        /**
+         * Gets the content description for the signal based on current state of connected and
+         * level.
+         */
+        public int getContentDescription() {
+            if (mCurrentState.connected) {
+                return getIcons().mContentDesc[mCurrentState.level];
+            } else {
+                return getIcons().mDiscContentDesc;
+            }
+        }
+
+        protected void notifyListenersIfNecessary() {
+            if (isDirty()) {
+                saveLastState();
+                notifyListeners();
+                mNetworkController.refreshCarrierLabel();
+            }
+        }
+
+        /**
+         * Returns the resource if resId is not 0, and an empty string otherwise.
+         */
+        protected String getStringIfExists(int resId) {
+            return resId != 0 ? mContext.getString(resId) : "";
+        }
+
+        protected I getIcons() {
+            return (I) mCurrentState.iconGroup;
+        }
+
+        /**
+         * Saves the last state of any changes, so we can log the current
+         * and last value of any state data.
+         */
+        protected void recordLast() {
+            mHistory[mHistoryIndex++ & (HISTORY_SIZE - 1)].copyFrom(mLastState);
+        }
+
+        public void dump(PrintWriter pw) {
+            pw.println("  - " + mTag + " -----");
+            pw.println("  Current State: " + mCurrentState);
+            if (RECORD_HISTORY) {
+                // Count up the states that actually contain time stamps, and only display those.
+                int size = 0;
+                for (int i = 0; i < HISTORY_SIZE; i++) {
+                    if (mHistory[i].time != 0) size++;
+                }
+                // Print out the previous states in ordered number.
+                for (int i = mHistoryIndex + HISTORY_SIZE - 1;
+                        i >= mHistoryIndex + HISTORY_SIZE - size; i--) {
+                    pw.println("  Previous State(" + (mHistoryIndex + HISTORY_SIZE - i) + ": "
+                            + mHistory[i & (HISTORY_SIZE - 1)]);
+                }
+            }
+        }
+
+        /**
+         * Trigger callbacks based on current state.  The callbacks should be completely
+         * based on current state, and only need to be called in the scenario where
+         * mCurrentState != mLastState.
+         */
+        public abstract void notifyListeners();
+
+        /**
+         * Generate a blank T.
+         */
+        public abstract T cleanState();
+
+        /*
+         * Holds icons for a given state. Arrays are generally indexed as inet
+         * state (full connectivity or not) first, and second dimension as
+         * signal strength.
+         */
+        static class IconGroup {
+            final int[][] mSbIcons;
+            final int[][] mQsIcons;
+            final int[] mContentDesc;
+            final int mSbNullState;
+            final int mQsNullState;
+            final int mSbDiscState;
+            final int mQsDiscState;
+            final int mDiscContentDesc;
+            // For logging.
+            final String mName;
+
+            public IconGroup(String name, int[][] sbIcons, int[][] qsIcons, int[] contentDesc,
+                    int sbNullState, int qsNullState, int sbDiscState, int qsDiscState,
+                    int discContentDesc) {
+                mName = name;
+                mSbIcons = sbIcons;
+                mQsIcons = qsIcons;
+                mContentDesc = contentDesc;
+                mSbNullState = sbNullState;
+                mQsNullState = qsNullState;
+                mSbDiscState = sbDiscState;
+                mQsDiscState = qsDiscState;
+                mDiscContentDesc = discContentDesc;
+            }
+
+            @Override
+            public String toString() {
+                return "IconGroup(" + mName + ")";
+            }
+        }
+
+        static class State {
+            boolean connected;
+            boolean enabled;
+            boolean activityIn;
+            boolean activityOut;
+            int level;
+            IconGroup iconGroup;
+            int inetCondition;
+            int rssi; // Only for logging.
+
+            // Not used for comparison, just used for logging.
+            long time;
+
+            public void copyFrom(State state) {
+                connected = state.connected;
+                enabled = state.enabled;
+                level = state.level;
+                iconGroup = state.iconGroup;
+                inetCondition = state.inetCondition;
+                activityIn = state.activityIn;
+                activityOut = state.activityOut;
+                rssi = state.rssi;
+                time = state.time;
+            }
+
+            @Override
+            public String toString() {
+                if (time != 0) {
+                    StringBuilder builder = new StringBuilder();
+                    toString(builder);
+                    return builder.toString();
+                } else {
+                    return "Empty " + getClass().getSimpleName();
+                }
+            }
+
+            protected void toString(StringBuilder builder) {
+                builder.append("connected=").append(connected).append(',')
+                        .append("enabled=").append(enabled).append(',')
+                        .append("level=").append(level).append(',')
+                        .append("inetCondition=").append(inetCondition).append(',')
+                        .append("iconGroup=").append(iconGroup).append(',')
+                        .append("activityIn=").append(activityIn).append(',')
+                        .append("activityOut=").append(activityOut).append(',')
+                        .append("rssi=").append(rssi).append(',')
+                        .append("lastModified=").append(DateFormat.format("MM-dd hh:mm:ss", time));
+            }
+
+            @Override
+            public boolean equals(Object o) {
+                if (!o.getClass().equals(getClass())) {
+                    return false;
+                }
+                State other = (State) o;
+                return other.connected == connected
+                        && other.enabled == enabled
+                        && other.level == level
+                        && other.inetCondition == inetCondition
+                        && other.iconGroup == iconGroup
+                        && other.activityIn == activityIn
+                        && other.activityOut == activityOut
+                        && other.rssi == rssi;
+            }
+        }
+    }
+
+    public interface SignalCluster {
+        void setWifiIndicators(boolean visible, int strengthIcon, String contentDescription);
+
+        void setMobileDataIndicators(boolean visible, int strengthIcon, int typeIcon,
+                String contentDescription, String typeContentDescription, boolean isTypeIconWide);
+
+        void setIsAirplaneMode(boolean is, int airplaneIcon, int contentDescription);
+    }
+
+    public interface EmergencyListener {
+        void setEmergencyCallsOnly(boolean emergencyOnly);
+    }
+
+    public interface CarrierLabelListener {
+        void setCarrierLabel(String label);
+    }
+
+    @VisibleForTesting
+    static class Config {
+        boolean showAtLeastThreeGees = false;
+        boolean alwaysShowCdmaRssi = false;
+        boolean show4gForLte = false;
+        boolean hspaDataDistinguishable;
+
+        static Config readConfig(Context context) {
+            Config config = new Config();
+            Resources res = context.getResources();
+
+            config.showAtLeastThreeGees = res.getBoolean(R.bool.config_showMin3G);
+            config.alwaysShowCdmaRssi =
+                    res.getBoolean(com.android.internal.R.bool.config_alwaysUseCdmaRssi);
+            config.show4gForLte = res.getBoolean(R.bool.config_show4GForLTE);
+            config.hspaDataDistinguishable =
+                    res.getBoolean(R.bool.config_hspa_data_distinguishable);
+            return config;
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
index 1f2b918..4091619 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
@@ -17,11 +17,16 @@
 package com.android.systemui.statusbar.policy;
 
 import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.NetworkControllerImpl.MobileSignalController.MobileIconGroup;
 
 class TelephonyIcons {
     //***** Signal strength icons
 
+    static final int TELEPHONY_NUM_LEVELS = 5;
+
     //GSM/UMTS
+    static final int TELEPHONY_NO_NETWORK = R.drawable.stat_sys_signal_null;
+
     static final int[][] TELEPHONY_SIGNAL_STRENGTH = {
         { R.drawable.stat_sys_signal_0,
           R.drawable.stat_sys_signal_1,
@@ -35,6 +40,8 @@
           R.drawable.stat_sys_signal_4_fully }
     };
 
+    static final int QS_TELEPHONY_NO_NETWORK = R.drawable.ic_qs_signal_no_signal;
+
     static final int[][] QS_TELEPHONY_SIGNAL_STRENGTH = {
         { R.drawable.ic_qs_signal_0,
           R.drawable.ic_qs_signal_1,
@@ -66,8 +73,6 @@
         R.drawable.ic_qs_signal_r
     };
 
-    static final int[][] DATA_SIGNAL_STRENGTH = TELEPHONY_SIGNAL_STRENGTH;
-
     //***** Data connection icons
 
     //GSM/UMTS
@@ -191,6 +196,9 @@
     static final int FLIGHT_MODE_ICON = R.drawable.stat_sys_airplane_mode;
     static final int ROAMING_ICON = R.drawable.stat_sys_data_fully_connected_roam;
     static final int ICON_LTE = R.drawable.stat_sys_data_fully_connected_lte;
+    static final int ICON_G = R.drawable.stat_sys_data_fully_connected_g;
+    static final int ICON_E = R.drawable.stat_sys_data_fully_connected_e;
+    static final int ICON_H = R.drawable.stat_sys_data_fully_connected_h;
     static final int ICON_3G = R.drawable.stat_sys_data_fully_connected_3g;
     static final int ICON_4G = R.drawable.stat_sys_data_fully_connected_4g;
     static final int ICON_1X = R.drawable.stat_sys_data_fully_connected_1x;
@@ -199,5 +207,137 @@
     static final int QS_ICON_3G = R.drawable.ic_qs_signal_3g;
     static final int QS_ICON_4G = R.drawable.ic_qs_signal_4g;
     static final int QS_ICON_1X = R.drawable.ic_qs_signal_1x;
+
+    static final MobileIconGroup THREE_G = new MobileIconGroup(
+            "3G",
+            TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH,
+            TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
+            0, 0,
+            TelephonyIcons.TELEPHONY_NO_NETWORK,
+            TelephonyIcons.QS_TELEPHONY_NO_NETWORK,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
+            R.string.accessibility_data_connection_3g,
+            TelephonyIcons.ICON_3G,
+            true,
+            TelephonyIcons.QS_DATA_3G
+            );
+
+    static final MobileIconGroup UNKNOWN = new MobileIconGroup(
+            "Unknown",
+            TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH,
+            TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
+            0, 0,
+            TelephonyIcons.TELEPHONY_NO_NETWORK,
+            TelephonyIcons.QS_TELEPHONY_NO_NETWORK,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
+            0, 0, false, new int[2]
+            );
+
+    static final MobileIconGroup E = new MobileIconGroup(
+            "E",
+            TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH,
+            TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
+            0, 0,
+            TelephonyIcons.TELEPHONY_NO_NETWORK,
+            TelephonyIcons.QS_TELEPHONY_NO_NETWORK,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
+            R.string.accessibility_data_connection_edge,
+            TelephonyIcons.ICON_E,
+            false,
+            TelephonyIcons.QS_DATA_E
+            );
+
+    static final MobileIconGroup ONE_X = new MobileIconGroup(
+            "1X",
+            TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH,
+            TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
+            0, 0,
+            TelephonyIcons.TELEPHONY_NO_NETWORK,
+            TelephonyIcons.QS_TELEPHONY_NO_NETWORK,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
+            R.string.accessibility_data_connection_cdma,
+            TelephonyIcons.ICON_1X,
+            true,
+            TelephonyIcons.QS_DATA_1X
+            );
+
+    static final MobileIconGroup G = new MobileIconGroup(
+            "G",
+            TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH,
+            TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
+            0, 0,
+            TelephonyIcons.TELEPHONY_NO_NETWORK,
+            TelephonyIcons.QS_TELEPHONY_NO_NETWORK,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
+            R.string.accessibility_data_connection_gprs,
+            TelephonyIcons.ICON_G,
+            false,
+            TelephonyIcons.QS_DATA_G
+            );
+
+    static final MobileIconGroup H = new MobileIconGroup(
+            "H",
+            TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH,
+            TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
+            0, 0,
+            TelephonyIcons.TELEPHONY_NO_NETWORK,
+            TelephonyIcons.QS_TELEPHONY_NO_NETWORK,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
+            R.string.accessibility_data_connection_3_5g,
+            TelephonyIcons.ICON_H,
+            false,
+            TelephonyIcons.QS_DATA_H
+            );
+
+    static final MobileIconGroup FOUR_G = new MobileIconGroup(
+            "4G",
+            TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH,
+            TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
+            0, 0,
+            TelephonyIcons.TELEPHONY_NO_NETWORK,
+            TelephonyIcons.QS_TELEPHONY_NO_NETWORK,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
+            R.string.accessibility_data_connection_4g,
+            TelephonyIcons.ICON_4G,
+            true,
+            TelephonyIcons.QS_DATA_4G
+            );
+
+    static final MobileIconGroup LTE = new MobileIconGroup(
+            "LTE",
+            TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH,
+            TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
+            0, 0,
+            TelephonyIcons.TELEPHONY_NO_NETWORK,
+            TelephonyIcons.QS_TELEPHONY_NO_NETWORK,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
+            R.string.accessibility_data_connection_lte,
+            TelephonyIcons.ICON_LTE,
+            true,
+            TelephonyIcons.QS_DATA_LTE
+            );
+
+    static final MobileIconGroup ROAMING = new MobileIconGroup(
+            "Roaming",
+            TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING,
+            TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
+            0, 0,
+            TelephonyIcons.TELEPHONY_NO_NETWORK,
+            TelephonyIcons.QS_TELEPHONY_NO_NETWORK,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
+            R.string.accessibility_data_connection_roaming,
+            TelephonyIcons.ROAMING_ICON,
+            false,
+            TelephonyIcons.QS_DATA_R
+            );
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java
index 49af979..c56646f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java
@@ -45,5 +45,8 @@
               R.drawable.ic_qs_wifi_full_4 }
         };
 
+    static final int QS_WIFI_NO_NETWORK = R.drawable.ic_qs_wifi_no_network;
+    static final int WIFI_NO_NETWORK = R.drawable.stat_sys_wifi_signal_null;
+
     static final int WIFI_LEVEL_COUNT = WIFI_SIGNAL_STRENGTH[0].length;
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WimaxIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WimaxIcons.java
deleted file mode 100644
index 4877828..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WimaxIcons.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.policy;
-
-import com.android.systemui.statusbar.policy.TelephonyIcons;
-
-class WimaxIcons {
-    static final int[][] WIMAX_SIGNAL_STRENGTH = TelephonyIcons.DATA_SIGNAL_STRENGTH;
-
-    static final int WIMAX_DISCONNECTED = WIMAX_SIGNAL_STRENGTH[0][0];
-
-    static final int WIMAX_IDLE = WIMAX_DISCONNECTED; // XXX: unclear if we need a different icon
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
index 3c93b19..3d4cda6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
@@ -33,6 +33,7 @@
     boolean animateHideSensitive;
     boolean hasDelays;
     boolean hasGoToFullShadeEvent;
+    boolean hasDarkEvent;
 
     public AnimationFilter animateAlpha() {
         animateAlpha = true;
@@ -98,6 +99,10 @@
                     NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_GO_TO_FULL_SHADE) {
                 hasGoToFullShadeEvent = true;
             }
+            if (events.get(i).animationType ==
+                    NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_DARK) {
+                hasDarkEvent = true;
+            }
         }
     }
 
@@ -126,5 +131,6 @@
         animateHideSensitive = false;
         hasDelays = false;
         hasGoToFullShadeEvent = false;
+        hasDarkEvent = false;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index e63be97..c5f1161 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -2455,7 +2455,8 @@
 
                 // ANIMATION_TYPE_DARK
                 new AnimationFilter()
-                        .animateDark(),
+                        .animateDark()
+                        .hasDelays(),
 
                 // ANIMATION_TYPE_GO_TO_FULL_SHADE
                 new AnimationFilter()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
index 4611370..0b1ce8f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -154,7 +154,7 @@
                 child.setDimmed(state.dimmed, false /* animate */);
 
                 // apply dark
-                child.setDark(state.dark, false /* animate */);
+                child.setDark(state.dark, false /* animate */, 0 /* delay */);
 
                 // apply hiding sensitive
                 child.setHideSensitive(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index a56440c..05077bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -46,6 +46,7 @@
     public static final int ANIMATION_DELAY_PER_ELEMENT_INTERRUPTING = 80;
     public static final int ANIMATION_DELAY_PER_ELEMENT_MANUAL = 32;
     public static final int ANIMATION_DELAY_PER_ELEMENT_GO_TO_FULL_SHADE = 48;
+    public static final int ANIMATION_DELAY_PER_ELEMENT_DARK = 24;
     private static final int DELAY_EFFECT_MAX_INDEX_DIFFERENCE = 2;
 
     private static final int TAG_ANIMATOR_TRANSLATION_Y = R.id.translation_y_animator_tag;
@@ -161,11 +162,12 @@
         boolean scaleChanging = child.getScaleX() != viewState.scale;
         boolean alphaChanging = alpha != child.getAlpha();
         boolean heightChanging = viewState.height != child.getActualHeight();
+        boolean darkChanging = viewState.dark != child.isDark();
         boolean topInsetChanging = viewState.clipTopAmount != child.getClipTopAmount();
         boolean wasAdded = mNewAddChildren.contains(child);
         boolean hasDelays = mAnimationFilter.hasDelays;
         boolean isDelayRelevant = yTranslationChanging || zTranslationChanging || scaleChanging ||
-                alphaChanging || heightChanging || topInsetChanging;
+                alphaChanging || heightChanging || topInsetChanging || darkChanging;
         boolean noAnimation = wasAdded;
         long delay = 0;
         long duration = mCurrentLength;
@@ -242,7 +244,7 @@
                 && !noAnimation);
 
         // start dark animation
-        child.setDark(viewState.dark, mAnimationFilter.animateDark && !noAnimation);
+        child.setDark(viewState.dark, mAnimationFilter.animateDark && !noAnimation, delay);
 
         // apply speed bump state
         child.setBelowSpeedBump(viewState.belowSpeedBump);
@@ -262,6 +264,9 @@
 
     private long calculateChildAnimationDelay(StackScrollState.ViewState viewState,
             StackScrollState finalState) {
+        if (mAnimationFilter.hasDarkEvent) {
+            return calculateDelayDark(viewState);
+        }
         if (mAnimationFilter.hasGoToFullShadeEvent) {
             return calculateDelayGoToFullShade(viewState);
         }
@@ -309,6 +314,10 @@
         return minDelay;
     }
 
+    private long calculateDelayDark(StackScrollState.ViewState viewState) {
+        return viewState.notGoneIndex * ANIMATION_DELAY_PER_ELEMENT_DARK;
+    }
+
     private long calculateDelayGoToFullShade(StackScrollState.ViewState viewState) {
         float index = viewState.notGoneIndex;
         index = (float) Math.pow(index, 0.7f);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
index f12053c..351911c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
@@ -793,7 +793,7 @@
             sc.icon.setAlpha(mDisabledAlpha);
             sc.icon.setClickable(false);
         } else if (fixedVolume ||
-                (sc.streamType != mAudioManager.getMasterStreamType() && muted) ||
+                (sc.streamType != mAudioManager.getMasterStreamType() && !isRinger && muted) ||
                 (sSafetyWarning != null)) {
             sc.seekbarView.setEnabled(false);
         } else {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 10cffc4..49fe1e3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -17,6 +17,7 @@
 
 import com.android.internal.telephony.cdma.EriInfo;
 import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
+import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config;
 import com.android.systemui.statusbar.policy.NetworkControllerImpl.SignalCluster;
 
 import org.mockito.ArgumentCaptor;
@@ -44,6 +45,7 @@
     protected ConnectivityManager mMockCm;
     protected WifiManager mMockWm;
     protected TelephonyManager mMockTm;
+    protected Config mConfig;
 
     @Override
     protected void setUp() throws Exception {
@@ -59,16 +61,19 @@
 
         mSignalStrength = mock(SignalStrength.class);
         mServiceState = mock(ServiceState.class);
-        mSignalCluster = mock(SignalCluster.class);
-        mNetworkSignalChangedCallback = mock(NetworkSignalChangedCallback.class);
 
+        mConfig = new Config();
+        mConfig.hspaDataDistinguishable = true;
         mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm,
-                mock(AccessPointController.class), mock(MobileDataController.class));
+                mConfig, mock(AccessPointControllerImpl.class),
+                mock(MobileDataControllerImpl.class));
         setupNetworkController();
     }
 
     protected void setupNetworkController() {
-        mPhoneStateListener = mNetworkController.mPhoneStateListener;
+        mPhoneStateListener = mNetworkController.mMobileSignalController.mPhoneStateListener;
+        mSignalCluster = mock(SignalCluster.class);
+        mNetworkSignalChangedCallback = mock(NetworkSignalChangedCallback.class);
         mNetworkController.addSignalCluster(mSignalCluster);
         mNetworkController.addNetworkSignalChangedCallback(mNetworkSignalChangedCallback);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
index af05309..bb2ff7c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
@@ -18,7 +18,8 @@
         Mockito.when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false);
         // Create a new NetworkController as this is currently handled in constructor.
         mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm,
-                mock(AccessPointController.class), mock(MobileDataController.class));
+                mConfig, mock(AccessPointControllerImpl.class),
+                mock(MobileDataControllerImpl.class));
         setupNetworkController();
 
         verifyLastMobileDataIndicators(false, 0, 0);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
index 4ffdff2..7f0a8f4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
@@ -6,8 +6,6 @@
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 
-import com.android.systemui.R;
-
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mockito;
 
@@ -16,14 +14,10 @@
     private static final int MIN_RSSI = -100;
     private static final int MAX_RSSI = -55;
 
-    // TODO: Move this into WifiIcons, remove all R.drawable from NetworkControllerImpl.
-    private static final int NULL_SIGNAL = R.drawable.stat_sys_wifi_signal_null;
-    private static final int QS_NO_NET = R.drawable.ic_qs_wifi_no_network;
-
     public void testWifiIcon() {
         String testSsid = "Test SSID";
         setWifiEnabled(true);
-        verifyLastWifiIcon(false, NULL_SIGNAL);
+        verifyLastWifiIcon(false, WifiIcons.WIFI_NO_NETWORK);
 
         setWifiState(true, testSsid);
         verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[0][0]);
@@ -42,10 +36,10 @@
         String testSsid = "Test SSID";
 
         setWifiEnabled(false);
-        verifyLastQsWifiIcon(false, false, 0, null);
+        verifyLastQsWifiIcon(false, false, WifiIcons.QS_WIFI_NO_NETWORK, null);
 
         setWifiEnabled(true);
-        verifyLastQsWifiIcon(true, false, QS_NO_NET, null);
+        verifyLastQsWifiIcon(true, false, WifiIcons.QS_WIFI_NO_NETWORK, null);
 
         setWifiState(true, testSsid);
         for (int testLevel = 0; testLevel < WifiIcons.WIFI_LEVEL_COUNT; testLevel++) {
@@ -118,8 +112,7 @@
 
     protected void setWifiActivity(int activity) {
         // TODO: Not this, because this variable probably isn't sticking around.
-        mNetworkController.mWifiActivity = activity;
-        mNetworkController.refreshViews();
+        mNetworkController.mWifiSignalController.setActivity(activity);
     }
 
     protected void setWifiLevel(int level) {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index c34316b..30a271e 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -101,6 +101,7 @@
 import android.view.accessibility.AccessibilityManager;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.PopupWindow;
@@ -2153,6 +2154,7 @@
     }
 
     private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {
+
         /* package */int mDefaultOpacity = PixelFormat.OPAQUE;
 
         /** The feature ID of the panel, or -1 if this is the application's DecorView */
@@ -2182,19 +2184,45 @@
         // View added at runtime to draw under the navigation bar area
         private View mNavigationGuard;
 
-        private View mStatusColorView;
-        private View mNavigationColorView;
+        private final ColorViewState mStatusColorViewState = new ColorViewState(
+                SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS,
+                Gravity.TOP,
+                STATUS_BAR_BACKGROUND_TRANSITION_NAME,
+                com.android.internal.R.id.statusBarBackground,
+                FLAG_FULLSCREEN);
+        private final ColorViewState mNavigationColorViewState = new ColorViewState(
+                SYSTEM_UI_FLAG_HIDE_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION,
+                Gravity.BOTTOM,
+                NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME,
+                com.android.internal.R.id.navigationBarBackground,
+                0 /* hideWindowFlag */);
+
+        private final Interpolator mShowInterpolator;
+        private final Interpolator mHideInterpolator;
+        private final int mBarEnterExitDuration;
+
         private final BackgroundFallback mBackgroundFallback = new BackgroundFallback();
 
         private int mLastTopInset = 0;
         private int mLastBottomInset = 0;
         private int mLastRightInset = 0;
+        private boolean mLastHasTopStableInset = false;
+        private boolean mLastHasBottomStableInset = false;
+        private int mLastWindowFlags = 0;
 
         private int mRootScrollY = 0;
 
         public DecorView(Context context, int featureId) {
             super(context);
             mFeatureId = featureId;
+
+            mShowInterpolator = AnimationUtils.loadInterpolator(context,
+                    android.R.interpolator.linear_out_slow_in);
+            mHideInterpolator = AnimationUtils.loadInterpolator(context,
+                    android.R.interpolator.fast_out_linear_in);
+
+            mBarEnterExitDuration = context.getResources().getInteger(
+                    R.integer.dock_enter_exit_duration);
         }
 
         public void setBackgroundFallback(int resId) {
@@ -2787,13 +2815,13 @@
 
         @Override
         public void onWindowSystemUiVisibilityChanged(int visible) {
-            updateColorViews(null /* insets */);
+            updateColorViews(null /* insets */, true /* animate */);
         }
 
         @Override
         public WindowInsets onApplyWindowInsets(WindowInsets insets) {
             mFrameOffsets.set(insets.getSystemWindowInsets());
-            insets = updateColorViews(insets);
+            insets = updateColorViews(insets, true /* animate */);
             insets = updateStatusGuard(insets);
             updateNavigationGuard(insets);
             if (getForeground() != null) {
@@ -2807,11 +2835,16 @@
             return false;
         }
 
-        private WindowInsets updateColorViews(WindowInsets insets) {
+        private WindowInsets updateColorViews(WindowInsets insets, boolean animate) {
             WindowManager.LayoutParams attrs = getAttributes();
             int sysUiVisibility = attrs.systemUiVisibility | getWindowSystemUiVisibility();
 
             if (!mIsFloating && ActivityManager.isHighEndGfx()) {
+                boolean disallowAnimate = !isLaidOut();
+                disallowAnimate |= ((mLastWindowFlags ^ attrs.flags)
+                        & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
+                mLastWindowFlags = attrs.flags;
+
                 if (insets != null) {
                     mLastTopInset = Math.min(insets.getStableInsetTop(),
                             insets.getSystemWindowInsetTop());
@@ -2819,19 +2852,23 @@
                             insets.getSystemWindowInsetBottom());
                     mLastRightInset = Math.min(insets.getStableInsetRight(),
                             insets.getSystemWindowInsetRight());
+
+                    // Don't animate if the presence of stable insets has changed, because that
+                    // indicates that the window was either just added and received them for the
+                    // first time, or the window size or position has changed.
+                    boolean hasTopStableInset = insets.getStableInsetTop() != 0;
+                    disallowAnimate |= hasTopStableInset && !mLastHasTopStableInset;
+                    mLastHasTopStableInset = hasTopStableInset;
+
+                    boolean hasBottomStableInset = insets.getStableInsetBottom() != 0;
+                    disallowAnimate |= hasBottomStableInset && !mLastHasBottomStableInset;
+                    mLastHasBottomStableInset = hasBottomStableInset;
                 }
-                mStatusColorView = updateColorViewInt(mStatusColorView, sysUiVisibility,
-                        SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS,
-                        mStatusBarColor, mLastTopInset, Gravity.TOP,
-                        STATUS_BAR_BACKGROUND_TRANSITION_NAME,
-                        com.android.internal.R.id.statusBarBackground,
-                        (getAttributes().flags & FLAG_FULLSCREEN) != 0);
-                mNavigationColorView = updateColorViewInt(mNavigationColorView, sysUiVisibility,
-                        SYSTEM_UI_FLAG_HIDE_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION,
-                        mNavigationBarColor, mLastBottomInset, Gravity.BOTTOM,
-                        NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME,
-                        com.android.internal.R.id.navigationBarBackground,
-                        false /* hiddenByWindowFlag */);
+
+                updateColorViewInt(mStatusColorViewState, sysUiVisibility, mStatusBarColor,
+                        mLastTopInset, animate && !disallowAnimate);
+                updateColorViewInt(mNavigationColorViewState, sysUiVisibility, mNavigationBarColor,
+                        mLastBottomInset, animate && !disallowAnimate);
             }
 
             // When we expand the window with FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, we still need
@@ -2875,28 +2912,35 @@
             return insets;
         }
 
-        private View updateColorViewInt(View view, int sysUiVis, int systemUiHideFlag,
-                int translucentFlag, int color, int height, int verticalGravity,
-                String transitionName, int id, boolean hiddenByWindowFlag) {
-            boolean show = height > 0 && (sysUiVis & systemUiHideFlag) == 0
-                    && !hiddenByWindowFlag
-                    && (getAttributes().flags & translucentFlag) == 0
+        private void updateColorViewInt(final ColorViewState state, int sysUiVis, int color,
+                int height, boolean animate) {
+            boolean show = height > 0 && (sysUiVis & state.systemUiHideFlag) == 0
+                    && (getAttributes().flags & state.hideWindowFlag) == 0
+                    && (getAttributes().flags & state.translucentFlag) == 0
                     && (color & Color.BLACK) != 0
                     && (getAttributes().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
 
+            boolean visibilityChanged = false;
+            View view = state.view;
+
             if (view == null) {
                 if (show) {
-                    view = new View(mContext);
+                    state.view = view = new View(mContext);
                     view.setBackgroundColor(color);
-                    view.setTransitionName(transitionName);
-                    view.setId(id);
+                    view.setTransitionName(state.transitionName);
+                    view.setId(state.id);
+                    visibilityChanged = true;
+                    view.setVisibility(INVISIBLE);
+                    state.targetVisibility = VISIBLE;
+
                     addView(view, new LayoutParams(LayoutParams.MATCH_PARENT, height,
-                            Gravity.START | verticalGravity));
+                            Gravity.START | state.verticalGravity));
                     updateColorViewTranslations();
                 }
             } else {
                 int vis = show ? VISIBLE : INVISIBLE;
-                view.setVisibility(vis);
+                visibilityChanged = state.targetVisibility != vis;
+                state.targetVisibility = vis;
                 if (show) {
                     LayoutParams lp = (LayoutParams) view.getLayoutParams();
                     if (lp.height != height) {
@@ -2906,18 +2950,43 @@
                     view.setBackgroundColor(color);
                 }
             }
-            return view;
+            if (visibilityChanged) {
+                view.animate().cancel();
+                if (animate) {
+                    if (show) {
+                        if (view.getVisibility() != VISIBLE) {
+                            view.setVisibility(VISIBLE);
+                            view.setAlpha(0.0f);
+                        }
+                        view.animate().alpha(1.0f).setInterpolator(mShowInterpolator).
+                                setDuration(mBarEnterExitDuration);
+                    } else {
+                        view.animate().alpha(0.0f).setInterpolator(mHideInterpolator)
+                                .setDuration(mBarEnterExitDuration)
+                                .withEndAction(new Runnable() {
+                                    @Override
+                                    public void run() {
+                                        state.view.setAlpha(1.0f);
+                                        state.view.setVisibility(INVISIBLE);
+                                    }
+                                });
+                    }
+                } else {
+                    view.setAlpha(1.0f);
+                    view.setVisibility(show ? VISIBLE : INVISIBLE);
+                }
+            }
         }
 
         private void updateColorViewTranslations() {
             // Put the color views back in place when they get moved off the screen
             // due to the the ViewRootImpl panning.
             int rootScrollY = mRootScrollY;
-            if (mStatusColorView != null) {
-                mStatusColorView.setTranslationY(rootScrollY > 0 ? rootScrollY : 0);
+            if (mStatusColorViewState.view != null) {
+                mStatusColorViewState.view.setTranslationY(rootScrollY > 0 ? rootScrollY : 0);
             }
-            if (mNavigationColorView != null) {
-                mNavigationColorView.setTranslationY(rootScrollY < 0 ? rootScrollY : 0);
+            if (mNavigationColorViewState.view != null) {
+                mNavigationColorViewState.view.setTranslationY(rootScrollY < 0 ? rootScrollY : 0);
             }
         }
 
@@ -2948,7 +3017,7 @@
                                 mStatusGuard = new View(mContext);
                                 mStatusGuard.setBackgroundColor(mContext.getResources()
                                         .getColor(R.color.input_method_navigation_guard));
-                                addView(mStatusGuard, indexOfChild(mStatusColorView),
+                                addView(mStatusGuard, indexOfChild(mStatusColorViewState.view),
                                         new LayoutParams(LayoutParams.MATCH_PARENT,
                                                 mlp.topMargin, Gravity.START | Gravity.TOP));
                             } else {
@@ -3008,9 +3077,10 @@
                     mNavigationGuard = new View(mContext);
                     mNavigationGuard.setBackgroundColor(mContext.getResources()
                             .getColor(R.color.input_method_navigation_guard));
-                    addView(mNavigationGuard, indexOfChild(mNavigationColorView), new LayoutParams(
-                            LayoutParams.MATCH_PARENT, insets.getSystemWindowInsetBottom(),
-                            Gravity.START | Gravity.BOTTOM));
+                    addView(mNavigationGuard, indexOfChild(mNavigationColorViewState.view),
+                            new LayoutParams(LayoutParams.MATCH_PARENT,
+                                    insets.getSystemWindowInsetBottom(),
+                                    Gravity.START | Gravity.BOTTOM));
                 } else {
                     LayoutParams lp = (LayoutParams) mNavigationGuard.getLayoutParams();
                     lp.height = insets.getSystemWindowInsetBottom();
@@ -3912,7 +3982,7 @@
     protected void dispatchWindowAttributesChanged(WindowManager.LayoutParams attrs) {
         super.dispatchWindowAttributesChanged(attrs);
         if (mDecor != null) {
-            mDecor.updateColorViews(null /* insets */);
+            mDecor.updateColorViews(null /* insets */, true /* animate */);
         }
     }
 
@@ -4639,6 +4709,29 @@
         }
     }
 
+    private static class ColorViewState {
+        View view = null;
+        int targetVisibility = View.INVISIBLE;
+
+        final int id;
+        final int systemUiHideFlag;
+        final int translucentFlag;
+        final int verticalGravity;
+        final String transitionName;
+        final int hideWindowFlag;
+
+        ColorViewState(int systemUiHideFlag,
+                int translucentFlag, int verticalGravity,
+                String transitionName, int id, int hideWindowFlag) {
+            this.id = id;
+            this.systemUiHideFlag = systemUiHideFlag;
+            this.translucentFlag = translucentFlag;
+            this.verticalGravity = verticalGravity;
+            this.transitionName = transitionName;
+            this.hideWindowFlag = hideWindowFlag;
+        }
+    }
+
     void sendCloseSystemWindows() {
         PhoneWindowManager.sendCloseSystemWindows(getContext(), null);
     }
@@ -4657,7 +4750,7 @@
         mStatusBarColor = color;
         mForcedStatusBarColor = true;
         if (mDecor != null) {
-            mDecor.updateColorViews(null);
+            mDecor.updateColorViews(null, false /* animate */);
         }
     }
 
@@ -4671,7 +4764,7 @@
         mNavigationBarColor = color;
         mForcedNavigationBarColor = true;
         if (mDecor != null) {
-            mDecor.updateColorViews(null);
+            mDecor.updateColorViews(null, false /* animate */);
         }
     }
 }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 1ac956a..dea9932 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -319,6 +319,7 @@
     // handler thread.  We'll need to resolve this someday by teaching the input dispatcher
     // to hold wakelocks during dispatch and eliminating the critical path.
     volatile boolean mPowerKeyHandled;
+    volatile boolean mBeganFromNonInteractive;
     volatile int mPowerKeyPressCounter;
     volatile boolean mEndCallKeyHandled;
 
@@ -882,15 +883,13 @@
                             ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
                 }
             } else {
-                // When non-interactive, we ordinarily wake up immediately and
-                // consume the key.  However on some devices we need to support multi-press
-                // without waking so we will delay handling for later in that case
-                // (at the cost of increased latency).
+                wakeUpFromPowerKey(event.getDownTime());
                 final int maxCount = getMaxMultiPressPowerCount();
+
                 if (maxCount <= 1) {
-                    // No other actions.  We can wake immediately.
-                    wakeUpFromPowerKey(event.getDownTime());
                     mPowerKeyHandled = true;
+                } else {
+                    mBeganFromNonInteractive = true;
                 }
             }
         }
@@ -927,6 +926,7 @@
     }
 
     private void finishPowerKeyPress() {
+        mBeganFromNonInteractive = false;
         mPowerKeyPressCounter = 0;
         if (mPowerKeyWakeLock.isHeld()) {
             mPowerKeyWakeLock.release();
@@ -951,9 +951,7 @@
             powerMultiPressAction(eventTime, interactive, mDoublePressOnPowerBehavior);
         } else if (count == 3) {
             powerMultiPressAction(eventTime, interactive, mTriplePressOnPowerBehavior);
-        } else if (!interactive) {
-            wakeUpFromPowerKey(eventTime);
-        } else {
+        } else if (interactive && !mBeganFromNonInteractive) {
             switch (mShortPressOnPowerBehavior) {
                 case SHORT_PRESS_POWER_NOTHING:
                     break;
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 8b524dd..08c47dc 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -75,6 +75,12 @@
     // warning message.  The time duration is in milliseconds.
     private static final long LATE_ALARM_THRESHOLD = 10 * 1000;
 
+    // Minimum futurity of a new alarm
+    private static final long MIN_FUTURITY = 5 * 1000;  // 5 seconds, in millis
+
+    // Minimum alarm recurrence interval
+    private static final long MIN_INTERVAL = 60 * 1000;  // one minute, in millis
+
     private static final int RTC_WAKEUP_MASK = 1 << RTC_WAKEUP;
     private static final int RTC_MASK = 1 << RTC;
     private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << ELAPSED_REALTIME_WAKEUP;
@@ -696,6 +702,15 @@
             windowLength = AlarmManager.INTERVAL_HOUR;
         }
 
+        // Sanity check the recurrence interval.  This will catch people who supply
+        // seconds when the API expects milliseconds.
+        if (interval > 0 && interval < MIN_INTERVAL) {
+            Slog.w(TAG, "Suspiciously short interval " + interval
+                    + " millis; expanding to " + (int)(MIN_INTERVAL/1000)
+                    + " seconds");
+            interval = MIN_INTERVAL;
+        }
+
         if (type < RTC_WAKEUP || type > ELAPSED_REALTIME) {
             throw new IllegalArgumentException("Invalid alarm type " + type);
         }
@@ -709,7 +724,11 @@
         }
 
         final long nowElapsed = SystemClock.elapsedRealtime();
-        final long triggerElapsed = convertToElapsed(triggerAtTime, type);
+        final long nominalTrigger = convertToElapsed(triggerAtTime, type);
+        // Try to prevent spamming by making sure we aren't firing alarms in the immediate future
+        final long minTrigger = nowElapsed + MIN_FUTURITY;
+        final long triggerElapsed = (nominalTrigger > minTrigger) ? nominalTrigger : minTrigger;
+
         final long maxElapsed;
         if (windowLength == AlarmManager.WINDOW_EXACT) {
             maxElapsed = triggerElapsed;
diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java
index de90aa2..17edb53 100644
--- a/services/core/java/com/android/server/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/PersistentDataBlockService.java
@@ -41,6 +41,9 @@
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.channels.FileChannel;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
 
 /**
  * Service for reading and writing blocks to a persistent partition.
@@ -63,22 +66,16 @@
     private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
     private static final int HEADER_SIZE = 8;
     // Magic number to mark block device as adhering to the format consumed by this service
-    private static final int PARTITION_TYPE_MARKER = 0x1990;
+    private static final int PARTITION_TYPE_MARKER = 0x19901873;
     // Limit to 100k as blocks larger than this might cause strain on Binder.
-    // TODO(anmorales): Consider splitting up too-large blocks in PersistentDataBlockManager
     private static final int MAX_DATA_BLOCK_SIZE = 1024 * 100;
+    public static final int DIGEST_SIZE_BYTES = 32;
 
     private final Context mContext;
     private final String mDataBlockFile;
     private final Object mLock = new Object();
 
     private int mAllowedUid = -1;
-    /*
-     * Separate lock for OEM unlock related operations as they can happen in parallel with regular
-     * block operations.
-     */
-    private final Object mOemLock = new Object();
-
     private long mBlockDeviceSize;
 
     public PersistentDataBlockService(Context context) {
@@ -89,7 +86,6 @@
         mAllowedUid = getAllowedUid(UserHandle.USER_OWNER);
     }
 
-
     private int getAllowedUid(int userHandle) {
         String allowedPackage = mContext.getResources()
                 .getString(R.string.config_persistentDataPackageName);
@@ -106,6 +102,7 @@
 
     @Override
     public void onStart() {
+        enforceChecksumValidity();
         publishBinderService(Context.PERSISTENT_DATA_BLOCK_SERVICE, mService);
     }
 
@@ -128,6 +125,9 @@
     }
 
     private int getTotalDataSizeLocked(DataInputStream inputStream) throws IOException {
+        // skip over checksum
+        inputStream.skipBytes(DIGEST_SIZE_BYTES);
+
         int totalDataSize;
         int blockId = inputStream.readInt();
         if (blockId == PARTITION_TYPE_MARKER) {
@@ -148,6 +148,143 @@
         return mBlockDeviceSize;
     }
 
+    private boolean enforceChecksumValidity() {
+        byte[] storedDigest = new byte[DIGEST_SIZE_BYTES];
+
+        synchronized (mLock) {
+            byte[] digest = computeDigestLocked(storedDigest);
+            if (digest == null || !Arrays.equals(storedDigest, digest)) {
+                Slog.i(TAG, "Formatting FRP partition...");
+                formatPartitionLocked();
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    private boolean computeAndWriteDigestLocked() {
+        byte[] digest = computeDigestLocked(null);
+        if (digest != null) {
+            DataOutputStream outputStream;
+            try {
+                outputStream = new DataOutputStream(
+                        new FileOutputStream(new File(mDataBlockFile)));
+            } catch (FileNotFoundException e) {
+                Slog.e(TAG, "partition not available?", e);
+                return false;
+            }
+
+            try {
+                outputStream.write(digest, 0, DIGEST_SIZE_BYTES);
+                outputStream.flush();
+            } catch (IOException e) {
+                Slog.e(TAG, "failed to write block checksum", e);
+                return false;
+            } finally {
+                IoUtils.closeQuietly(outputStream);
+            }
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    private byte[] computeDigestLocked(byte[] storedDigest) {
+        DataInputStream inputStream;
+        try {
+            inputStream = new DataInputStream(new FileInputStream(new File(mDataBlockFile)));
+        } catch (FileNotFoundException e) {
+            Slog.e(TAG, "partition not available?", e);
+            return null;
+        }
+
+        MessageDigest md;
+        try {
+            md = MessageDigest.getInstance("SHA-256");
+        } catch (NoSuchAlgorithmException e) {
+            // won't ever happen -- every implementation is required to support SHA-256
+            Slog.e(TAG, "SHA-256 not supported?", e);
+            IoUtils.closeQuietly(inputStream);
+            return null;
+        }
+
+        try {
+            if (storedDigest != null && storedDigest.length == DIGEST_SIZE_BYTES) {
+                inputStream.read(storedDigest);
+            } else {
+                inputStream.skipBytes(DIGEST_SIZE_BYTES);
+            }
+
+            int read;
+            byte[] data = new byte[1024];
+            md.update(data, 0, DIGEST_SIZE_BYTES); // include 0 checksum in digest
+            while ((read = inputStream.read(data)) != -1) {
+                md.update(data, 0, read);
+            }
+        } catch (IOException e) {
+            Slog.e(TAG, "failed to read partition", e);
+            return null;
+        } finally {
+            IoUtils.closeQuietly(inputStream);
+        }
+
+        return md.digest();
+    }
+
+    private void formatPartitionLocked() {
+        DataOutputStream outputStream;
+        try {
+            outputStream = new DataOutputStream(new FileOutputStream(new File(mDataBlockFile)));
+        } catch (FileNotFoundException e) {
+            Slog.e(TAG, "partition not available?", e);
+            return;
+        }
+
+        byte[] data = new byte[DIGEST_SIZE_BYTES];
+        try {
+            outputStream.write(data, 0, DIGEST_SIZE_BYTES);
+            outputStream.writeInt(PARTITION_TYPE_MARKER);
+            outputStream.writeInt(0); // data size
+            outputStream.flush();
+        } catch (IOException e) {
+            Slog.e(TAG, "failed to format block", e);
+            return;
+        } finally {
+            IoUtils.closeQuietly(outputStream);
+        }
+
+        doSetOemUnlockEnabledLocked(false);
+        computeAndWriteDigestLocked();
+    }
+
+    private void doSetOemUnlockEnabledLocked(boolean enabled) {
+        FileOutputStream outputStream;
+        try {
+            outputStream = new FileOutputStream(new File(mDataBlockFile));
+        } catch (FileNotFoundException e) {
+            Slog.e(TAG, "partition not available", e);
+            return;
+        }
+
+        try {
+            FileChannel channel = outputStream.getChannel();
+
+            channel.position(getBlockDeviceSize() - 1);
+
+            ByteBuffer data = ByteBuffer.allocate(1);
+            data.put(enabled ? (byte) 1 : (byte) 0);
+            data.flip();
+            channel.write(data);
+            outputStream.flush();
+        } catch (IOException e) {
+            Slog.e(TAG, "unable to access persistent partition", e);
+            return;
+        } finally {
+            IoUtils.closeQuietly(outputStream);
+        }
+    }
+
     private native long nativeGetBlockDeviceSize(String path);
     private native int nativeWipe(String path);
 
@@ -176,19 +313,23 @@
             headerAndData.putInt(data.length);
             headerAndData.put(data);
 
-            try {
-                synchronized (mLock) {
-                    outputStream.write(headerAndData.array());
-                    return data.length;
-                }
-            } catch (IOException e) {
-                Slog.e(TAG, "failed writing to the persistent data block", e);
-                return -1;
-            } finally {
+            synchronized (mLock) {
                 try {
-                    outputStream.close();
+                    byte[] checksum = new byte[DIGEST_SIZE_BYTES];
+                    outputStream.write(checksum, 0, DIGEST_SIZE_BYTES);
+                    outputStream.write(headerAndData.array());
+                    outputStream.flush();
                 } catch (IOException e) {
-                    Slog.e(TAG, "failed closing output stream", e);
+                    Slog.e(TAG, "failed writing to the persistent data block", e);
+                    return -1;
+                } finally {
+                    IoUtils.closeQuietly(outputStream);
+                }
+
+                if (computeAndWriteDigestLocked()) {
+                    return data.length;
+                } else {
+                    return -1;
                 }
             }
         }
@@ -196,6 +337,9 @@
         @Override
         public byte[] read() {
             enforceUid(Binder.getCallingUid());
+            if (!enforceChecksumValidity()) {
+                return new byte[0];
+            }
 
             DataInputStream inputStream;
             try {
@@ -256,30 +400,10 @@
             }
             enforceOemUnlockPermission();
             enforceIsOwner();
-            FileOutputStream outputStream;
-            try {
-                outputStream = new FileOutputStream(new File(mDataBlockFile));
-            } catch (FileNotFoundException e) {
-                Slog.e(TAG, "parition not available", e);
-                return;
-            }
 
-            try {
-                FileChannel channel = outputStream.getChannel();
-
-                channel.position(getBlockDeviceSize() - 1);
-
-                ByteBuffer data = ByteBuffer.allocate(1);
-                data.put(enabled ? (byte) 1 : (byte) 0);
-                data.flip();
-
-                synchronized (mOemLock) {
-                    channel.write(data);
-                }
-            } catch (IOException e) {
-                Slog.e(TAG, "unable to access persistent partition", e);
-            } finally {
-                IoUtils.closeQuietly(outputStream);
+            synchronized (mLock) {
+                doSetOemUnlockEnabledLocked(enabled);
+                computeAndWriteDigestLocked();
             }
         }
 
@@ -295,8 +419,8 @@
             }
 
             try {
-                inputStream.skip(getBlockDeviceSize() - 1);
-                synchronized (mOemLock) {
+                synchronized (mLock) {
+                    inputStream.skip(getBlockDeviceSize() - 1);
                     return inputStream.readByte() != 0;
                 }
             } catch (IOException e) {
@@ -336,6 +460,5 @@
             long actualSize = getBlockDeviceSize() - HEADER_SIZE - 1;
             return actualSize <= MAX_DATA_BLOCK_SIZE ? actualSize : MAX_DATA_BLOCK_SIZE;
         }
-
     };
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 772192a..f0fb9e6 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -795,7 +795,11 @@
 
         @Override
         public int hashCode() {
-            return toString().hashCode();
+            int hashCode = 1;
+            hashCode = 31 * hashCode + sourceUserId;
+            hashCode = 31 * hashCode + uri.hashCode();
+            hashCode = 31 * hashCode + (prefix ? 1231 : 1237);
+            return hashCode;
         }
 
         @Override
@@ -834,10 +838,12 @@
      * indirect content-provider access.
      */
     private class Identity {
-        public int pid;
-        public int uid;
+        public final IBinder token;
+        public final int pid;
+        public final int uid;
 
-        Identity(int _pid, int _uid) {
+        Identity(IBinder _token, int _pid, int _uid) {
+            token = _token;
             pid = _pid;
             uid = _uid;
         }
@@ -2271,15 +2277,19 @@
      * process when the bindApplication() IPC is sent to the process. They're
      * lazily setup to make sure the services are running when they're asked for.
      */
-    private HashMap<String, IBinder> getCommonServicesLocked() {
+    private HashMap<String, IBinder> getCommonServicesLocked(boolean isolated) {
         if (mAppBindArgs == null) {
-            mAppBindArgs = new HashMap<String, IBinder>();
+            mAppBindArgs = new HashMap<>();
 
-            // Setup the application init args
-            mAppBindArgs.put("package", ServiceManager.getService("package"));
-            mAppBindArgs.put("window", ServiceManager.getService("window"));
-            mAppBindArgs.put(Context.ALARM_SERVICE,
-                    ServiceManager.getService(Context.ALARM_SERVICE));
+            // Isolated processes won't get this optimization, so that we don't
+            // violate the rules about which services they have access to.
+            if (!isolated) {
+                // Setup the application init args
+                mAppBindArgs.put("package", ServiceManager.getService("package"));
+                mAppBindArgs.put("window", ServiceManager.getService("window"));
+                mAppBindArgs.put(Context.ALARM_SERVICE,
+                        ServiceManager.getService(Context.ALARM_SERVICE));
+            }
         }
         return mAppBindArgs;
     }
@@ -5902,7 +5912,8 @@
                     profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
                     app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
                     isRestrictedBackupMode || !normalMode, app.persistent,
-                    new Configuration(mConfiguration), app.compat, getCommonServicesLocked(),
+                    new Configuration(mConfiguration), app.compat,
+                    getCommonServicesLocked(app.isolated),
                     mCoreSettingsObserver.getCoreSettingsLocked());
             updateLruProcessLocked(app, false, null);
             app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
@@ -6256,7 +6267,7 @@
             synchronized (this) {
                 ActivityStack stack = ActivityRecord.getStackLocked(token);
                 if (stack != null) {
-                    stack.backgroundResourcesReleased(token);
+                    stack.backgroundResourcesReleased();
                 }
             }
         } finally {
@@ -6722,21 +6733,9 @@
      */
     int checkComponentPermission(String permission, int pid, int uid,
             int owningUid, boolean exported) {
-        // We might be performing an operation on behalf of an indirect binder
-        // invocation, e.g. via {@link #openContentUri}.  Check and adjust the
-        // client identity accordingly before proceeding.
-        Identity tlsIdentity = sCallerIdentity.get();
-        if (tlsIdentity != null) {
-            Slog.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
-                    + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
-            uid = tlsIdentity.uid;
-            pid = tlsIdentity.pid;
-        }
-
         if (pid == MY_PID) {
             return PackageManager.PERMISSION_GRANTED;
         }
-
         return ActivityManager.checkComponentPermission(permission, uid,
                 owningUid, exported);
     }
@@ -6758,6 +6757,26 @@
         return checkComponentPermission(permission, pid, UserHandle.getAppId(uid), -1, true);
     }
 
+    @Override
+    public int checkPermissionWithToken(String permission, int pid, int uid, IBinder callerToken) {
+        if (permission == null) {
+            return PackageManager.PERMISSION_DENIED;
+        }
+
+        // We might be performing an operation on behalf of an indirect binder
+        // invocation, e.g. via {@link #openContentUri}.  Check and adjust the
+        // client identity accordingly before proceeding.
+        Identity tlsIdentity = sCallerIdentity.get();
+        if (tlsIdentity != null && tlsIdentity.token == callerToken) {
+            Slog.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
+                    + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
+            uid = tlsIdentity.uid;
+            pid = tlsIdentity.pid;
+        }
+
+        return checkComponentPermission(permission, pid, UserHandle.getAppId(uid), -1, true);
+    }
+
     /**
      * Binder IPC calls go through the public entry point.
      * This can be called with or without the global lock held.
@@ -6963,13 +6982,13 @@
      */
     @Override
     public int checkUriPermission(Uri uri, int pid, int uid,
-            final int modeFlags, int userId) {
+            final int modeFlags, int userId, IBinder callerToken) {
         enforceNotIsolatedCaller("checkUriPermission");
 
         // Another redirected-binder-call permissions check as in
-        // {@link checkComponentPermission}.
+        // {@link checkPermissionWithToken}.
         Identity tlsIdentity = sCallerIdentity.get();
-        if (tlsIdentity != null) {
+        if (tlsIdentity != null && tlsIdentity.token == callerToken) {
             uid = tlsIdentity.uid;
             pid = tlsIdentity.pid;
         }
@@ -9876,10 +9895,11 @@
             // we do the check against the caller's permissions even though it looks
             // to the content provider like the Activity Manager itself is making
             // the request.
+            Binder token = new Binder();
             sCallerIdentity.set(new Identity(
-                    Binder.getCallingPid(), Binder.getCallingUid()));
+                    token, Binder.getCallingPid(), Binder.getCallingUid()));
             try {
-                pfd = cph.provider.openFile(null, uri, "r", null);
+                pfd = cph.provider.openFile(null, uri, "r", null, token);
             } catch (FileNotFoundException e) {
                 // do nothing; pfd will be returned null
             } finally {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 3a1fafe..c8b7205 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -3317,17 +3317,18 @@
                 mHandler.sendEmptyMessageDelayed(RELEASE_BACKGROUND_RESOURCES_TIMEOUT_MSG, 500);
             } else {
                 Slog.e(TAG, "releaseBackgroundResources: activity " + r + " no longer running");
-                backgroundResourcesReleased(r.appToken);
+                backgroundResourcesReleased();
             }
         }
     }
 
-    final void backgroundResourcesReleased(IBinder token) {
+    final void backgroundResourcesReleased() {
         mHandler.removeMessages(RELEASE_BACKGROUND_RESOURCES_TIMEOUT_MSG);
         final ActivityRecord r = getVisibleBehindActivity();
         if (r != null) {
             mStackSupervisor.mStoppingActivities.add(r);
             setVisibleBehindActivity(null);
+            mStackSupervisor.scheduleIdleTimeoutLocked(null);
         }
         mStackSupervisor.resumeTopActivitiesLocked();
     }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 0cdb4d5..ec38124 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -798,7 +798,7 @@
     }
 
     boolean isSystemAudioActivated() {
-        if (getAvrDeviceInfo() == null) {
+        if (!hasSystemAudioDevice()) {
             return false;
         }
         synchronized (mLock) {
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 921b68b..9440697 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -90,6 +90,7 @@
     private final SessionStub mSession;
     private final SessionCb mSessionCb;
     private final MediaSessionService mService;
+    private final boolean mUseMasterVolume;
 
     private final Object mLock = new Object();
     private final ArrayList<ISessionControllerCallback> mControllerCallbacks =
@@ -139,6 +140,8 @@
         mAudioManager = (AudioManager) service.getContext().getSystemService(Context.AUDIO_SERVICE);
         mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);
         mAudioAttrs = new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build();
+        mUseMasterVolume = service.getContext().getResources().getBoolean(
+                com.android.internal.R.bool.config_useMasterVolume);
     }
 
     /**
@@ -248,6 +251,12 @@
             direction = -1;
         }
         if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
+            if (mUseMasterVolume) {
+                // If this device only uses master volume and playback is local
+                // just adjust the master volume and return.
+                mAudioManagerInternal.adjustMasterVolumeForUid(direction, flags, packageName, uid);
+                return;
+            }
             int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs);
             if (useSuggested) {
                 if (AudioSystem.isStreamActive(stream, 0)) {
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index ba18f48..98a3970 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -86,6 +86,7 @@
     private final Object mLock = new Object();
     private final MessageHandler mHandler = new MessageHandler();
     private final PowerManager.WakeLock mMediaEventWakeLock;
+    private final boolean mUseMasterVolume;
 
     private KeyguardManager mKeyguardManager;
     private IAudioService mAudioService;
@@ -104,6 +105,8 @@
         mPriorityStack = new MediaSessionStack();
         PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent");
+        mUseMasterVolume = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_useMasterVolume);
     }
 
     @Override
@@ -819,8 +822,13 @@
                     return;
                 }
                 try {
-                    mAudioService.adjustSuggestedStreamVolume(direction, suggestedStream, flags,
-                            getContext().getOpPackageName());
+                    if (mUseMasterVolume) {
+                        mAudioService.adjustMasterVolume(direction, flags,
+                                getContext().getOpPackageName());
+                    } else {
+                        mAudioService.adjustSuggestedStreamVolume(direction, suggestedStream, flags,
+                                getContext().getOpPackageName());
+                    }
                 } catch (RemoteException e) {
                     Log.e(TAG, "Error adjusting default volume.", e);
                 }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 42a8551..6958ff8 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1931,12 +1931,7 @@
             if (hasValidSound) {
                 boolean looping =
                         (notification.flags & Notification.FLAG_INSISTENT) != 0;
-                AudioAttributes audioAttributes;
-                if (notification.audioAttributes != null) {
-                    audioAttributes = notification.audioAttributes;
-                } else {
-                    audioAttributes = Notification.AUDIO_ATTRIBUTES_DEFAULT;
-                }
+                AudioAttributes audioAttributes = audioAttributesForNotification(notification);
                 mSoundNotification = record;
                 // do not play notifications if stream volume is 0 (typically because
                 // ringer mode is silent) or if there is a user of exclusive audio focus
@@ -2030,7 +2025,9 @@
     }
 
     private static AudioAttributes audioAttributesForNotification(Notification n) {
-        if (n.audioAttributes != null) {
+        if (n.audioAttributes != null
+                && !Notification.AUDIO_ATTRIBUTES_DEFAULT.equals(n.audioAttributes)) {
+            // the audio attributes are set and different from the default, use them
             return n.audioAttributes;
         } else if (n.audioStreamType >= 0 && n.audioStreamType < AudioSystem.getNumStreamTypes()) {
             // the stream type is valid, use it
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index a9c8a61..c3cbbd3 100644
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -299,6 +299,13 @@
         return -1;
     }
 
+    private static boolean intArrayContains(int[] array, int value) {
+        for (int element : array) {
+            if (element == value) return true;
+        }
+        return false;
+    }
+
     public void addHdmiTvInput(int id, TvInputInfo info) {
         if (info.getType() != TvInputInfo.TYPE_HDMI) {
             throw new IllegalArgumentException("info (" + info + ") has non-HDMI type.");
@@ -762,20 +769,64 @@
             AudioPortConfig sinkConfig = mAudioSink.activeConfig();
             AudioPatch[] audioPatchArray = new AudioPatch[] { mAudioPatch };
             boolean shouldRecreateAudioPatch = sourceUpdated || sinkUpdated;
+
+            int sinkSamplingRate = mDesiredSamplingRate;
+            int sinkChannelMask = mDesiredChannelMask;
+            int sinkFormat = mDesiredFormat;
+            // If sinkConfig != null and values are set to default, fill in the sinkConfig values.
+            if (sinkConfig != null) {
+                if (sinkSamplingRate == 0) {
+                    sinkSamplingRate = sinkConfig.samplingRate();
+                }
+                if (sinkChannelMask == AudioFormat.CHANNEL_OUT_DEFAULT) {
+                    sinkChannelMask = sinkConfig.channelMask();
+                }
+                if (sinkFormat == AudioFormat.ENCODING_DEFAULT) {
+                    sinkChannelMask = sinkConfig.format();
+                }
+            }
+
             if (sinkConfig == null
-                    || (mDesiredSamplingRate != 0
-                            && sinkConfig.samplingRate() != mDesiredSamplingRate)
-                    || (mDesiredChannelMask != AudioFormat.CHANNEL_OUT_DEFAULT
-                            && sinkConfig.channelMask() != mDesiredChannelMask)
-                    || (mDesiredFormat != AudioFormat.ENCODING_DEFAULT
-                            && sinkConfig.format() != mDesiredFormat)) {
-                sinkConfig = mAudioSink.buildConfig(mDesiredSamplingRate, mDesiredChannelMask,
-                        mDesiredFormat, null);
+                    || sinkConfig.samplingRate() != sinkSamplingRate
+                    || sinkConfig.channelMask() != sinkChannelMask
+                    || sinkConfig.format() != sinkFormat) {
+                // Check for compatibility and reset to default if necessary.
+                if (!intArrayContains(mAudioSink.samplingRates(), sinkSamplingRate)
+                        && mAudioSink.samplingRates().length > 0) {
+                    sinkSamplingRate = mAudioSink.samplingRates()[0];
+                }
+                if (!intArrayContains(mAudioSink.channelMasks(), sinkChannelMask)) {
+                    sinkChannelMask = AudioFormat.CHANNEL_OUT_DEFAULT;
+                }
+                if (!intArrayContains(mAudioSink.formats(), sinkFormat)) {
+                    sinkFormat = AudioFormat.ENCODING_DEFAULT;
+                }
+                sinkConfig = mAudioSink.buildConfig(sinkSamplingRate, sinkChannelMask,
+                        sinkFormat, null);
                 shouldRecreateAudioPatch = true;
             }
             if (sourceConfig == null || sourceGainConfig != null) {
-                sourceConfig = mAudioSource.buildConfig(sinkConfig.samplingRate(),
-                        sinkConfig.channelMask(), sinkConfig.format(), sourceGainConfig);
+                int sourceSamplingRate = 0;
+                if (intArrayContains(mAudioSource.samplingRates(), sinkConfig.samplingRate())) {
+                    sourceSamplingRate = sinkConfig.samplingRate();
+                } else if (mAudioSource.samplingRates().length > 0) {
+                    // Use any sampling rate and hope audio patch can handle resampling...
+                    sourceSamplingRate = mAudioSource.samplingRates()[0];
+                }
+                int sourceChannelMask = AudioFormat.CHANNEL_IN_DEFAULT;
+                for (int inChannelMask : mAudioSource.channelMasks()) {
+                    if (AudioFormat.channelCountFromOutChannelMask(sinkConfig.channelMask())
+                            == AudioFormat.channelCountFromInChannelMask(inChannelMask)) {
+                        sourceChannelMask = inChannelMask;
+                        break;
+                    }
+                }
+                int sourceFormat = AudioFormat.ENCODING_DEFAULT;
+                if (intArrayContains(mAudioSource.formats(), sinkConfig.format())) {
+                    sourceFormat = sinkConfig.format();
+                }
+                sourceConfig = mAudioSource.buildConfig(sourceSamplingRate, sourceChannelMask,
+                        sourceFormat, sourceGainConfig);
                 shouldRecreateAudioPatch = true;
             }
             if (shouldRecreateAudioPatch) {
@@ -785,6 +836,9 @@
                         new AudioPortConfig[] { sourceConfig },
                         new AudioPortConfig[] { sinkConfig });
                 mAudioPatch = audioPatchArray[0];
+                if (sourceGainConfig != null) {
+                    mAudioManager.setAudioPortGain(mAudioSource, sourceGainConfig);
+                }
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 7e6da8b..0cbf03a 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -992,12 +992,6 @@
                         continue;
                     }
 
-                    // If the window is an accessibility overlay - ignore.
-                    if (windowState.mAttrs.type ==
-                            WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
-                        continue;
-                    }
-
                     // Compute the bounds in the screen.
                     final Rect boundsInScreen = mTempRect;
                     computeWindowBoundsInScreen(windowState, boundsInScreen);
@@ -1018,8 +1012,14 @@
                         }
                     }
 
-                    unaccountedSpace.op(boundsInScreen, unaccountedSpace,
-                            Region.Op.REVERSE_DIFFERENCE);
+                    // Account for the space this window takes if the window
+                    // is not an accessibility overlay which does not change
+                    // the reported windows.
+                    if (windowState.mAttrs.type !=
+                            WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
+                        unaccountedSpace.op(boundsInScreen, unaccountedSpace,
+                                Region.Op.REVERSE_DIFFERENCE);
+                    }
 
                     // We figured out what is touchable for the entire screen - done.
                     if (unaccountedSpace.isEmpty()) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 9e51849..3b0a511 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3923,7 +3923,7 @@
         final int n = policy.mAdminList.size();
         for (int i = 0; i < n; i++) {
             ActiveAdmin admin = policy.mAdminList.get(i);
-            if (profileOwner.equals(admin.info)) {
+            if (profileOwner.equals(admin.info.getComponent())) {
                 return admin;
             }
         }
@@ -5040,13 +5040,15 @@
 
     @Override
     public boolean isUninstallBlocked(ComponentName who, String packageName) {
+        // This function should return true if and only if the package is blocked by
+        // setUninstallBlocked(). It should still return false for other cases of blocks, such as
+        // when the package is a system app, or when it is an active device admin.
         final int userId = UserHandle.getCallingUserId();
 
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
+            if (who != null) {
+                getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             }
-            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             long id = Binder.clearCallingIdentity();
             try {
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index 215c682..6e404de 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -30,7 +30,7 @@
  * @hide
  */
 @SystemApi
-public abstract class Conference {
+public abstract class Conference implements IConferenceable {
 
     /** @hide */
     public abstract static class Listener {
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 63b44a6..fb63c85 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -47,7 +47,7 @@
  * @hide
  */
 @SystemApi
-public abstract class Connection {
+public abstract class Connection implements IConferenceable {
 
     public static final int STATE_INITIALIZING = 0;
 
@@ -82,8 +82,8 @@
                 Connection c, VideoProvider videoProvider) {}
         public void onAudioModeIsVoipChanged(Connection c, boolean isVoip) {}
         public void onStatusHintsChanged(Connection c, StatusHints statusHints) {}
-        public void onConferenceableConnectionsChanged(
-                Connection c, List<Connection> conferenceableConnections) {}
+        public void onConferenceablesChanged(
+                Connection c, List<IConferenceable> conferenceables) {}
         public void onConferenceChanged(Connection c, Conference conference) {}
         /** @hide */
         public void onConferenceParticipantsChanged(Connection c,
@@ -449,7 +449,16 @@
     private final Listener mConnectionDeathListener = new Listener() {
         @Override
         public void onDestroyed(Connection c) {
-            if (mConferenceableConnections.remove(c)) {
+            if (mConferenceables.remove(c)) {
+                fireOnConferenceableConnectionsChanged();
+            }
+        }
+    };
+
+    private final Conference.Listener mConferenceDeathListener = new Conference.Listener() {
+        @Override
+        public void onDestroyed(Conference c) {
+            if (mConferenceables.remove(c)) {
                 fireOnConferenceableConnectionsChanged();
             }
         }
@@ -462,9 +471,9 @@
      */
     private final Set<Listener> mListeners = Collections.newSetFromMap(
             new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1));
-    private final List<Connection> mConferenceableConnections = new ArrayList<>();
-    private final List<Connection> mUnmodifiableConferenceableConnections =
-            Collections.unmodifiableList(mConferenceableConnections);
+    private final List<IConferenceable> mConferenceables = new ArrayList<>();
+    private final List<IConferenceable> mUnmodifiableConferenceables =
+            Collections.unmodifiableList(mConferenceables);
 
     private int mState = STATE_NEW;
     private AudioState mAudioState;
@@ -864,19 +873,44 @@
         for (Connection c : conferenceableConnections) {
             // If statement checks for duplicates in input. It makes it N^2 but we're dealing with a
             // small amount of items here.
-            if (!mConferenceableConnections.contains(c)) {
+            if (!mConferenceables.contains(c)) {
                 c.addConnectionListener(mConnectionDeathListener);
-                mConferenceableConnections.add(c);
+                mConferenceables.add(c);
             }
         }
         fireOnConferenceableConnectionsChanged();
     }
 
     /**
-     * Returns the connections with which this connection can be conferenced.
+     * Similar to {@link #setConferenceableConnections(java.util.List)}, sets a list of connections
+     * or conferences with which this connection can be conferenced.
+     *
+     * @param conferenceables The conferenceables.
      */
-    public final List<Connection> getConferenceableConnections() {
-        return mUnmodifiableConferenceableConnections;
+    public final void setConferenceables(List<IConferenceable> conferenceables) {
+        clearConferenceableList();
+        for (IConferenceable c : conferenceables) {
+            // If statement checks for duplicates in input. It makes it N^2 but we're dealing with a
+            // small amount of items here.
+            if (!mConferenceables.contains(c)) {
+                if (c instanceof Connection) {
+                    Connection connection = (Connection) c;
+                    connection.addConnectionListener(mConnectionDeathListener);
+                } else if (c instanceof Conference) {
+                    Conference conference = (Conference) c;
+                    conference.addListener(mConferenceDeathListener);
+                }
+                mConferenceables.add(c);
+            }
+        }
+        fireOnConferenceableConnectionsChanged();
+    }
+
+    /**
+     * Returns the connections or conferences with which this connection can be conferenced.
+     */
+    public final List<IConferenceable> getConferenceables() {
+        return mUnmodifiableConferenceables;
     }
 
     /*
@@ -1109,7 +1143,7 @@
 
     private final void  fireOnConferenceableConnectionsChanged() {
         for (Listener l : mListeners) {
-            l.onConferenceableConnectionsChanged(this, getConferenceableConnections());
+            l.onConferenceablesChanged(this, getConferenceables());
         }
     }
 
@@ -1120,10 +1154,16 @@
     }
 
     private final void clearConferenceableList() {
-        for (Connection c : mConferenceableConnections) {
-            c.removeConnectionListener(mConnectionDeathListener);
+        for (IConferenceable c : mConferenceables) {
+            if (c instanceof Connection) {
+                Connection connection = (Connection) c;
+                connection.removeConnectionListener(mConnectionDeathListener);
+            } else if (c instanceof Conference) {
+                Conference conference = (Conference) c;
+                conference.removeListener(mConferenceDeathListener);
+            }
         }
-        mConferenceableConnections.clear();
+        mConferenceables.clear();
     }
 
     /**
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 48e6ff3..08f3853 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -515,11 +515,11 @@
         }
 
         @Override
-        public void onConferenceableConnectionsChanged(
-                Connection connection, List<Connection> conferenceableConnections) {
+        public void onConferenceablesChanged(
+                Connection connection, List<IConferenceable> conferenceables) {
             mAdapter.setConferenceableConnections(
                     mIdByConnection.get(connection),
-                    createConnectionIdList(conferenceableConnections));
+                    createIdList(conferenceables));
         }
 
         @Override
@@ -602,7 +602,7 @@
                         connection.getAudioModeIsVoip(),
                         connection.getStatusHints(),
                         connection.getDisconnectCause(),
-                        createConnectionIdList(connection.getConferenceableConnections())));
+                        createIdList(connection.getConferenceables())));
     }
 
     private void abort(String callId) {
@@ -682,12 +682,19 @@
     private void conference(String callId1, String callId2) {
         Log.d(this, "conference %s, %s", callId1, callId2);
 
+        // Attempt to get second connection or conference.
         Connection connection2 = findConnectionForAction(callId2, "conference");
+        Conference conference2 = getNullConference();
         if (connection2 == getNullConnection()) {
-            Log.w(this, "Connection2 missing in conference request %s.", callId2);
-            return;
+            conference2 = findConferenceForAction(callId2, "conference");
+            if (conference2 == getNullConference()) {
+                Log.w(this, "Connection2 or Conference2 missing in conference request %s.",
+                        callId2);
+                return;
+            }
         }
 
+        // Attempt to get first connection or conference and perform merge.
         Connection connection1 = findConnectionForAction(callId1, "conference");
         if (connection1 == getNullConnection()) {
             Conference conference1 = findConferenceForAction(callId1, "addConnection");
@@ -696,10 +703,26 @@
                         "Connection1 or Conference1 missing in conference request %s.",
                         callId1);
             } else {
-                conference1.onMerge(connection2);
+                // Call 1 is a conference.
+                if (connection2 != getNullConnection()) {
+                    // Call 2 is a connection so merge via call 1 (conference).
+                    conference1.onMerge(connection2);
+                } else {
+                    // Call 2 is ALSO a conference; this should never happen.
+                    Log.wtf(this, "There can only be one conference and an attempt was made to " +
+                            "merge two conferences.");
+                    return;
+                }
             }
         } else {
-            onConference(connection1, connection2);
+            // Call 1 is a connection.
+            if (conference2 != getNullConference()) {
+                // Call 2 is a conference, so merge via call 2.
+                conference2.onMerge(connection1);
+            } else {
+                // Call 2 is a connection, so merge together.
+                onConference(connection1, connection2);
+            }
         }
     }
 
@@ -1111,6 +1134,33 @@
         return ids;
     }
 
+    /**
+     * Builds a list of {@link Connection} and {@link Conference} IDs based on the list of
+     * {@link IConferenceable}s passed in.
+     *
+     * @param conferenceables The {@link IConferenceable} connections and conferences.
+     * @return List of string conference and call Ids.
+     */
+    private List<String> createIdList(List<IConferenceable> conferenceables) {
+        List<String> ids = new ArrayList<>();
+        for (IConferenceable c : conferenceables) {
+            // Only allow Connection and Conference conferenceables.
+            if (c instanceof Connection) {
+                Connection connection = (Connection) c;
+                if (mIdByConnection.containsKey(connection)) {
+                    ids.add(mIdByConnection.get(connection));
+                }
+            } else if (c instanceof Conference) {
+                Conference conference = (Conference) c;
+                if (mIdByConference.containsKey(conference)) {
+                    ids.add(mIdByConference.get(conference));
+                }
+            }
+        }
+        Collections.sort(ids);
+        return ids;
+    }
+
     private Conference getNullConference() {
         if (sNullConference == null) {
             sNullConference = new Conference(null) {};
diff --git a/telecomm/java/android/telecom/IConferenceable.java b/telecomm/java/android/telecom/IConferenceable.java
new file mode 100644
index 0000000..095d7cb
--- /dev/null
+++ b/telecomm/java/android/telecom/IConferenceable.java
@@ -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
+ */
+
+package android.telecom;
+
+import android.annotation.SystemApi;
+
+/**
+ * Interface used to identify entities with which another entity can participate in a conference
+ * call with.  The {@link ConnectionService} implementation will only recognize
+ * {@link IConferenceable}s which are {@link Connection}s or {@link Conference}s.
+ *
+ * @hide
+ */
+@SystemApi
+public interface IConferenceable {
+
+}
diff --git a/telecomm/java/android/telecom/PhoneCapabilities.java b/telecomm/java/android/telecom/PhoneCapabilities.java
index feb7a95..c21a6d1 100644
--- a/telecomm/java/android/telecom/PhoneCapabilities.java
+++ b/telecomm/java/android/telecom/PhoneCapabilities.java
@@ -101,6 +101,16 @@
      */
     public static final int DISCONNECT_FROM_CONFERENCE = 0x00002000;
 
+    /**
+     * Whether the call is a generic conference, where we do not know the precise state of
+     * participants in the conference (eg. on CDMA).
+     *
+     * TODO: Move to CallProperties.
+     *
+     * @hide
+     */
+    public static final int GENERIC_CONFERENCE = 0x00004000;
+
     public static final int ALL = HOLD | SUPPORT_HOLD | MERGE_CONFERENCE | SWAP_CONFERENCE
             | RESPOND_VIA_TEXT | MUTE | MANAGE_CONFERENCE | SEPARATE_FROM_CONFERENCE
             | DISCONNECT_FROM_CONFERENCE;
@@ -163,6 +173,10 @@
         if (can(capabilities, VoWIFI)) {
             builder.append(" VoWIFI");
         }
+        if (can(capabilities, GENERIC_CONFERENCE)) {
+            builder.append(" GENERIC_CONFERENCE");
+        }
+
         builder.append("]");
         return builder.toString();
     }
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index 1891976..674777e 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -165,6 +165,22 @@
      */
     public static final int IMS_MERGED_SUCCESSFULLY = 45;
 
+    /**
+     * Stk Call Control modified DIAL request to USSD request.
+     * {@hide}
+     */
+    public static final int DIAL_MODIFIED_TO_USSD          = 46;
+    /**
+     * Stk Call Control modified DIAL request to SS request.
+     * {@hide}
+     */
+    public static final int DIAL_MODIFIED_TO_SS            = 47;
+    /**
+     * Stk Call Control modified DIAL request to DIAL with modified data.
+     * {@hide}
+     */
+    public static final int DIAL_MODIFIED_TO_DIAL          = 48;
+
     //*********************************************************************************************
     // When adding a disconnect type:
     // 1) Please assign the new type the next id value below.
@@ -173,14 +189,14 @@
     // 4) Update toString() with the newly added disconnect type.
     // 5) Update android.telecom.DisconnectCauseUtil with any mappings to a telecom.DisconnectCause.
     //
-    // NextId: 46
+    // NextId: 49
     //*********************************************************************************************
 
     /** Smallest valid value for call disconnect codes. */
     public static final int MINIMUM_VALID_VALUE = NOT_DISCONNECTED;
 
     /** Largest valid value for call disconnect codes. */
-    public static final int MAXIMUM_VALID_VALUE = IMS_MERGED_SUCCESSFULLY;
+    public static final int MAXIMUM_VALID_VALUE = DIAL_MODIFIED_TO_DIAL;
 
     /** Private constructor to avoid class instantiation. */
     private DisconnectCause() {
@@ -272,6 +288,12 @@
             return "CDMA_CALL_LOST";
         case EXITED_ECM:
             return "EXITED_ECM";
+        case DIAL_MODIFIED_TO_USSD:
+            return "DIAL_MODIFIED_TO_USSD";
+        case DIAL_MODIFIED_TO_SS:
+            return "DIAL_MODIFIED_TO_SS";
+        case DIAL_MODIFIED_TO_DIAL:
+            return "DIAL_MODIFIED_TO_DIAL";
         case ERROR_UNSPECIFIED:
             return "ERROR_UNSPECIFIED";
         case OUTGOING_FAILURE:
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index f2d859f..7c03d42 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1797,10 +1797,9 @@
      * for display purpose only, for example, displayed in Phone Status. It won't
      * change the actual MSISDN/MDN. To unset alphatag or number, pass in a null
      * value.
-     * <p>
-     * Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     *
+     * <p>Requires that the calling app has carrier privileges.
+     * @see #hasCarrierPrivileges
      *
      * @param alphaTag alpha-tagging of the dailing nubmer
      * @param number The dialing number
@@ -1814,10 +1813,9 @@
      * for display purpose only, for example, displayed in Phone Status. It won't
      * change the actual MSISDN/MDN. To unset alphatag or number, pass in a null
      * value.
-     * <p>
-     * Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     *
+     * <p>Requires that the calling app has carrier privileges.
+     * @see #hasCarrierPrivileges
      *
      * @param subId the subscriber that the alphatag and dialing number belongs to.
      * @param alphaTag alpha-tagging of the dailing nubmer
@@ -1974,10 +1972,9 @@
 
     /**
      * Sets the voice mail number.
-     * <p>
-     * Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     *
+     * <p>Requires that the calling app has carrier privileges.
+     * @see #hasCarrierPrivileges
      *
      * @param alphaTag The alpha tag to display.
      * @param number The voicemail number.
@@ -1988,10 +1985,9 @@
 
     /**
      * Sets the voicemail number for the given subscriber.
-     * <p>
-     * Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     *
+     * <p>Requires that the calling app has carrier privileges.
+     * @see #hasCarrierPrivileges
      *
      * @param subId The subscriber id.
      * @param alphaTag The alpha tag to display.
@@ -3072,9 +3068,8 @@
      * Set the preferred network type to global mode which includes LTE, CDMA, EvDo and GSM/WCDMA.
      *
      * <p>
-     * Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     * Requires that the calling app has carrier privileges.
+     * @see #hasCarrierPrivileges
      *
      * @return true on success; false on any failure.
      */
@@ -3085,9 +3080,13 @@
     /**
      * Values used to return status for hasCarrierPrivileges call.
      */
+    /** @hide */
     public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1;
+    /** @hide */
     public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0;
+    /** @hide */
     public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1;
+    /** @hide */
     public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2;
 
     /**
@@ -3099,21 +3098,18 @@
      *
      * TODO: Add a link to documentation.
      *
-     * @return CARRIER_PRIVILEGE_STATUS_HAS_ACCESS if the app has carrier privileges.
-     *         CARRIER_PRIVILEGE_STATUS_NO_ACCESS if the app does not have carrier privileges.
-     *         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).
+     * @return true if the app has carrier privileges.
      */
-    public int hasCarrierPrivileges() {
+    public boolean hasCarrierPrivileges() {
         try {
-            return getITelephony().hasCarrierPrivileges();
+            return getITelephony().getCarrierPrivilegeStatus() ==
+                CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
         } catch (RemoteException ex) {
             Rlog.e(TAG, "hasCarrierPrivileges RemoteException", ex);
         } catch (NullPointerException ex) {
             Rlog.e(TAG, "hasCarrierPrivileges NPE", ex);
         }
-        return CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
+        return false;
     }
 
     /**
@@ -3124,9 +3120,8 @@
      * brand value input. To unset the value, the same function should be
      * called with a null brand value.
      *
-     * <p>Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     *  or has to be carrier app - see #hasCarrierPrivileges.
+     * <p>Requires that the calling app has carrier privileges.
+     * @see #hasCarrierPrivileges
      *
      * @param brand The brand name to display/set.
      * @return true if the operation was executed correctly.
@@ -3188,9 +3183,9 @@
         try {
             return getITelephony().checkCarrierPrivilegesForPackage(pkgname);
         } catch (RemoteException ex) {
-            Rlog.e(TAG, "hasCarrierPrivileges RemoteException", ex);
+            Rlog.e(TAG, "checkCarrierPrivilegesForPackage RemoteException", ex);
         } catch (NullPointerException ex) {
-            Rlog.e(TAG, "hasCarrierPrivileges NPE", ex);
+            Rlog.e(TAG, "checkCarrierPrivilegesForPackage NPE", ex);
         }
         return CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
     }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index cbfa9f6..adb3bc4 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -713,7 +713,7 @@
      *
      * @return carrier privilege status defined in TelephonyManager.
      */
-    int hasCarrierPrivileges();
+    int getCarrierPrivilegeStatus();
 
     /**
      * Similar to above, but check for pkg whose name is pkgname.
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index b5e82e3..082e8bb 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -24,6 +24,8 @@
  * Also they should all probably be static final.
  */
 
+import android.os.SystemProperties;
+
 /**
  * {@hide}
  */
@@ -57,7 +59,17 @@
                                                  retries needed */
     int MISSING_RESOURCE = 16;                /* no logical channel available */
     int NO_SUCH_ELEMENT = 17;                 /* application not found on SIM */
+    int DIAL_MODIFIED_TO_USSD = 18;           /* DIAL request modified to USSD */
+    int DIAL_MODIFIED_TO_SS = 19;             /* DIAL request modified to SS */
+    int DIAL_MODIFIED_TO_DIAL = 20;           /* DIAL request modified to DIAL with different data*/
+    int USSD_MODIFIED_TO_DIAL = 21;           /* USSD request modified to DIAL */
+    int USSD_MODIFIED_TO_SS = 22;             /* USSD request modified to SS */
+    int USSD_MODIFIED_TO_USSD = 23;           /* USSD request modified to different USSD request */
+    int SS_MODIFIED_TO_DIAL = 24;             /* SS request modified to DIAL */
+    int SS_MODIFIED_TO_USSD = 25;             /* SS request modified to USSD */
     int SUBSCRIPTION_NOT_SUPPORTED = 26;      /* Subscription not supported */
+    int SS_MODIFIED_TO_SS = 27;               /* SS request modified to different SS request */
+
 
     /* NETWORK_MODE_* See ril.h RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE */
     int NETWORK_MODE_WCDMA_PREF     = 0; /* GSM/WCDMA (WCDMA preferred) */
@@ -76,7 +88,8 @@
     int NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA = 10; /* LTE, CDMA, EvDo, GSM/WCDMA */
     int NETWORK_MODE_LTE_ONLY       = 11; /* LTE Only mode. */
     int NETWORK_MODE_LTE_WCDMA      = 12; /* LTE/WCDMA */
-    int PREFERRED_NETWORK_MODE      = NETWORK_MODE_WCDMA_PREF;
+    int PREFERRED_NETWORK_MODE      = SystemProperties.getInt("ro.telephony.default_network",
+            NETWORK_MODE_WCDMA_PREF);
 
     int CDMA_CELL_BROADCAST_SMS_DISABLED = 1;
     int CDMA_CELL_BROADCAST_SMS_ENABLED  = 0;
@@ -339,4 +352,6 @@
     int RIL_UNSOL_HARDWARE_CONFIG_CHANGED = 1040;
     int RIL_UNSOL_DC_RT_INFO_CHANGED = 1041;
     int RIL_UNSOL_RADIO_CAPABILITY = 1042;
+    int RIL_UNSOL_ON_SS = 1043;
+    int RIL_UNSOL_STK_CC_ALPHA_NOTIFY = 1044;
 }
diff --git a/test-runner/src/android/test/mock/MockContentProvider.java b/test-runner/src/android/test/mock/MockContentProvider.java
index 28d52b0..5ef71df 100644
--- a/test-runner/src/android/test/mock/MockContentProvider.java
+++ b/test-runner/src/android/test/mock/MockContentProvider.java
@@ -91,8 +91,8 @@
 
         @Override
         public ParcelFileDescriptor openFile(
-                String callingPackage, Uri url, String mode, ICancellationSignal signal)
-                throws RemoteException, FileNotFoundException {
+                String callingPackage, Uri url, String mode, ICancellationSignal signal,
+                IBinder callerToken) throws RemoteException, FileNotFoundException {
             return MockContentProvider.this.openFile(url, mode);
         }
 
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index 46c81b6..3378872 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -37,6 +37,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Looper;
 import android.os.UserHandle;
 import android.view.DisplayAdjustments;
@@ -483,6 +484,12 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @hide */
+    @Override
+    public int checkPermission(String permission, int pid, int uid, IBinder callerToken) {
+        return checkPermission(permission, pid, uid);
+    }
+
     @Override
     public int checkCallingPermission(String permission) {
         throw new UnsupportedOperationException();
@@ -524,6 +531,12 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @hide */
+    @Override
+    public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags, IBinder callerToken) {
+        return checkUriPermission(uri, pid, uid, modeFlags);
+    }
+
     @Override
     public int checkCallingUriPermission(Uri uri, int modeFlags) {
         throw new UnsupportedOperationException();
diff --git a/test-runner/src/android/test/mock/MockIContentProvider.java b/test-runner/src/android/test/mock/MockIContentProvider.java
index c0dc7c3..ee8c376 100644
--- a/test-runner/src/android/test/mock/MockIContentProvider.java
+++ b/test-runner/src/android/test/mock/MockIContentProvider.java
@@ -62,7 +62,8 @@
     }
 
     public ParcelFileDescriptor openFile(
-            String callingPackage, Uri url, String mode, ICancellationSignal signal) {
+            String callingPackage, Uri url, String mode, ICancellationSignal signal,
+            IBinder callerToken) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
index 89288bf..e4cbb2f 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
@@ -90,7 +90,7 @@
 
     @Override
     public ParcelFileDescriptor openFile(
-            String callingPackage, Uri arg0, String arg1, ICancellationSignal signal)
+            String callingPackage, Uri arg0, String arg1, ICancellationSignal signal, IBinder token)
             throws RemoteException, FileNotFoundException {
         // TODO Auto-generated method stub
         return null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index aeb70e9..2c3736f 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -16,6 +16,7 @@
 
 package com.android.layoutlib.bridge.android;
 
+import android.os.IBinder;
 import com.android.annotations.Nullable;
 import com.android.ide.common.rendering.api.ILayoutPullParser;
 import com.android.ide.common.rendering.api.IProjectCallback;
@@ -938,12 +939,24 @@
     }
 
     @Override
+    public int checkPermission(String arg0, int arg1, int arg2, IBinder arg3) {
+        // pass
+        return 0;
+    }
+
+    @Override
     public int checkUriPermission(Uri arg0, int arg1, int arg2, int arg3) {
         // pass
         return 0;
     }
 
     @Override
+    public int checkUriPermission(Uri arg0, int arg1, int arg2, int arg3, IBinder arg4) {
+        // pass
+        return 0;
+    }
+
+    @Override
     public int checkUriPermission(Uri arg0, String arg1, String arg2, int arg3,
             int arg4, int arg5) {
         // pass
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 1393bce..6ddebde 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1968,7 +1968,7 @@
     /**
      * Start Wi-fi Protected Setup
      *
-     * @param config WPS configuration
+     * @param config WPS configuration (does not support {@link WpsInfo#LABEL})
      * @param listener for callbacks on success or failure. Can be null.
      * @throws IllegalStateException if the WifiManager instance needs to be
      * initialized again