Merge "Import translations. DO NOT MERGE" into lmp-dev
diff --git a/api/current.txt b/api/current.txt
index fc042d2..a69a8e5 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5424,7 +5424,7 @@
     method public boolean getCrossProfileCallerIdDisabled(android.content.ComponentName);
     method public java.util.List<java.lang.String> getCrossProfileWidgetProviders(android.content.ComponentName);
     method public int getCurrentFailedPasswordAttempts();
-    method public java.util.List<byte[]> getInstalledCaCerts();
+    method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
     method public int getKeyguardDisabledFeatures(android.content.ComponentName);
     method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
     method public long getMaximumTimeToLock(android.content.ComponentName);
@@ -5445,7 +5445,7 @@
     method public boolean getScreenCaptureDisabled(android.content.ComponentName);
     method public boolean getStorageEncryption(android.content.ComponentName);
     method public int getStorageEncryptionStatus();
-    method public boolean hasCaCertInstalled(byte[]);
+    method public boolean hasCaCertInstalled(android.content.ComponentName, byte[]);
     method public boolean hasGrantedPolicy(android.content.ComponentName, int);
     method public boolean installCaCert(android.content.ComponentName, byte[]);
     method public boolean isActivePasswordSufficient();
@@ -5513,7 +5513,6 @@
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.deviceAdminPackageName";
-    field public static final java.lang.String EXTRA_PROVISIONING_EMAIL_ADDRESS = "android.app.extra.ManagedProfileEmailAddress";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCALE = "android.app.extra.LOCALE";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCAL_TIME = "android.app.extra.LOCAL_TIME";
     field public static final java.lang.String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.TIME_ZONE";
@@ -5535,6 +5534,7 @@
     field public static final int KEYGUARD_DISABLE_TRUST_AGENTS = 16; // 0x10
     field public static final int KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS = 8; // 0x8
     field public static final int KEYGUARD_DISABLE_WIDGETS_ALL = 1; // 0x1
+    field public static final java.lang.String KEY_PROVISIONING_EMAIL_ADDRESS = "android.app.key.ManagedProfileEmailAddress";
     field public static final java.lang.String MIME_TYPE_PROVISIONING_NFC = "application/com.android.managedprovisioning";
     field public static final int PASSWORD_QUALITY_ALPHABETIC = 262144; // 0x40000
     field public static final int PASSWORD_QUALITY_ALPHANUMERIC = 327680; // 0x50000
@@ -15920,13 +15920,13 @@
   }
 
   public abstract class VolumeProvider {
-    ctor public VolumeProvider(int, int);
+    ctor public VolumeProvider(int, int, int);
+    method public final int getCurrentVolume();
     method public final int getMaxVolume();
     method public final int getVolumeControl();
-    method public final void notifyVolumeChanged();
     method public void onAdjustVolume(int);
-    method public abstract int onGetCurrentVolume();
     method public void onSetVolumeTo(int);
+    method public final void setCurrentVolume(int);
     field public static final int VOLUME_CONTROL_ABSOLUTE = 2; // 0x2
     field public static final int VOLUME_CONTROL_FIXED = 0; // 0x0
     field public static final int VOLUME_CONTROL_RELATIVE = 1; // 0x1
@@ -28267,7 +28267,6 @@
     method public final void setRequestingRingback(boolean);
     method public final void setRinging();
     method public final void setStatusHints(android.telecomm.StatusHints);
-    method public final void startActivityFromInCall(android.app.PendingIntent);
     method public static java.lang.String stateToString(int);
     field public static final int STATE_ACTIVE = 4; // 0x4
     field public static final int STATE_DIALING = 3; // 0x3
@@ -28298,8 +28297,6 @@
     method public final java.util.Collection<android.telecomm.Connection> getAllConnections();
     method public final android.os.IBinder onBind(android.content.Intent);
     method public void onConference(android.telecomm.Connection, android.telecomm.Connection);
-    method public void onConnectionAdded(android.telecomm.Connection);
-    method public void onConnectionRemoved(android.telecomm.Connection);
     method public android.telecomm.Connection onCreateIncomingConnection(android.telecomm.PhoneAccountHandle, android.telecomm.ConnectionRequest);
     method public android.telecomm.Connection onCreateOutgoingConnection(android.telecomm.PhoneAccountHandle, android.telecomm.ConnectionRequest);
     method public void onRemoteConferenceAdded(android.telecomm.RemoteConference);
@@ -28327,10 +28324,15 @@
     method public java.lang.CharSequence getLabel();
     method public java.lang.CharSequence getShortDescription();
     method public java.lang.String getSubscriptionNumber();
+    method public java.util.List<java.lang.String> getSupportedUriSchemes();
+    method public boolean supportsUriScheme(java.lang.String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1
     field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
     field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final java.lang.String SCHEME_SIP = "sip";
+    field public static final java.lang.String SCHEME_TEL = "tel";
+    field public static final java.lang.String SCHEME_VOICEMAIL = "voicemail";
   }
 
   public static class PhoneAccount.Builder {
@@ -28343,6 +28345,8 @@
     method public android.telecomm.PhoneAccount.Builder withLabel(java.lang.CharSequence);
     method public android.telecomm.PhoneAccount.Builder withShortDescription(java.lang.CharSequence);
     method public android.telecomm.PhoneAccount.Builder withSubscriptionNumber(java.lang.String);
+    method public android.telecomm.PhoneAccount.Builder withSupportedUriScheme(java.lang.String);
+    method public android.telecomm.PhoneAccount.Builder withSupportedUriSchemes(java.util.List<java.lang.String>);
   }
 
   public class PhoneAccountHandle implements android.os.Parcelable {
@@ -28445,7 +28449,6 @@
     method public void onParentChanged(android.telecomm.RemoteConnection, android.telecomm.RemoteConnection);
     method public void onPostDialWait(android.telecomm.RemoteConnection, java.lang.String);
     method public void onRequestingRingback(android.telecomm.RemoteConnection, boolean);
-    method public void onStartActivityFromInCall(android.telecomm.RemoteConnection, android.app.PendingIntent);
     method public void onStateChanged(android.telecomm.RemoteConnection, int);
     method public void onStatusHintsChanged(android.telecomm.RemoteConnection, android.telecomm.StatusHints);
   }
@@ -28471,9 +28474,10 @@
     method public void addNewIncomingCall(android.telecomm.PhoneAccountHandle, android.os.Bundle);
     method public void cancelMissedCallsNotification();
     method public void clearAccounts(java.lang.String);
-    method public android.telecomm.PhoneAccountHandle getDefaultOutgoingPhoneAccount();
+    method public android.telecomm.PhoneAccountHandle getDefaultOutgoingPhoneAccount(java.lang.String);
     method public java.util.List<android.telecomm.PhoneAccountHandle> getEnabledPhoneAccounts();
     method public android.telecomm.PhoneAccount getPhoneAccount(android.telecomm.PhoneAccountHandle);
+    method public java.util.List<android.telecomm.PhoneAccountHandle> getPhoneAccountsSupportingScheme(java.lang.String);
     method public boolean handleMmi(java.lang.String);
     method public boolean hasMultipleEnabledAccounts();
     method public boolean isInCall();
@@ -28849,23 +28853,23 @@
   }
 
   public final class SmsManager {
-    method public android.net.Uri addMultimediaMessageDraft(byte[]);
+    method public android.net.Uri addMultimediaMessageDraft(android.net.Uri);
     method public android.net.Uri addTextMessageDraft(java.lang.String, java.lang.String);
     method public boolean archiveStoredConversation(long, boolean);
     method public boolean deleteStoredConversation(long);
     method public boolean deleteStoredMessage(android.net.Uri);
     method public java.util.ArrayList<java.lang.String> divideMessage(java.lang.String);
-    method public void downloadMultimediaMessage(java.lang.String, android.content.ContentValues, android.app.PendingIntent);
+    method public void downloadMultimediaMessage(java.lang.String, android.net.Uri, android.content.ContentValues, android.app.PendingIntent);
     method public boolean getAutoPersisting();
     method public android.os.Bundle getCarrierConfigValues();
     method public static android.telephony.SmsManager getDefault();
-    method public static android.telephony.SmsManager getSmsManagerForSubId(long);
+    method public static android.telephony.SmsManager getSmsManagerUsingSubId(long);
     method public long getSubId();
-    method public android.net.Uri importMultimediaMessage(byte[], java.lang.String, long, boolean, boolean);
+    method public android.net.Uri importMultimediaMessage(android.net.Uri, java.lang.String, long, boolean, boolean);
     method public android.net.Uri importTextMessage(java.lang.String, int, java.lang.String, long, boolean, boolean);
     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(byte[], java.lang.String, android.content.ContentValues, android.app.PendingIntent);
+    method public void sendMultimediaMessage(android.net.Uri, java.lang.String, android.content.ContentValues, android.app.PendingIntent);
     method public void sendMultipartTextMessage(java.lang.String, java.lang.String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>);
     method public void sendStoredMultimediaMessage(android.net.Uri, android.content.ContentValues, android.app.PendingIntent);
     method public void sendStoredMultipartTextMessage(android.net.Uri, java.lang.String, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>);
@@ -28876,6 +28880,8 @@
     method public void updateMmsSendStatus(int, boolean);
     method public void updateSmsSendStatus(int, boolean);
     method public boolean updateStoredMessageStatus(android.net.Uri, android.content.ContentValues);
+    field public static final java.lang.String MESSAGE_STATUS_READ = "read";
+    field public static final java.lang.String MESSAGE_STATUS_SEEN = "seen";
     field public static final java.lang.String MMS_CONFIG_ALIAS_ENABLED = "aliasEnabled";
     field public static final java.lang.String MMS_CONFIG_ALIAS_MAX_CHARS = "aliasMaxChars";
     field public static final java.lang.String MMS_CONFIG_ALIAS_MIN_CHARS = "aliasMinChars";
@@ -28904,10 +28910,9 @@
     field public static final java.lang.String MMS_CONFIG_UA_PROF_TAG_NAME = "uaProfTagName";
     field public static final java.lang.String MMS_CONFIG_UA_PROF_URL = "uaProfUrl";
     field public static final java.lang.String MMS_CONFIG_USER_AGENT = "userAgent";
-    field public static final java.lang.String MESSAGE_STATUS_READ = "read";
-    field public static final java.lang.String MESSAGE_STATUS_SEEN = "seen";
     field public static final int MMS_ERROR_HTTP_FAILURE = 4; // 0x4
     field public static final int MMS_ERROR_INVALID_APN = 2; // 0x2
+    field public static final int MMS_ERROR_IO_ERROR = 5; // 0x5
     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_EXTRA_DATA = "data";
@@ -32916,6 +32921,7 @@
     field public static final int KEYCODE_GUIDE = 172; // 0xac
     field public static final int KEYCODE_H = 36; // 0x24
     field public static final int KEYCODE_HEADSETHOOK = 79; // 0x4f
+    field public static final int KEYCODE_HELP = 259; // 0x103
     field public static final int KEYCODE_HENKAN = 214; // 0xd6
     field public static final int KEYCODE_HOME = 3; // 0x3
     field public static final int KEYCODE_I = 37; // 0x25
@@ -33016,9 +33022,36 @@
     field public static final int KEYCODE_T = 48; // 0x30
     field public static final int KEYCODE_TAB = 61; // 0x3d
     field public static final int KEYCODE_TV = 170; // 0xaa
+    field public static final int KEYCODE_TV_ANTENNA_CABLE = 242; // 0xf2
+    field public static final int KEYCODE_TV_AUDIO_DESCRIPTION = 252; // 0xfc
+    field public static final int KEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN = 254; // 0xfe
+    field public static final int KEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP = 253; // 0xfd
+    field public static final int KEYCODE_TV_CONTENTS_MENU = 256; // 0x100
     field public static final int KEYCODE_TV_DATA_SERVICE = 230; // 0xe6
     field public static final int KEYCODE_TV_INPUT = 178; // 0xb2
+    field public static final int KEYCODE_TV_INPUT_COMPONENT_1 = 249; // 0xf9
+    field public static final int KEYCODE_TV_INPUT_COMPONENT_2 = 250; // 0xfa
+    field public static final int KEYCODE_TV_INPUT_COMPOSITE_1 = 247; // 0xf7
+    field public static final int KEYCODE_TV_INPUT_COMPOSITE_2 = 248; // 0xf8
+    field public static final int KEYCODE_TV_INPUT_HDMI_1 = 243; // 0xf3
+    field public static final int KEYCODE_TV_INPUT_HDMI_2 = 244; // 0xf4
+    field public static final int KEYCODE_TV_INPUT_HDMI_3 = 245; // 0xf5
+    field public static final int KEYCODE_TV_INPUT_HDMI_4 = 246; // 0xf6
+    field public static final int KEYCODE_TV_INPUT_VGA_1 = 251; // 0xfb
+    field public static final int KEYCODE_TV_MEDIA_CONTEXT_MENU = 257; // 0x101
+    field public static final int KEYCODE_TV_NETWORK = 241; // 0xf1
+    field public static final int KEYCODE_TV_NUMBER_ENTRY = 234; // 0xea
     field public static final int KEYCODE_TV_POWER = 177; // 0xb1
+    field public static final int KEYCODE_TV_RADIO_SERVICE = 232; // 0xe8
+    field public static final int KEYCODE_TV_SATELLITE = 237; // 0xed
+    field public static final int KEYCODE_TV_SATELLITE_BS = 238; // 0xee
+    field public static final int KEYCODE_TV_SATELLITE_CS = 239; // 0xef
+    field public static final int KEYCODE_TV_SATELLITE_SERVICE = 240; // 0xf0
+    field public static final int KEYCODE_TV_TELETEXT = 233; // 0xe9
+    field public static final int KEYCODE_TV_TERRESTRIAL_ANALOG = 235; // 0xeb
+    field public static final int KEYCODE_TV_TERRESTRIAL_DIGITAL = 236; // 0xec
+    field public static final int KEYCODE_TV_TIMER_PROGRAMMING = 258; // 0x102
+    field public static final int KEYCODE_TV_ZOOM_MODE = 255; // 0xff
     field public static final int KEYCODE_U = 49; // 0x31
     field public static final int KEYCODE_UNKNOWN = 0; // 0x0
     field public static final int KEYCODE_V = 50; // 0x32
@@ -36762,7 +36795,6 @@
     method public deprecated void onGlobalFocusChanged(android.view.View, android.view.View);
     method public void onPause();
     method public void onResume();
-    method public static void optOutDataReductionProxy();
     method public boolean overlayHorizontalScrollbar();
     method public boolean overlayVerticalScrollbar();
     method public boolean pageDown(boolean);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index bc54055..3e03893 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -18,12 +18,14 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.Point;
 import android.os.BatteryStats;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
+
 import com.android.internal.app.ProcessStats;
 import com.android.internal.os.TransferPipe;
 import com.android.internal.util.FastPrintWriter;
@@ -2464,7 +2466,11 @@
         }
     }
 
-    /** @hide */
+    /**
+     * Gets the userId of the current foreground user. Requires system permissions.
+     * @hide
+     */
+    @SystemApi
     public static int getCurrentUser() {
         UserInfo ui;
         try {
diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java
index 613e248..ad4a22b 100644
--- a/core/java/android/app/ActivityTransitionState.java
+++ b/core/java/android/app/ActivityTransitionState.java
@@ -151,6 +151,7 @@
             mEnterActivityOptions = options;
             mIsEnterTriggered = false;
             if (mEnterActivityOptions.isReturning()) {
+                restoreExitedViews();
                 int result = mEnterActivityOptions.getResultCode();
                 if (result != 0) {
                     activity.onActivityReenter(result, mEnterActivityOptions.getResultData());
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 6843827..e2def31 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1640,7 +1640,10 @@
         if (itemInfo.showUserIcon != UserHandle.USER_NULL) {
             return new BitmapDrawable(getUserManager().getUserIcon(itemInfo.showUserIcon));
         }
-        Drawable dr = getDrawable(itemInfo.packageName, itemInfo.icon, appInfo);
+        Drawable dr = null;
+        if (itemInfo.packageName != null) {
+            dr = getDrawable(itemInfo.packageName, itemInfo.icon, appInfo);
+        }
         if (dr == null) {
             dr = itemInfo.loadDefaultIcon(this);
         }
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index 47d3fd6..4126647 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -170,7 +170,7 @@
 
     private void sendSharedElementDestination() {
         boolean allReady;
-        if (allowOverlappingTransitions()) {
+        if (allowOverlappingTransitions() && getEnterViewsTransition() != null) {
             allReady = false;
         } else {
             allReady = !getDecor().isLayoutRequested();
@@ -466,6 +466,7 @@
             Drawable background = getDecor().getBackground();
             if (background != null) {
                 background = background.mutate();
+                getWindow().setBackgroundDrawable(background);
                 mBackgroundAnimator = ObjectAnimator.ofInt(background, "alpha", 255);
                 mBackgroundAnimator.setDuration(getFadeDuration());
                 mBackgroundAnimator.addListener(new AnimatorListenerAdapter() {
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index 3760b96..231c93f 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -140,7 +140,8 @@
         if (getDecor() != null) {
             getDecor().suppressLayout(true);
         }
-        if (!mSharedElements.isEmpty() && getSharedElementTransition() != null) {
+        if (mExitSharedElementBundle != null && !mExitSharedElementBundle.isEmpty() &&
+                !mSharedElements.isEmpty() && getSharedElementTransition() != null) {
             startTransition(new Runnable() {
                 public void run() {
                     startSharedElementExit();
@@ -259,6 +260,8 @@
             ViewGroup decor = getDecor();
             Drawable background;
             if (decor != null && (background = decor.getBackground()) != null) {
+                background = background.mutate();
+                getWindow().setBackgroundDrawable(background);
                 mBackgroundAnimator = ObjectAnimator.ofInt(background, "alpha", 0);
                 mBackgroundAnimator.addListener(new AnimatorListenerAdapter() {
                     @Override
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index dbd180f..bdcff38 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -48,6 +48,9 @@
     void setPackagePriority(String pkg, int uid, int priority);
     int getPackagePriority(String pkg, int uid);
 
+    void setPackageVisibilityOverride(String pkg, int uid, int visibility);
+    int getPackageVisibilityOverride(String pkg, int uid);
+
     // TODO: Remove this when callers have been migrated to the equivalent
     // INotificationListener method.
     StatusBarNotification[] getActiveNotifications(String callingPkg);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 6cc6fb2..f8dfdd9 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -21,6 +21,7 @@
 import android.annotation.SdkConstant.SdkConstantType;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -129,6 +130,14 @@
     public static final int DEFAULT_LIGHTS = 4;
 
     /**
+     * Maximum length of CharSequences accepted by Builder and friends.
+     *
+     * <p>
+     * Avoids spamming the system with overly large strings such as full e-mails.
+     */
+    private static final int MAX_CHARSEQUENCE_LENGTH = 5 * 1024;
+
+    /**
      * A timestamp related to this notification, in milliseconds since the epoch.
      *
      * Default value: {@link System#currentTimeMillis() Now}.
@@ -816,13 +825,6 @@
     public static final String EXTRA_COMPACT_ACTIONS = "android.compactActions";
 
     /**
-     * {@link #extras} key: the user that built the notification.
-     *
-     * @hide
-     */
-    public static final String EXTRA_ORIGINATING_USERID = "android.originatingUserId";
-
-    /**
      * Value for {@link #EXTRA_AS_HEADS_UP} that indicates this notification should not be
      * displayed in the heads up space.
      *
@@ -1435,6 +1437,10 @@
      * @hide
      */
     public static CharSequence safeCharSequence(CharSequence cs) {
+        if (cs == null) return cs;
+        if (cs.length() > MAX_CHARSEQUENCE_LENGTH) {
+            cs = cs.subSequence(0, MAX_CHARSEQUENCE_LENGTH);
+        }
         if (cs instanceof Parcelable) {
             Log.e(TAG, "warning: " + cs.getClass().getCanonicalName()
                     + " instance is a custom Parcelable and not allowed in Notification");
@@ -1801,10 +1807,12 @@
                 = "android.rebuild.hudViewActionCount";
 
         /**
-         * The package name of the context used to create the notification via a Builder.
+         * The ApplicationInfo of the package that created the notification, used to create
+         * a context to rebuild the notification via a Builder.
+         * @hide
          */
-        private static final String EXTRA_REBUILD_CONTEXT_PACKAGE =
-                "android.rebuild.contextPackage";
+        private static final String EXTRA_REBUILD_CONTEXT_APPLICATION_INFO =
+                "android.rebuild.applicationInfo";
 
         // Whether to enable stripping (at post time) & rebuilding (at listener receive time) of
         // memory intensive resources.
@@ -1855,11 +1863,6 @@
         private int mColor = COLOR_DEFAULT;
 
         /**
-         * The user that built the notification originally.
-         */
-        private int mOriginatingUserId;
-
-        /**
          * Contains extras related to rebuilding during the build phase.
          */
         private Bundle mRebuildBundle = new Bundle();
@@ -1917,7 +1920,7 @@
             mPeople = new ArrayList<String>();
 
             mColorUtil = context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.L ?
-                    NotificationColorUtil.getInstance() : null;
+                    NotificationColorUtil.getInstance(mContext) : null;
         }
 
         /**
@@ -2579,7 +2582,7 @@
             // Note: This assumes that the current user can read the profile badge of the
             // originating user.
             UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-            return userManager.getBadgeForUser(new UserHandle(mOriginatingUserId), 0);
+            return userManager.getBadgeForUser(new UserHandle(mContext.getUserId()), 0);
         }
 
         private Bitmap getProfileBadge() {
@@ -2658,8 +2661,7 @@
          * @param hasProgress whether the progress bar should be shown and set
          */
         private RemoteViews applyStandardTemplate(int resId, boolean hasProgress) {
-            RemoteViews contentView = new BuilderRemoteViews(mContext.getPackageName(),
-                    mOriginatingUserId, resId);
+            RemoteViews contentView = new BuilderRemoteViews(mContext.getApplicationInfo(), resId);
 
             resetStandardTemplate(contentView);
 
@@ -2890,7 +2892,7 @@
         }
 
         private void processLegacyAction(Action action, RemoteViews button) {
-            if (!isLegacy() || mColorUtil.isGrayscale(mContext, action.icon)) {
+            if (!isLegacy() || mColorUtil.isGrayscaleIcon(mContext, action.icon)) {
                 button.setTextViewCompoundDrawablesRelativeColorFilter(R.id.action0, 0,
                         mContext.getResources().getColor(R.color.notification_action_color_filter),
                         PorterDuff.Mode.MULTIPLY);
@@ -2909,7 +2911,7 @@
          * Apply any necessary background to smallIcons being used in the largeIcon spot.
          */
         private void processSmallIconAsLarge(int largeIconId, RemoteViews contentView) {
-            if (!isLegacy() || mColorUtil.isGrayscale(mContext, largeIconId)) {
+            if (!isLegacy() || mColorUtil.isGrayscaleIcon(mContext, largeIconId)) {
                 applyLargeIconBackground(contentView);
             }
         }
@@ -2920,7 +2922,7 @@
          */
         // TODO: also check bounds, transparency, that sort of thing.
         private void processLargeLegacyIcon(Bitmap largeIcon, RemoteViews contentView) {
-            if (isLegacy() && mColorUtil.isGrayscale(largeIcon)) {
+            if (isLegacy() && mColorUtil.isGrayscaleIcon(largeIcon)) {
                 applyLargeIconBackground(contentView);
             } else {
                 removeLargeIconBackground(contentView);
@@ -2956,7 +2958,7 @@
          */
         private void processSmallRightIcon(int smallIconDrawableId,
                 RemoteViews contentView) {
-            if (!isLegacy() || mColorUtil.isGrayscale(mContext, smallIconDrawableId)) {
+            if (!isLegacy() || mColorUtil.isGrayscaleIcon(mContext, smallIconDrawableId)) {
                 contentView.setDrawableParameters(R.id.right_icon, false, -1,
                         0xFFFFFFFF,
                         PorterDuff.Mode.SRC_ATOP, -1);
@@ -3051,8 +3053,8 @@
          */
         public void populateExtras(Bundle extras) {
             // Store original information used in the construction of this object
-            extras.putInt(EXTRA_ORIGINATING_USERID, mOriginatingUserId);
-            extras.putString(EXTRA_REBUILD_CONTEXT_PACKAGE, mContext.getPackageName());
+            extras.putParcelable(EXTRA_REBUILD_CONTEXT_APPLICATION_INFO,
+                    mContext.getApplicationInfo());
             extras.putCharSequence(EXTRA_TITLE, mContentTitle);
             extras.putCharSequence(EXTRA_TEXT, mContentText);
             extras.putCharSequence(EXTRA_SUB_TEXT, mSubText);
@@ -3140,13 +3142,14 @@
             extras.remove(EXTRA_NEEDS_REBUILD);
 
             // Re-create notification context so we can access app resources.
-            String packageName = extras.getString(EXTRA_REBUILD_CONTEXT_PACKAGE);
+            ApplicationInfo applicationInfo = extras.getParcelable(
+                    EXTRA_REBUILD_CONTEXT_APPLICATION_INFO);
             Context builderContext;
             try {
-                builderContext = context.createPackageContext(packageName,
+                builderContext = context.createApplicationContext(applicationInfo,
                         Context.CONTEXT_RESTRICTED);
             } catch (NameNotFoundException e) {
-                Log.e(TAG, "Package name " + packageName + " not found");
+                Log.e(TAG, "ApplicationInfo " + applicationInfo + " not found");
                 builderContext = context;  // try with our context
             }
 
@@ -3281,7 +3284,6 @@
 
             // Extras.
             Bundle extras = n.extras;
-            mOriginatingUserId = extras.getInt(EXTRA_ORIGINATING_USERID);
             mContentTitle = extras.getCharSequence(EXTRA_TITLE);
             mContentText = extras.getCharSequence(EXTRA_TEXT);
             mSubText = extras.getCharSequence(EXTRA_SUB_TEXT);
@@ -3314,7 +3316,6 @@
          * object.
          */
         public Notification build() {
-            mOriginatingUserId = mContext.getUserId();
             mHasThreeLines = hasThreeLines();
 
             Notification n = buildUnstyled();
@@ -4814,8 +4815,8 @@
             super(parcel);
         }
 
-        public BuilderRemoteViews(String packageName, int userId, int layoutId) {
-            super(packageName, userId, layoutId);
+        public BuilderRemoteViews(ApplicationInfo appInfo, int layoutId) {
+            super(appInfo, layoutId);
         }
 
         @Override
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 9ed8960..668de62 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -115,13 +115,14 @@
         = "android.app.action.ACTION_PROVISION_MANAGED_PROFILE";
 
     /**
-     * A {@link Parcelable} extra of type {@link PersistableBundle} that allows a mobile device
-     * management application that starts managed profile provisioning to pass data to itself on the
-     * managed profile when provisioning completes. The mobile device management application sends
-     * this extra in an intent with the action {@link #ACTION_PROVISION_MANAGED_PROFILE} and
-     * receives it in {@link DeviceAdminReceiver#onProfileProvisioningComplete} via an intent with
-     * the action {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE}. The bundle is
-     * not changed during the managed profile provisioning.
+     * A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that allows
+     * a mobile device management application that starts managed profile provisioning to pass data
+     * to itself on the managed profile when provisioning completes. The mobile device management
+     * application sends this extra in an intent with the action
+     * {@link #ACTION_PROVISION_MANAGED_PROFILE} and receives it in
+     * {@link DeviceAdminReceiver#onProfileProvisioningComplete} via an intent with the action
+     * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE}. The bundle is not changed
+     * during the managed profile provisioning.
      */
     public static final String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE =
             "android.app.extra.ADMIN_EXTRA_BUNDLE";
@@ -150,18 +151,12 @@
         = "android.app.extra.DEFAULT_MANAGED_PROFILE_NAME";
 
     /**
-     * A String extra that, holds the email address of the account which a managed profile is
-     * created for. Used with {@link #ACTION_PROVISION_MANAGED_PROFILE} and
-     * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE}.
-     *
-     * <p> If the {@link #ACTION_PROVISION_MANAGED_PROFILE} intent that starts managed provisioning
-     * contains this extra, it is forwarded in the
-     * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE} intent to the mobile
-     * device management application that was set as the profile owner during provisioning.
-     * It is usually used to avoid that the user has to enter their email address twice.
+     * A bundle key, used in the bundle extra {@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}. The
+     * corresponding value holds the email address of the account which the managed profile is
+     * created for.
      */
-    public static final String EXTRA_PROVISIONING_EMAIL_ADDRESS
-        = "android.app.extra.ManagedProfileEmailAddress";
+    public static final String KEY_PROVISIONING_EMAIL_ADDRESS
+        = "android.app.key.ManagedProfileEmailAddress";
 
     /**
      * A String extra holding the time zone {@link android.app.AlarmManager} that the device
@@ -1785,16 +1780,24 @@
      * If a user has installed any certificates by other means than device policy these will be
      * included too.
      *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @return a List of byte[] arrays, each encoding one user CA certificate.
      */
-    public List<byte[]> getInstalledCaCerts() {
-        final TrustedCertificateStore certStore = new TrustedCertificateStore();
+    public List<byte[]> getInstalledCaCerts(ComponentName admin) {
         List<byte[]> certs = new ArrayList<byte[]>();
-        for (String alias : certStore.userAliases()) {
+        if (mService != null) {
             try {
-                certs.add(certStore.getCertificate(alias).getEncoded());
-            } catch (CertificateException ce) {
-                Log.w(TAG, "Could not encode certificate: " + alias, ce);
+                mService.enforceCanManageCaCerts(admin);
+                final TrustedCertificateStore certStore = new TrustedCertificateStore();
+                for (String alias : certStore.userAliases()) {
+                    try {
+                        certs.add(certStore.getCertificate(alias).getEncoded());
+                    } catch (CertificateException ce) {
+                        Log.w(TAG, "Could not encode certificate: " + alias, ce);
+                    }
+                }
+            } catch (RemoteException re) {
+                Log.w(TAG, "Failed talking with device policy service", re);
             }
         }
         return certs;
@@ -1821,13 +1824,19 @@
     /**
      * Returns whether this certificate is installed as a trusted CA.
      *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param certBuffer encoded form of the certificate to look up.
      */
-    public boolean hasCaCertInstalled(byte[] certBuffer) {
-        try {
-            return getCaCertAlias(certBuffer) != null;
-        } catch (CertificateException ce) {
-            Log.w(TAG, "Could not parse certificate", ce);
+    public boolean hasCaCertInstalled(ComponentName admin, byte[] certBuffer) {
+        if (mService != null) {
+            try {
+                mService.enforceCanManageCaCerts(admin);
+                return getCaCertAlias(certBuffer) != null;
+            } catch (RemoteException re) {
+                Log.w(TAG, "Failed talking with device policy service", re);
+            } catch (CertificateException ce) {
+                Log.w(TAG, "Could not parse certificate", ce);
+            }
         }
         return false;
     }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index c984cf9..57d8b95 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -124,6 +124,7 @@
 
     boolean installCaCert(in ComponentName admin, in byte[] certBuffer);
     void uninstallCaCert(in ComponentName admin, in String alias);
+    void enforceCanManageCaCerts(in ComponentName admin);
 
     void addPersistentPreferredActivity(in ComponentName admin, in IntentFilter filter, in ComponentName activity);
     void clearPackagePersistentPreferredActivities(in ComponentName admin, String packageName);
diff --git a/core/java/android/app/job/JobScheduler.java b/core/java/android/app/job/JobScheduler.java
index ca7022d..89efeb2 100644
--- a/core/java/android/app/job/JobScheduler.java
+++ b/core/java/android/app/job/JobScheduler.java
@@ -21,14 +21,24 @@
 import android.content.Context;
 
 /**
- * Class for scheduling various types of jobs with the scheduling framework on the device.
+ * This is an API for scheduling various types of jobs against the framework that will be executed
+ * in your application's own process.
+ * <p>
  * See {@link android.app.job.JobInfo} for more description of the types of jobs that can be run
- * and how to construct them.
+ * and how to construct them. You will construct these JobInfo objects and pass them to the
+ * JobScheduler with {@link #schedule(JobInfo)}. When the criteria declared are met, the
+ * system will execute this job on your application's {@link android.app.job.JobService}.
+ * You identify which JobService is meant to execute the logic for your job when you create the
+ * JobInfo with
+ * {@link android.app.job.JobInfo.Builder#JobInfo.Builder(int,android.content.ComponentName)}.
+ * </p>
+ * <p>
  * The framework will be intelligent about when you receive your callbacks, and attempt to batch
  * and defer them as much as possible. Typically if you don't specify a deadline on your job, it
  * can be run at any moment depending on the current state of the JobScheduler's internal queue,
  * however it might be deferred as long as until the next time the device is connected to a power
  * source.
+ * </p>
  * <p>You do not
  * instantiate this class directly; instead, retrieve it through
  * {@link android.content.Context#getSystemService
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index b98e5ae..36997e5 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -375,6 +375,14 @@
             } // else ASSERT(mPort == channel)
             ret = 0;
         } catch (IOException e) {
+            if (mPfd != null) {
+                try {
+                    mPfd.close();
+                } catch (IOException e1) {
+                    Log.e(TAG, "bindListen, close mPfd: " + e1);
+                }
+                mPfd = null;
+            }
             Log.e(TAG, "bindListen, fail to get port number, exception: " + e);
             return -1;
         }
diff --git a/core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java b/core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java
index d0a3a3f..d5ec71a 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java
@@ -114,21 +114,24 @@
                 currentAfRun = mAfRun;
             }
 
-            mCamera.setAutoFocusMoveCallback(new Camera.AutoFocusMoveCallback() {
+            Camera.AutoFocusMoveCallback afMoveCallback = new Camera.AutoFocusMoveCallback() {
                 @Override
                 public void onAutoFocusMoving(boolean start, Camera camera) {
                     synchronized (mLock) {
                         int latestAfRun = mAfRun;
 
                         if (VERBOSE) {
-                            Log.v(TAG, "onAutoFocusMoving - start " + start + " latest AF run " +
-                                    latestAfRun + ", last AF run " + currentAfRun);
+                            Log.v(TAG,
+                                    "onAutoFocusMoving - start " + start + " latest AF run " +
+                                            latestAfRun + ", last AF run " + currentAfRun
+                            );
                         }
 
                         if (currentAfRun != latestAfRun) {
                             Log.d(TAG,
                                     "onAutoFocusMoving - ignoring move callbacks from old af run"
-                                            + currentAfRun);
+                                            + currentAfRun
+                            );
                             return;
                         }
 
@@ -151,9 +154,19 @@
                         mAfState = newAfState;
                     }
                 }
-            });
+            };
+
+            // Only set move callback if we can call autofocus.
+            switch (afMode) {
+                case Parameters.FOCUS_MODE_AUTO:
+                case Parameters.FOCUS_MODE_MACRO:
+                case Parameters.FOCUS_MODE_CONTINUOUS_PICTURE:
+                case Parameters.FOCUS_MODE_CONTINUOUS_VIDEO:
+                    mCamera.setAutoFocusMoveCallback(afMoveCallback);
+            }
         }
 
+
         // AF Locking
         switch (afTrigger) {
             case CONTROL_AF_TRIGGER_START:
@@ -167,6 +180,7 @@
                     case Parameters.FOCUS_MODE_CONTINUOUS_PICTURE:
                     case Parameters.FOCUS_MODE_CONTINUOUS_VIDEO:
                         afStateAfterStart = CONTROL_AF_STATE_PASSIVE_SCAN;
+                        break;
                     default:
                         // EDOF, INFINITY
                         afStateAfterStart = CONTROL_AF_STATE_INACTIVE;
@@ -183,6 +197,11 @@
                             "new AF run is " + currentAfRun);
                 }
 
+                // Avoid calling autofocus unless we are in a state that supports calling this.
+                if (afStateAfterStart == CONTROL_AF_STATE_INACTIVE) {
+                    break;
+                }
+
                 mCamera.autoFocus(new Camera.AutoFocusCallback() {
                     @Override
                     public void onAutoFocus(boolean success, Camera camera) {
diff --git a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java b/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
index 4c4ad0d..42ee4fa 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
@@ -122,7 +122,10 @@
                         activeArray, zoomData, aeRegions, maxNumMeteringAreas,
                         /*regionName*/"AE");
 
-                params.setMeteringAreas(meteringAreaList);
+                // WAR: for b/17252693, some devices can't handle params.setFocusAreas(null).
+                if (maxNumMeteringAreas > 0) {
+                    params.setMeteringAreas(meteringAreaList);
+                }
             }
 
             // afRegions
@@ -133,7 +136,10 @@
                         activeArray, zoomData, afRegions, maxNumFocusAreas,
                         /*regionName*/"AF");
 
-                params.setFocusAreas(focusAreaList);
+                // WAR: for b/17252693, some devices can't handle params.setFocusAreas(null).
+                if (maxNumFocusAreas > 0) {
+                    params.setFocusAreas(focusAreaList);
+                }
             }
         }
 
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 5ce9d5c..0ff5f6a 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -234,6 +234,7 @@
      * @return user id of the current process
      * @hide
      */
+    @SystemApi
     public static final int myUserId() {
         return getUserId(Process.myUid());
     }
@@ -253,7 +254,11 @@
         mHandle = h;
     }
 
-    /** @hide */
+    /**
+     * Returns the userId stored in this UserHandle.
+     * @hide
+     */
+    @SystemApi
     public int getIdentifier() {
         return mHandle;
     }
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index f793667..59220e1 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -15,6 +15,7 @@
  */
 package android.os;
 
+import android.annotation.SystemApi;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.content.Context;
@@ -424,6 +425,19 @@
     }
 
     /**
+     * Checks if the calling app is running in a managed profile.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
+     *
+     * @return whether the caller is in a managed profile.
+     * @hide
+     */
+    @SystemApi
+    public boolean isManagedProfile() {
+        UserInfo user = getUserInfo(UserHandle.myUserId());
+        return user != null ? user.isManagedProfile() : false;
+    }
+
+    /**
      * Return whether the given user is actively running.  This means that
      * the user is in the "started" state, not "stopped" -- it is currently
      * allowed to run code through scheduled alarms, receiving broadcasts,
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index fc12101..2ca8098 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -26,6 +26,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ParceledListSlice;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -693,10 +694,15 @@
      * current {@link RankingMap}.
      */
     public static class Ranking {
+        /** Value signifying that the user has not expressed a per-app visibility override value.
+         * @hide */
+        public static final int VISIBILITY_NO_OVERRIDE = -1000;
+
         private String mKey;
         private int mRank = -1;
         private boolean mIsAmbient;
         private boolean mMatchesInterruptionFilter;
+        private int mVisibilityOverride;
 
         public Ranking() {}
 
@@ -726,6 +732,17 @@
         }
 
         /**
+         * Returns the user specificed visibility for the package that posted
+         * this notification, or
+         * {@link NotificationListenerService.Ranking#VISIBILITY_NO_OVERRIDE} if
+         * no such preference has been expressed.
+         * @hide
+         */
+        public int getVisibilityOverride() {
+            return mVisibilityOverride;
+        }
+
+        /**
          * Returns whether the notification meets the user's interruption
          * filter.
          *
@@ -744,11 +761,12 @@
         }
 
         private void populate(String key, int rank, boolean isAmbient,
-                boolean matchesInterruptionFilter) {
+                boolean matchesInterruptionFilter, int visibilityOverride) {
             mKey = key;
             mRank = rank;
             mIsAmbient = isAmbient;
             mMatchesInterruptionFilter = matchesInterruptionFilter;
+            mVisibilityOverride = visibilityOverride;
         }
     }
 
@@ -764,6 +782,7 @@
         private final NotificationRankingUpdate mRankingUpdate;
         private ArrayMap<String,Integer> mRanks;
         private ArraySet<Object> mIntercepted;
+        private ArrayMap<String, Integer> mVisibilityOverrides;
 
         private RankingMap(NotificationRankingUpdate rankingUpdate) {
             mRankingUpdate = rankingUpdate;
@@ -788,7 +807,8 @@
          */
         public boolean getRanking(String key, Ranking outRanking) {
             int rank = getRank(key);
-            outRanking.populate(key, rank, isAmbient(key), !isIntercepted(key));
+            outRanking.populate(key, rank, isAmbient(key), !isIntercepted(key),
+                    getVisibilityOverride(key));
             return rank >= 0;
         }
 
@@ -820,6 +840,19 @@
             return mIntercepted.contains(key);
         }
 
+        private int getVisibilityOverride(String key) {
+            synchronized (this) {
+                if (mVisibilityOverrides == null) {
+                    buildVisibilityOverridesLocked();
+                }
+            }
+            Integer overide = mVisibilityOverrides.get(key);
+            if (overide == null) {
+                return Ranking.VISIBILITY_NO_OVERRIDE;
+            }
+            return overide.intValue();
+        }
+
         // Locked by 'this'
         private void buildRanksLocked() {
             String[] orderedKeys = mRankingUpdate.getOrderedKeys();
@@ -837,6 +870,15 @@
             Collections.addAll(mIntercepted, dndInterceptedKeys);
         }
 
+        // Locked by 'this'
+        private void buildVisibilityOverridesLocked() {
+            Bundle visibilityBundle = mRankingUpdate.getVisibilityOverrides();
+            mVisibilityOverrides = new ArrayMap<>(visibilityBundle.size());
+            for (String key: visibilityBundle.keySet()) {
+               mVisibilityOverrides.put(key, visibilityBundle.getInt(key));
+            }
+        }
+
         // ----------- Parcelable
 
         @Override
diff --git a/core/java/android/service/notification/NotificationRankingUpdate.java b/core/java/android/service/notification/NotificationRankingUpdate.java
index 26af38b..6fba900 100644
--- a/core/java/android/service/notification/NotificationRankingUpdate.java
+++ b/core/java/android/service/notification/NotificationRankingUpdate.java
@@ -15,6 +15,7 @@
  */
 package android.service.notification;
 
+import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -26,18 +27,21 @@
     private final String[] mKeys;
     private final String[] mInterceptedKeys;
     private final int mFirstAmbientIndex;
+    private final Bundle mVisibilityOverrides;
 
     public NotificationRankingUpdate(String[] keys, String[] interceptedKeys,
-                                     int firstAmbientIndex) {
+            Bundle visibilityOverrides, int firstAmbientIndex) {
         mKeys = keys;
         mFirstAmbientIndex = firstAmbientIndex;
         mInterceptedKeys = interceptedKeys;
+        mVisibilityOverrides = visibilityOverrides;
     }
 
     public NotificationRankingUpdate(Parcel in) {
         mKeys = in.readStringArray();
         mFirstAmbientIndex = in.readInt();
         mInterceptedKeys = in.readStringArray();
+        mVisibilityOverrides = in.readBundle();
     }
 
     @Override
@@ -50,6 +54,7 @@
         out.writeStringArray(mKeys);
         out.writeInt(mFirstAmbientIndex);
         out.writeStringArray(mInterceptedKeys);
+        out.writeBundle(mVisibilityOverrides);
     }
 
     public static final Parcelable.Creator<NotificationRankingUpdate> CREATOR
@@ -74,4 +79,8 @@
     public String[] getInterceptedKeys() {
         return mInterceptedKeys;
     }
+
+    public Bundle getVisibilityOverrides() {
+        return mVisibilityOverrides;
+    }
 }
diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java
index 9fec9a1..1e411b4 100755
--- a/core/java/android/text/format/DateFormat.java
+++ b/core/java/android/text/format/DateFormat.java
@@ -17,6 +17,7 @@
 package android.text.format;
 
 import android.content.Context;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.SpannableStringBuilder;
 import android.text.Spanned;
@@ -128,8 +129,14 @@
      * @return true if 24 hour time format is selected, false otherwise.
      */
     public static boolean is24HourFormat(Context context) {
-        String value = Settings.System.getString(context.getContentResolver(),
-                Settings.System.TIME_12_24);
+        // This method is called by View classes that can be used by RemoteViews
+        // and rendered in another user. The context therefore may reference
+        // a user that would require interact accross users to access. So
+        // use the user id we are running as.
+        // This is the case when we have widgets from a user profile added
+        // to the homescreen.
+        String value = Settings.System.getStringForUser(context.getContentResolver(),
+                Settings.System.TIME_12_24, UserHandle.myUserId());
 
         if (value == null) {
             Locale locale = context.getResources().getConfiguration().locale;
@@ -227,8 +234,14 @@
      * @return the {@link java.text.DateFormat} object that properly formats the date.
      */
     public static java.text.DateFormat getDateFormat(Context context) {
-        String value = Settings.System.getString(context.getContentResolver(),
-                Settings.System.DATE_FORMAT);
+        // This method is called by View classes that can be used by RemoteViews
+        // and rendered in another user. The context therefore may reference
+        // a user that would require interact accross users to access. So
+        // use the user id we are running as.
+        // This is the case when we have widgets from a user profile added
+        // to the homescreen.
+        String value = Settings.System.getStringForUser(context.getContentResolver(),
+                Settings.System.DATE_FORMAT, UserHandle.myUserId());
 
         return getDateFormatForSetting(context, value);
     }
diff --git a/core/java/android/transition/ChangeTransform.java b/core/java/android/transition/ChangeTransform.java
index d579f54..cb0a875 100644
--- a/core/java/android/transition/ChangeTransform.java
+++ b/core/java/android/transition/ChangeTransform.java
@@ -45,6 +45,10 @@
     private static final String PROPNAME_TRANSFORMS = "android:changeTransform:transforms";
     private static final String PROPNAME_PARENT = "android:changeTransform:parent";
     private static final String PROPNAME_PARENT_MATRIX = "android:changeTransform:parentMatrix";
+    private static final String PROPNAME_INTERMEDIATE_PARENT_MATRIX =
+            "android:changeTransform:intermediateParentMatrix";
+    private static final String PROPNAME_INTERMEDIATE_MATRIX =
+            "android:changeTransform:intermediateMatrix";
 
     private static final String[] sTransitionProperties = {
             PROPNAME_MATRIX,
@@ -172,6 +176,10 @@
             parent.transformMatrixToGlobal(parentMatrix);
             parentMatrix.preTranslate(-parent.getScrollX(), -parent.getScrollY());
             transitionValues.values.put(PROPNAME_PARENT_MATRIX, parentMatrix);
+            transitionValues.values.put(PROPNAME_INTERMEDIATE_MATRIX,
+                    view.getTag(R.id.transitionTransform));
+            transitionValues.values.put(PROPNAME_INTERMEDIATE_PARENT_MATRIX,
+                    view.getTag(R.id.parentMatrix));
         }
         return;
     }
@@ -199,12 +207,13 @@
         ViewGroup endParent = (ViewGroup) endValues.values.get(PROPNAME_PARENT);
         boolean handleParentChange = mReparent && !parentsMatch(startParent, endParent);
 
-        Matrix startMatrix = (Matrix) startValues.view.getTag(R.id.transitionTransform);
+        Matrix startMatrix = (Matrix) startValues.values.get(PROPNAME_INTERMEDIATE_MATRIX);
         if (startMatrix != null) {
             startValues.values.put(PROPNAME_MATRIX, startMatrix);
         }
 
-        Matrix startParentMatrix = (Matrix) startValues.view.getTag(R.id.parentMatrix);
+        Matrix startParentMatrix = (Matrix)
+                startValues.values.get(PROPNAME_INTERMEDIATE_PARENT_MATRIX);
         if (startParentMatrix != null) {
             startValues.values.put(PROPNAME_PARENT_MATRIX, startParentMatrix);
         }
@@ -250,9 +259,11 @@
         ObjectAnimator animator = ObjectAnimator.ofObject(view, ANIMATION_MATRIX_PROPERTY,
                 new TransitionUtils.MatrixEvaluator(), startMatrix, endMatrix);
 
+        final Matrix finalEndMatrix = endMatrix;
+
         AnimatorListenerAdapter listener = new AnimatorListenerAdapter() {
             private boolean mIsCanceled;
-            private Matrix mTempMatrix;
+            private Matrix mTempMatrix = new Matrix();
 
             @Override
             public void onAnimationCancel(Animator animation) {
@@ -262,8 +273,7 @@
             @Override
             public void onAnimationEnd(Animator animation) {
                 if (!mIsCanceled) {
-                    view.setTagInternal(R.id.transitionTransform, null);
-                    view.setTagInternal(R.id.parentMatrix, null);
+                    setCurrentMatrix(finalEndMatrix);
                 }
                 ANIMATION_MATRIX_PROPERTY.set(view, null);
                 transforms.restore(view);
@@ -273,19 +283,19 @@
             public void onAnimationPause(Animator animation) {
                 ValueAnimator animator = (ValueAnimator) animation;
                 Matrix currentMatrix = (Matrix) animator.getAnimatedValue();
-                if (mTempMatrix == null) {
-                    mTempMatrix = new Matrix(currentMatrix);
-                } else {
-                    mTempMatrix.set(currentMatrix);
-                }
-                view.setTagInternal(R.id.transitionTransform, mTempMatrix);
-                transforms.restore(view);
+                setCurrentMatrix(currentMatrix);
             }
 
             @Override
             public void onAnimationResume(Animator animation) {
                 setIdentityTransforms(view);
             }
+
+            private void setCurrentMatrix(Matrix currentMatrix) {
+                mTempMatrix.set(currentMatrix);
+                view.setTagInternal(R.id.transitionTransform, mTempMatrix);
+                transforms.restore(view);
+            }
         };
 
         animator.addListener(listener);
@@ -423,6 +433,8 @@
         public void onTransitionEnd(Transition transition) {
             transition.removeListener(this);
             GhostView.removeGhost(mView);
+            mView.setTagInternal(R.id.transitionTransform, null);
+            mView.setTagInternal(R.id.parentMatrix, null);
         }
 
         @Override
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 964b054..0701b53 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -660,8 +660,96 @@
     /** Key code constant: Voice Assist key.
      * Launches the global voice assist activity. Not delivered to applications. */
     public static final int KEYCODE_VOICE_ASSIST = 231;
+    /** Key code constant: Radio key.
+     * Toggles TV service / Radio service. */
+    public static final int KEYCODE_TV_RADIO_SERVICE = 232;
+    /** Key code constant: Teletext key.
+     * Displays Teletext service. */
+    public static final int KEYCODE_TV_TELETEXT = 233;
+    /** Key code constant: Number entry key.
+     * Initiates to enter multi-digit channel nubmber when each digit key is assigned
+     * for selecting separate channel. Corresponds to Number Entry Mode (0x1D) of CEC
+     * User Control Code. */
+    public static final int KEYCODE_TV_NUMBER_ENTRY = 234;
+    /** Key code constant: Analog Terrestrial key.
+     * Switches to analog terrestrial broadcast service. */
+    public static final int KEYCODE_TV_TERRESTRIAL_ANALOG = 235;
+    /** Key code constant: Digital Terrestrial key.
+     * Switches to digital terrestrial broadcast service. */
+    public static final int KEYCODE_TV_TERRESTRIAL_DIGITAL = 236;
+    /** Key code constant: Satellite key.
+     * Switches to digital satellite broadcast service. */
+    public static final int KEYCODE_TV_SATELLITE = 237;
+    /** Key code constant: BS key.
+     * Switches to BS digital satellite broadcasting service available in Japan. */
+    public static final int KEYCODE_TV_SATELLITE_BS = 238;
+    /** Key code constant: CS key.
+     * Switches to CS digital satellite broadcasting service available in Japan. */
+    public static final int KEYCODE_TV_SATELLITE_CS = 239;
+    /** Key code constant: BS/CS key.
+     * Toggles between BS and CS digital satellite services. */
+    public static final int KEYCODE_TV_SATELLITE_SERVICE = 240;
+    /** Key code constant: Toggle Network key.
+     * Toggles selecting broacast services. */
+    public static final int KEYCODE_TV_NETWORK = 241;
+    /** Key code constant: Antenna/Cable key.
+     * Toggles broadcast input source between antenna and cable. */
+    public static final int KEYCODE_TV_ANTENNA_CABLE = 242;
+    /** Key code constant: HDMI #1 key.
+     * Switches to HDMI input #1. */
+    public static final int KEYCODE_TV_INPUT_HDMI_1 = 243;
+    /** Key code constant: HDMI #2 key.
+     * Switches to HDMI input #2. */
+    public static final int KEYCODE_TV_INPUT_HDMI_2 = 244;
+    /** Key code constant: HDMI #3 key.
+     * Switches to HDMI input #3. */
+    public static final int KEYCODE_TV_INPUT_HDMI_3 = 245;
+    /** Key code constant: HDMI #4 key.
+     * Switches to HDMI input #4. */
+    public static final int KEYCODE_TV_INPUT_HDMI_4 = 246;
+    /** Key code constant: Composite #1 key.
+     * Switches to composite video input #1. */
+    public static final int KEYCODE_TV_INPUT_COMPOSITE_1 = 247;
+    /** Key code constant: Composite #2 key.
+     * Switches to composite video input #2. */
+    public static final int KEYCODE_TV_INPUT_COMPOSITE_2 = 248;
+    /** Key code constant: Component #1 key.
+     * Switches to component video input #1. */
+    public static final int KEYCODE_TV_INPUT_COMPONENT_1 = 249;
+    /** Key code constant: Component #2 key.
+     * Switches to component video input #2. */
+    public static final int KEYCODE_TV_INPUT_COMPONENT_2 = 250;
+    /** Key code constant: VGA #1 key.
+     * Switches to VGA (analog RGB) input #1. */
+    public static final int KEYCODE_TV_INPUT_VGA_1 = 251;
+    /** Key code constant: Audio description key.
+     * Toggles audio description off / on. */
+    public static final int KEYCODE_TV_AUDIO_DESCRIPTION = 252;
+    /** Key code constant: Audio description mixing volume up key.
+     * Louden audio description volume as compared with normal audio volume. */
+    public static final int KEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP = 253;
+    /** Key code constant: Audio description mixing volume down key.
+     * Lessen audio description volume as compared with normal audio volume. */
+    public static final int KEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN = 254;
+    /** Key code constant: Zoom mode key.
+     * Changes Zoom mode (Normal, Full, Zoom, Wide-zoom, etc.) */
+    public static final int KEYCODE_TV_ZOOM_MODE = 255;
+    /** Key code constant: Contents menu key.
+     * Goes to the title list. Corresponds to Contents Menu (0x0B) of CEC User Control
+     * Code */
+    public static final int KEYCODE_TV_CONTENTS_MENU = 256;
+    /** Key code constant: Media context menu key.
+     * Goes to the context menu of media contents. Corresponds to Media Context-sensitive
+     * Menu (0x11) of CEC User Control Code. */
+    public static final int KEYCODE_TV_MEDIA_CONTEXT_MENU = 257;
+    /** Key code constant: Timer programming key.
+     * Goes to the timer recording menu. Corresponds to Timer Programming (0x54) of
+     * CEC User Control Code. */
+    public static final int KEYCODE_TV_TIMER_PROGRAMMING = 258;
+    /** Key code constant: Help key. */
+    public static final int KEYCODE_HELP = 259;
 
-    private static final int LAST_KEYCODE = KEYCODE_VOICE_ASSIST;
+    private static final int LAST_KEYCODE = KEYCODE_HELP;
 
     // NOTE: If you add a new keycode here you must also add it to:
     //  isSystem()
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index ca08ecc..5d2822d 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -126,7 +126,7 @@
     void destroy() {
         mInitialized = false;
         updateEnabledState(null);
-        nDestroyCanvasAndSurface(mNativeProxy);
+        nDestroy(mNativeProxy);
     }
 
     private void updateEnabledState(Surface surface) {
@@ -488,7 +488,7 @@
     private static native void nSetOpaque(long nativeProxy, boolean opaque);
     private static native int nSyncAndDrawFrame(long nativeProxy,
             long frameTimeNanos, long recordDuration, float density);
-    private static native void nDestroyCanvasAndSurface(long nativeProxy);
+    private static native void nDestroy(long nativeProxy);
     private static native void nRegisterAnimatingRenderNode(long rootRenderNode, long animatingNode);
 
     private static native void nInvokeFunctor(long functor, boolean waitForCompletion);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index fce6f0b..21e7c6b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4908,36 +4908,11 @@
             }
 
             onFocusChanged(true, direction, previouslyFocusedRect);
-            manageFocusHotspot(true, oldFocus);
             refreshDrawableState();
         }
     }
 
     /**
-     * Forwards focus information to the background drawable, if necessary. When
-     * the view is gaining focus, <code>v</code> is the previous focus holder.
-     * When the view is losing focus, <code>v</code> is the next focus holder.
-     *
-     * @param focused whether this view is focused
-     * @param v previous or the next focus holder, or null if none
-     */
-    private void manageFocusHotspot(boolean focused, View v) {
-        final Rect r = new Rect();
-        if (v != null && mAttachInfo != null) {
-            v.getHotspotBounds(r);
-            final int[] location = mAttachInfo.mTmpLocation;
-            getLocationOnScreen(location);
-            r.offset(-location[0], -location[1]);
-        } else {
-            r.set(0, 0, mRight - mLeft, mBottom - mTop);
-        }
-
-        final float x = r.exactCenterX();
-        final float y = r.exactCenterY();
-        drawableHotspotChanged(x, y);
-    }
-
-    /**
      * Populates <code>outRect</code> with the hotspot bounds. By default,
      * the hotspot bounds are identical to the screen bounds.
      *
@@ -5060,8 +5035,6 @@
             }
 
             onFocusChanged(false, 0, null);
-
-            manageFocusHotspot(false, focused);
             refreshDrawableState();
 
             if (propagate && (!refocus || !rootViewRequestFocus())) {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index e1f19ee..edfa7af3 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1810,21 +1810,6 @@
     }
 
     /**
-     * Sets whether the application wants to opt out from using the Data Reduction Proxy
-     * service.
-     * Data reduction proxy can only be enabled by the user and will almost always be
-     * transparent to the application. In rare cases where using the proxy interferes
-     * with the app, the application developer can use this API to opt out from using the
-     * proxy. Note that this may increase network bandwidth usage.
-     *
-     * See <a href=http://developer.chrome.com/multidevice/data-compression>
-     * Data Compression Proxy</a>
-     */
-    public static void optOutDataReductionProxy() {
-        getFactory().getStatics().optOutDataReductionProxy();
-    }
-
-    /**
      * Gets the list of currently loaded plugins.
      *
      * @return the list of currently loaded plugins
diff --git a/core/java/android/webkit/WebViewFactoryProvider.java b/core/java/android/webkit/WebViewFactoryProvider.java
index 48f3ca3..20bb932 100644
--- a/core/java/android/webkit/WebViewFactoryProvider.java
+++ b/core/java/android/webkit/WebViewFactoryProvider.java
@@ -61,12 +61,6 @@
 
         /**
          * Implements the API method:
-         * {@link android.webkit.WebView#optOutDataReductionProxy() }
-         */
-        void optOutDataReductionProxy();
-
-        /**
-         * Implements the API method:
          * {@link android.webkit.WebView#setSlowWholeDocumentDrawEnabled(boolean) }
          */
         void enableSlowWholeDocumentDraw();
diff --git a/core/java/android/widget/DateTimeView.java b/core/java/android/widget/DateTimeView.java
index 45d1403..b3ff88b 100644
--- a/core/java/android/widget/DateTimeView.java
+++ b/core/java/android/widget/DateTimeView.java
@@ -29,6 +29,7 @@
 import android.provider.Settings;
 import android.widget.TextView;
 import android.widget.RemoteViews.RemoteView;
+import android.os.UserHandle;
 
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
@@ -190,8 +191,15 @@
     }
 
     private DateFormat getDateFormat() {
-        String format = Settings.System.getString(getContext().getContentResolver(),
-                Settings.System.DATE_FORMAT);
+        // OK, this is gross but needed. This class is supported by the
+        // remote views mechanism and as a part of that the remote views
+        // can be inflated by a context for another user without the app
+        // having interact users permission - just for loading resources.
+        // For example, when adding widgets from a user profile to the
+        // home screen. Therefore, we access settings as the user the app
+        // is running as not the one the context is for.
+        String format = Settings.System.getStringForUser(getContext().getContentResolver(),
+                Settings.System.DATE_FORMAT, UserHandle.myUserId());
         if (format == null || "".equals(format)) {
             return DateFormat.getDateInstance(DateFormat.SHORT);
         } else {
@@ -212,10 +220,20 @@
         filter.addAction(Intent.ACTION_TIME_CHANGED);
         filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
         filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
-        context.registerReceiver(mBroadcastReceiver, filter);
+
+        // OK, this is gross but needed. This class is supported by the
+        // remote views mechanism and as a part of that the remote views
+        // can be inflated by a context for another user without the app
+        // having interact users permission - just for loading resources.
+        // For example, when adding widgets from a user profile to the
+        // home screen. Therefore, we register the receiver and content
+        // observer as the user the app is running as not the one the context is for.
+        context.registerReceiverAsUser(mBroadcastReceiver, android.os.Process.myUserHandle(),
+                filter, null, null);
 
         Uri uri = Settings.System.getUriFor(Settings.System.DATE_FORMAT);
-        context.getContentResolver().registerContentObserver(uri, true, mContentObserver);
+        context.getContentResolver().registerContentObserver(uri, true, mContentObserver,
+                UserHandle.myUserId());
     }
 
     private void unregisterReceivers() {
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 69d5f40..9de69f2 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -1653,8 +1653,10 @@
      *
      * @param application The application whose content is shown by the views.
      * @param layoutId The id of the layout resource.
+     *
+     * @hide
      */
-    private RemoteViews(ApplicationInfo application, int layoutId) {
+    protected RemoteViews(ApplicationInfo application, int layoutId) {
         mApplication = application;
         mLayoutId = layoutId;
         mBitmapCache = new BitmapCache();
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 0a3c7ff..0289ccc 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -334,6 +334,10 @@
             setInputType(inputType);
         }
 
+        boolean focusable = true;
+        focusable = a.getBoolean(R.styleable.SearchView_focusable, focusable);
+        setFocusable(focusable);
+
         a.recycle();
 
         // Save voice intent for later queries/launching
diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java
index 4c5c71d..acfc543 100644
--- a/core/java/android/widget/TextClock.java
+++ b/core/java/android/widget/TextClock.java
@@ -26,6 +26,7 @@
 import android.net.Uri;
 import android.os.Handler;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.format.DateFormat;
 import android.util.AttributeSet;
@@ -495,12 +496,28 @@
         filter.addAction(Intent.ACTION_TIME_CHANGED);
         filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
 
-        getContext().registerReceiver(mIntentReceiver, filter, null, getHandler());
+        // OK, this is gross but needed. This class is supported by the
+        // remote views mechanism and as a part of that the remote views
+        // can be inflated by a context for another user without the app
+        // having interact users permission - just for loading resources.
+        // For example, when adding widgets from a user profile to the
+        // home screen. Therefore, we register the receiver as the user
+        // the app is running as not the one the context is for.
+        getContext().registerReceiverAsUser(mIntentReceiver, android.os.Process.myUserHandle(),
+                filter, null, getHandler());
     }
 
     private void registerObserver() {
         final ContentResolver resolver = getContext().getContentResolver();
-        resolver.registerContentObserver(Settings.System.CONTENT_URI, true, mFormatChangeObserver);
+        // OK, this is gross but needed. This class is supported by the
+        // remote views mechanism and as a part of that the remote views
+        // can be inflated by a context for another user without the app
+        // having interact users permission - just for loading resources.
+        // For example, when adding widgets from a user profile to the
+        // home screen. Therefore, we register the content observer
+        // as the user the app is running as not the one the context is for.
+        resolver.registerContentObserver(Settings.System.CONTENT_URI, true,
+                mFormatChangeObserver, UserHandle.myUserId());
     }
 
     private void unregisterReceiver() {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 3e1b674..188a3e9 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -41,6 +41,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.BoringLayout;
 import android.text.DynamicLayout;
@@ -8337,8 +8338,15 @@
      * to speak passwords.
      */
     private boolean shouldSpeakPasswordsForAccessibility() {
-        return (Settings.Secure.getInt(mContext.getContentResolver(),
-                Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, 0) == 1);
+        // OK, this is gross but needed. This class is supported by the
+        // remote views mechanism and as a part of that the remote views
+        // can be inflated by a context for another user without the app
+        // having interact users permission - just for loading resources.
+        // For example, when adding widgets from a user profile to the
+        // home screen. Therefore, we access settings as user the app is
+        // running as not the one the context is for.
+        return (Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, 0, UserHandle.myUserId()) == 1);
     }
 
     @Override
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index c409520..6d5c98e 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -63,63 +63,46 @@
     private final Context mContext;
     private final DialogInterface mDialogInterface;
     private final Window mWindow;
-    
+
     private CharSequence mTitle;
-
     private CharSequence mMessage;
-
     private ListView mListView;
-    
     private View mView;
 
     private int mViewLayoutResId;
 
     private int mViewSpacingLeft;
-    
     private int mViewSpacingTop;
-    
     private int mViewSpacingRight;
-    
     private int mViewSpacingBottom;
-    
     private boolean mViewSpacingSpecified = false;
-    
+
     private Button mButtonPositive;
-
     private CharSequence mButtonPositiveText;
-
     private Message mButtonPositiveMessage;
 
     private Button mButtonNegative;
-
     private CharSequence mButtonNegativeText;
-
     private Message mButtonNegativeMessage;
 
     private Button mButtonNeutral;
-
     private CharSequence mButtonNeutralText;
-
     private Message mButtonNeutralMessage;
 
     private ScrollView mScrollView;
-    
+
     private int mIconId = 0;
-    
     private Drawable mIcon;
-    
+
     private ImageView mIconView;
-    
     private TextView mTitleView;
-
     private TextView mMessageView;
-
     private View mCustomTitleView;
-    
+
     private boolean mForceInverseBackground;
-    
+
     private ListAdapter mAdapter;
-    
+
     private int mCheckedItem = -1;
 
     private int mAlertDialogLayout;
@@ -130,7 +113,7 @@
     private int mListItemLayout;
 
     private int mButtonPanelLayoutHint = AlertDialog.LAYOUT_HINT_NONE;
-    
+
     private Handler mHandler;
 
     private final View.OnClickListener mButtonHandler = new View.OnClickListener() {
@@ -160,7 +143,7 @@
     private static final class ButtonHandler extends Handler {
         // Button clicks have Message.what as the BUTTON{1,2,3} constant
         private static final int MSG_DISMISS_DIALOG = 1;
-        
+
         private WeakReference<DialogInterface> mDialog;
 
         public ButtonHandler(DialogInterface dialog) {
@@ -170,13 +153,13 @@
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
-                
+
                 case DialogInterface.BUTTON_POSITIVE:
                 case DialogInterface.BUTTON_NEGATIVE:
                 case DialogInterface.BUTTON_NEUTRAL:
                     ((DialogInterface.OnClickListener) msg.obj).onClick(mDialog.get(), msg.what);
                     break;
-                    
+
                 case MSG_DISMISS_DIALOG:
                     ((DialogInterface) msg.obj).dismiss();
             }
@@ -220,16 +203,16 @@
 
         a.recycle();
     }
-    
+
     static boolean canTextInput(View v) {
         if (v.onCheckIsTextEditor()) {
             return true;
         }
-        
+
         if (!(v instanceof ViewGroup)) {
             return false;
         }
-        
+
         ViewGroup vg = (ViewGroup)v;
         int i = vg.getChildCount();
         while (i > 0) {
@@ -239,10 +222,10 @@
                 return true;
             }
         }
-        
+
         return false;
     }
-    
+
     public void installContent() {
         /* We use a custom title so never request a window title */
         mWindow.requestFeature(Window.FEATURE_NO_TITLE);
@@ -262,7 +245,7 @@
         // TODO: use layout hint side for long messages/lists
         return mAlertDialogLayout;
     }
-    
+
     public void setTitle(CharSequence title) {
         mTitle = title;
         if (mTitleView != null) {
@@ -276,7 +259,7 @@
     public void setCustomTitle(View customTitleView) {
         mCustomTitleView = customTitleView;
     }
-    
+
     public void setMessage(CharSequence message) {
         mMessage = message;
         if (mMessageView != null) {
@@ -301,7 +284,7 @@
         mViewLayoutResId = 0;
         mViewSpacingSpecified = false;
     }
-    
+
     /**
      * Set the view to display in the dialog along with the spacing around that view
      */
@@ -326,7 +309,7 @@
     /**
      * Sets a click listener or a message to be sent when the button is clicked.
      * You only need to pass one of {@code listener} or {@code msg}.
-     * 
+     *
      * @param whichButton Which button, can be one of
      *            {@link DialogInterface#BUTTON_POSITIVE},
      *            {@link DialogInterface#BUTTON_NEGATIVE}, or
@@ -341,24 +324,24 @@
         if (msg == null && listener != null) {
             msg = mHandler.obtainMessage(whichButton, listener);
         }
-        
+
         switch (whichButton) {
 
             case DialogInterface.BUTTON_POSITIVE:
                 mButtonPositiveText = text;
                 mButtonPositiveMessage = msg;
                 break;
-                
+
             case DialogInterface.BUTTON_NEGATIVE:
                 mButtonNegativeText = text;
                 mButtonNegativeMessage = msg;
                 break;
-                
+
             case DialogInterface.BUTTON_NEUTRAL:
                 mButtonNeutralText = text;
                 mButtonNeutralMessage = msg;
                 break;
-                
+
             default:
                 throw new IllegalArgumentException("Button does not exist");
         }
@@ -416,11 +399,11 @@
     public void setInverseBackgroundForced(boolean forceInverseBackground) {
         mForceInverseBackground = forceInverseBackground;
     }
-    
+
     public ListView getListView() {
         return mListView;
     }
-    
+
     public Button getButton(int whichButton) {
         switch (whichButton) {
             case DialogInterface.BUTTON_POSITIVE:
@@ -433,7 +416,7 @@
                 return null;
         }
     }
-    
+
     @SuppressWarnings({"UnusedDeclaration"})
     public boolean onKeyDown(int keyCode, KeyEvent event) {
         return mScrollView != null && mScrollView.executeKeyEvent(event);
@@ -469,12 +452,12 @@
         final LinearLayout contentPanel = (LinearLayout) mWindow.findViewById(R.id.contentPanel);
         setupContent(contentPanel);
         final boolean hasButtons = setupButtons();
-        
+
         final LinearLayout topPanel = (LinearLayout) mWindow.findViewById(R.id.topPanel);
         final TypedArray a = mContext.obtainStyledAttributes(
                 null, R.styleable.AlertDialog, R.attr.alertDialogStyle, 0);
         final boolean hasTitle = setupTitle(topPanel);
-            
+
         final View buttonPanel = mWindow.findViewById(R.id.buttonPanel);
         if (!hasButtons) {
             buttonPanel.setVisibility(View.GONE);
@@ -536,14 +519,14 @@
 
     private boolean setupTitle(LinearLayout topPanel) {
         boolean hasTitle = true;
-        
+
         if (mCustomTitleView != null) {
             // Add the custom title view directly to the topPanel layout
             LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                     LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
-            
+
             topPanel.addView(mCustomTitleView, 0, lp);
-            
+
             // Hide the title template
             View titleTemplate = mWindow.findViewById(R.id.title_template);
             titleTemplate.setVisibility(View.GONE);
@@ -587,19 +570,19 @@
     private void setupContent(LinearLayout contentPanel) {
         mScrollView = (ScrollView) mWindow.findViewById(R.id.scrollView);
         mScrollView.setFocusable(false);
-        
+
         // Special case for users that only want to display a String
         mMessageView = (TextView) mWindow.findViewById(R.id.message);
         if (mMessageView == null) {
             return;
         }
-        
+
         if (mMessage != null) {
             mMessageView.setText(mMessage);
         } else {
             mMessageView.setVisibility(View.GONE);
             mScrollView.removeView(mMessageView);
-            
+
             if (mListView != null) {
                 contentPanel.removeView(mWindow.findViewById(R.id.scrollView));
                 contentPanel.addView(mListView,
@@ -664,7 +647,7 @@
                 centerButton(mButtonNeutral);
             }
         }
-        
+
         return whichButtons != 0;
     }
 
@@ -694,7 +677,12 @@
         int centerBright = 0;
         int bottomBright = 0;
         int bottomMedium = 0;
-        if (mContext.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.KITKAT) {
+
+        // If the needsDefaultBackgrounds attribute is set, we know we're
+        // inheriting from a framework style.
+        final boolean needsDefaultBackgrounds = a.getBoolean(
+                R.styleable.AlertDialog_needsDefaultBackgrounds, true);
+        if (needsDefaultBackgrounds) {
             fullDark = R.drawable.popup_full_dark;
             topDark = R.drawable.popup_top_dark;
             centerDark = R.drawable.popup_center_dark;
@@ -705,12 +693,12 @@
             bottomBright = R.drawable.popup_bottom_bright;
             bottomMedium = R.drawable.popup_bottom_medium;
         }
+
         topBright = a.getResourceId(R.styleable.AlertDialog_topBright, topBright);
         topDark = a.getResourceId(R.styleable.AlertDialog_topDark, topDark);
         centerBright = a.getResourceId(R.styleable.AlertDialog_centerBright, centerBright);
         centerDark = a.getResourceId(R.styleable.AlertDialog_centerDark, centerDark);
 
-
         /* We now set the background of all of the sections of the alert.
          * First collect together each section that is being displayed along
          * with whether it is on a light or dark background, then run through
@@ -789,31 +777,6 @@
             }
         }
 
-        /* TODO: uncomment section below. The logic for this should be if 
-         * it's a Contextual menu being displayed AND only a Cancel button 
-         * is shown then do this.
-         */
-//        if (hasButtons && (mListView != null)) {
-            
-            /* Yet another *special* case. If there is a ListView with buttons
-             * don't put the buttons on the bottom but instead put them in the
-             * footer of the ListView this will allow more items to be
-             * displayed.
-             */
-            
-            /*
-            contentPanel.setBackgroundResource(bottomBright);
-            buttonPanel.setBackgroundResource(centerMedium);
-            ViewGroup parent = (ViewGroup) mWindow.findViewById(R.id.parentPanel);
-            parent.removeView(buttonPanel);
-            AbsListView.LayoutParams params = new AbsListView.LayoutParams(
-                    AbsListView.LayoutParams.MATCH_PARENT, 
-                    AbsListView.LayoutParams.MATCH_PARENT);
-            buttonPanel.setLayoutParams(params);
-            mListView.addFooterView(buttonPanel);
-            */
-//        }
-
         final ListView listView = mListView;
         if (listView != null && mAdapter != null) {
             listView.setAdapter(mAdapter);
@@ -854,7 +817,7 @@
     public static class AlertParams {
         public final Context mContext;
         public final LayoutInflater mInflater;
-        
+
         public int mIconId = 0;
         public Drawable mIcon;
         public int mIconAttrId = 0;
@@ -899,20 +862,20 @@
          * will be bound to an adapter.
          */
         public interface OnPrepareListViewListener {
-            
+
             /**
              * Called before the ListView is bound to an adapter.
              * @param listView The ListView that will be shown in the dialog.
              */
             void onPrepareListView(ListView listView);
         }
-        
+
         public AlertParams(Context context) {
             mContext = context;
             mCancelable = true;
             mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         }
-    
+
         public void apply(AlertController dialog) {
             if (mCustomTitleView != null) {
                 dialog.setCustomTitle(mCustomTitleView);
@@ -972,12 +935,12 @@
             }
             */
         }
-        
+
         private void createListView(final AlertController dialog) {
             final RecycleListView listView = (RecycleListView)
                     mInflater.inflate(dialog.mListLayout, null);
             ListAdapter adapter;
-            
+
             if (mIsMultiChoice) {
                 if (mCursor == null) {
                     adapter = new ArrayAdapter<CharSequence>(
@@ -1012,37 +975,37 @@
                             listView.setItemChecked(cursor.getPosition(),
                                     cursor.getInt(mIsCheckedIndex) == 1);
                         }
-    
+
                         @Override
                         public View newView(Context context, Cursor cursor, ViewGroup parent) {
                             return mInflater.inflate(dialog.mMultiChoiceItemLayout,
                                     parent, false);
                         }
-                        
+
                     };
                 }
             } else {
-                int layout = mIsSingleChoice 
+                int layout = mIsSingleChoice
                         ? dialog.mSingleChoiceItemLayout : dialog.mListItemLayout;
                 if (mCursor == null) {
                     adapter = (mAdapter != null) ? mAdapter
                             : new CheckedItemAdapter(mContext, layout, R.id.text1, mItems);
                 } else {
-                    adapter = new SimpleCursorAdapter(mContext, layout, 
+                    adapter = new SimpleCursorAdapter(mContext, layout,
                             mCursor, new String[]{mLabelColumn}, new int[]{R.id.text1});
                 }
             }
-            
+
             if (mOnPrepareListViewListener != null) {
                 mOnPrepareListViewListener.onPrepareListView(listView);
             }
-            
+
             /* Don't directly set the adapter on the ListView as we might
              * want to add a footer to the ListView later.
              */
             dialog.mAdapter = adapter;
             dialog.mCheckedItem = mCheckedItem;
-            
+
             if (mOnClickListener != null) {
                 listView.setOnItemClickListener(new OnItemClickListener() {
                     @Override
@@ -1065,12 +1028,12 @@
                     }
                 });
             }
-            
+
             // Attach a given OnItemSelectedListener to the ListView
             if (mOnItemSelectedListener != null) {
                 listView.setOnItemSelectedListener(mOnItemSelectedListener);
             }
-            
+
             if (mIsSingleChoice) {
                 listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
             } else if (mIsMultiChoice) {
diff --git a/core/java/com/android/internal/util/ImageUtils.java b/core/java/com/android/internal/util/ImageUtils.java
index a5ce6e0ca..c153904 100644
--- a/core/java/com/android/internal/util/ImageUtils.java
+++ b/core/java/com/android/internal/util/ImageUtils.java
@@ -17,6 +17,10 @@
 package com.android.internal.util;
 
 import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
 
 /**
  * Utility class for image analysis and processing.
@@ -31,17 +35,49 @@
     // Alpha amount for which values below are considered transparent.
     private static final int ALPHA_TOLERANCE = 50;
 
+    // Size of the smaller bitmap we're actually going to scan.
+    private static final int COMPACT_BITMAP_SIZE = 64; // pixels
+
     private int[] mTempBuffer;
+    private Bitmap mTempCompactBitmap;
+    private Canvas mTempCompactBitmapCanvas;
+    private Paint mTempCompactBitmapPaint;
+    private final Matrix mTempMatrix = new Matrix();
 
     /**
      * Checks whether a bitmap is grayscale. Grayscale here means "very close to a perfect
      * gray".
+     *
+     * Instead of scanning every pixel in the bitmap, we first resize the bitmap to no more than
+     * COMPACT_BITMAP_SIZE^2 pixels using filtering. The hope is that any non-gray color elements
+     * will survive the squeezing process, contaminating the result with color.
      */
     public boolean isGrayscale(Bitmap bitmap) {
-        final int height = bitmap.getHeight();
-        final int width = bitmap.getWidth();
-        int size = height*width;
+        int height = bitmap.getHeight();
+        int width = bitmap.getWidth();
 
+        // shrink to a more manageable (yet hopefully no more or less colorful) size
+        if (height > COMPACT_BITMAP_SIZE || width > COMPACT_BITMAP_SIZE) {
+            if (mTempCompactBitmap == null) {
+                mTempCompactBitmap = Bitmap.createBitmap(
+                        COMPACT_BITMAP_SIZE, COMPACT_BITMAP_SIZE, Bitmap.Config.ARGB_8888
+                );
+                mTempCompactBitmapCanvas = new Canvas(mTempCompactBitmap);
+                mTempCompactBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+                mTempCompactBitmapPaint.setFilterBitmap(true);
+            }
+            mTempMatrix.reset();
+            mTempMatrix.setScale(
+                    (float) COMPACT_BITMAP_SIZE / width,
+                    (float) COMPACT_BITMAP_SIZE / height,
+                    0, 0);
+            mTempCompactBitmapCanvas.drawColor(0, PorterDuff.Mode.SRC); // select all, erase
+            mTempCompactBitmapCanvas.drawBitmap(bitmap, mTempMatrix, mTempCompactBitmapPaint);
+            bitmap = mTempCompactBitmap;
+            width = height = COMPACT_BITMAP_SIZE;
+        }
+
+        final int size = height*width;
         ensureBufferSize(size);
         bitmap.getPixels(mTempBuffer, 0, width, 0, 0, width, height);
         for (int i = 0; i < size; i++) {
diff --git a/core/java/com/android/internal/util/NotificationColorUtil.java b/core/java/com/android/internal/util/NotificationColorUtil.java
index 665055c..3249ea3 100644
--- a/core/java/com/android/internal/util/NotificationColorUtil.java
+++ b/core/java/com/android/internal/util/NotificationColorUtil.java
@@ -50,23 +50,36 @@
     private final WeakHashMap<Bitmap, Pair<Boolean, Integer>> mGrayscaleBitmapCache =
             new WeakHashMap<Bitmap, Pair<Boolean, Integer>>();
 
-    public static NotificationColorUtil getInstance() {
+    private final int mGrayscaleIconMaxSize; // @dimen/notification_large_icon_width (64dp)
+
+    public static NotificationColorUtil getInstance(Context context) {
         synchronized (sLock) {
             if (sInstance == null) {
-                sInstance = new NotificationColorUtil();
+                sInstance = new NotificationColorUtil(context);
             }
             return sInstance;
         }
     }
 
+    private NotificationColorUtil(Context context) {
+        mGrayscaleIconMaxSize = context.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.notification_large_icon_width);
+    }
+
     /**
-     * Checks whether a bitmap is grayscale. Grayscale here means "very close to a perfect
-     * gray".
+     * Checks whether a Bitmap is a small grayscale icon.
+     * Grayscale here means "very close to a perfect gray"; icon means "no larger than 64dp".
      *
      * @param bitmap The bitmap to test.
-     * @return Whether the bitmap is grayscale.
+     * @return True if the bitmap is grayscale; false if it is color or too large to examine.
      */
-    public boolean isGrayscale(Bitmap bitmap) {
+    public boolean isGrayscaleIcon(Bitmap bitmap) {
+        // quick test: reject large bitmaps
+        if (bitmap.getWidth() > mGrayscaleIconMaxSize
+                || bitmap.getHeight() > mGrayscaleIconMaxSize) {
+            return false;
+        }
+
         synchronized (sLock) {
             Pair<Boolean, Integer> cached = mGrayscaleBitmapCache.get(bitmap);
             if (cached != null) {
@@ -92,22 +105,22 @@
     }
 
     /**
-     * Checks whether a drawable is grayscale. Grayscale here means "very close to a perfect
-     * gray".
+     * Checks whether a Drawable is a small grayscale icon.
+     * Grayscale here means "very close to a perfect gray"; icon means "no larger than 64dp".
      *
      * @param d The drawable to test.
-     * @return Whether the drawable is grayscale.
+     * @return True if the bitmap is grayscale; false if it is color or too large to examine.
      */
-    public boolean isGrayscale(Drawable d) {
+    public boolean isGrayscaleIcon(Drawable d) {
         if (d == null) {
             return false;
         } else if (d instanceof BitmapDrawable) {
             BitmapDrawable bd = (BitmapDrawable) d;
-            return bd.getBitmap() != null && isGrayscale(bd.getBitmap());
+            return bd.getBitmap() != null && isGrayscaleIcon(bd.getBitmap());
         } else if (d instanceof AnimationDrawable) {
             AnimationDrawable ad = (AnimationDrawable) d;
             int count = ad.getNumberOfFrames();
-            return count > 0 && isGrayscale(ad.getFrame(0));
+            return count > 0 && isGrayscaleIcon(ad.getFrame(0));
         } else if (d instanceof VectorDrawable) {
             // We just assume you're doing the right thing if using vectors
             return true;
@@ -117,16 +130,16 @@
     }
 
     /**
-     * Checks whether a drawable with a resoure id is grayscale. Grayscale here means "very close
-     * to a perfect gray".
+     * Checks whether a drawable with a resoure id is a small grayscale icon.
+     * Grayscale here means "very close to a perfect gray"; icon means "no larger than 64dp".
      *
      * @param context The context to load the drawable from.
-     * @return Whether the drawable is grayscale.
+     * @return True if the bitmap is grayscale; false if it is color or too large to examine.
      */
-    public boolean isGrayscale(Context context, int drawableResId) {
+    public boolean isGrayscaleIcon(Context context, int drawableResId) {
         if (drawableResId != 0) {
             try {
-                return isGrayscale(context.getDrawable(drawableResId));
+                return isGrayscaleIcon(context.getDrawable(drawableResId));
             } catch (Resources.NotFoundException ex) {
                 Log.e(TAG, "Drawable not found: " + drawableResId);
                 return false;
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index c7ac815..062a9b1 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -59,6 +59,7 @@
     private int mSubtitleStyleRes;
     private Drawable mSplitBackground;
     private boolean mTitleOptional;
+    private int mCloseItemLayout;
 
     private Animator mCurrentAnimation;
     private boolean mAnimateInOnLayout;
@@ -99,6 +100,10 @@
         mSplitBackground = a.getDrawable(
                 com.android.internal.R.styleable.ActionMode_backgroundSplit);
 
+        mCloseItemLayout = a.getResourceId(
+                com.android.internal.R.styleable.ActionMode_closeItemLayout,
+                R.layout.action_mode_close_item);
+
         a.recycle();
     }
 
@@ -120,7 +125,7 @@
                         LayoutParams.MATCH_PARENT);
                 if (!split) {
                     mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
-                    mMenuView.setBackgroundDrawable(null);
+                    mMenuView.setBackground(null);
                     final ViewGroup oldParent = (ViewGroup) mMenuView.getParent();
                     if (oldParent != null) oldParent.removeView(mMenuView);
                     addView(mMenuView, layoutParams);
@@ -134,7 +139,7 @@
                     layoutParams.width = LayoutParams.MATCH_PARENT;
                     layoutParams.height = mContentHeight;
                     mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
-                    mMenuView.setBackgroundDrawable(mSplitBackground);
+                    mMenuView.setBackground(mSplitBackground);
                     final ViewGroup oldParent = (ViewGroup) mMenuView.getParent();
                     if (oldParent != null) oldParent.removeView(mMenuView);
                     mSplitView.addView(mMenuView, layoutParams);
@@ -211,7 +216,7 @@
     public void initForMode(final ActionMode mode) {
         if (mClose == null) {
             LayoutInflater inflater = LayoutInflater.from(mContext);
-            mClose = inflater.inflate(R.layout.action_mode_close_item, this, false);
+            mClose = inflater.inflate(mCloseItemLayout, this, false);
             addView(mClose);
         } else if (mClose.getParent() == null) {
             addView(mClose);
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 2114ff6..c84708e0 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1449,7 +1449,7 @@
         }
 
         int textId;
-        if (getTelecommManager().isInCall()) {
+        if (isInCall()) {
             // show "return to call" text and show phone icon
             textId = R.string.lockscreen_return_to_call;
             int phoneCallIcon = showIcon ? R.drawable.stat_sys_phone_call : 0;
@@ -1470,6 +1470,13 @@
         getTelecommManager().showInCallScreen(false);
     }
 
+    /**
+     * @return {@code true} if there is a call currently in progress, {@code false} otherwise.
+     */
+    public boolean isInCall() {
+        return getTelecommManager().isInCall();
+    }
+
     private TelecommManager getTelecommManager() {
         return (TelecommManager) mContext.getSystemService(Context.TELECOMM_SERVICE);
     }
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 1296831..949f4ff 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -458,7 +458,7 @@
 static void android_view_RenderNode_endAllAnimators(JNIEnv* env, jobject clazz,
         jlong renderNodePtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
-    renderNode->animators().endAllAnimators();
+    renderNode->animators().endAllStagingAnimators();
 }
 
 #endif // USE_OPENGL_RENDERER
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 99babac..7e6d335 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -166,12 +166,7 @@
     // Runs any animations still left in mCurrentFrameAnimations
     virtual void runRemainingAnimations(TreeInfo& info) {
         AnimationContext::runRemainingAnimations(info);
-        // post all the finished stuff
-        if (mOnFinishedEvents.size()) {
-            sp<InvokeAnimationListeners> message
-                    = new InvokeAnimationListeners(mOnFinishedEvents);
-            mRootNode->sendMessage(message);
-        }
+        postOnFinishedEvents();
     }
 
     virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener) {
@@ -179,9 +174,22 @@
         mOnFinishedEvents.push_back(event);
     }
 
+    virtual void destroy() {
+        AnimationContext::destroy();
+        postOnFinishedEvents();
+    }
+
 private:
     sp<RootRenderNode> mRootNode;
     std::vector<OnFinishedEvent> mOnFinishedEvents;
+
+    void postOnFinishedEvents() {
+        if (mOnFinishedEvents.size()) {
+            sp<InvokeAnimationListeners> message
+                    = new InvokeAnimationListeners(mOnFinishedEvents);
+            mRootNode->sendMessage(message);
+        }
+    }
 };
 
 class ContextFactoryImpl : public IContextFactory {
@@ -291,10 +299,10 @@
     return proxy->syncAndDrawFrame(frameTimeNanos, recordDuration, density);
 }
 
-static void android_view_ThreadedRenderer_destroyCanvasAndSurface(JNIEnv* env, jobject clazz,
+static void android_view_ThreadedRenderer_destroy(JNIEnv* env, jobject clazz,
         jlong proxyPtr) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
-    proxy->destroyCanvasAndSurface();
+    proxy->destroy();
 }
 
 static void android_view_ThreadedRenderer_registerAnimatingRenderNode(JNIEnv* env, jobject clazz,
@@ -430,7 +438,7 @@
     { "nSetup", "(JIIFFFFII)V", (void*) android_view_ThreadedRenderer_setup },
     { "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
     { "nSyncAndDrawFrame", "(JJJF)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
-    { "nDestroyCanvasAndSurface", "(J)V", (void*) android_view_ThreadedRenderer_destroyCanvasAndSurface },
+    { "nDestroy", "(J)V", (void*) android_view_ThreadedRenderer_destroy },
     { "nRegisterAnimatingRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_registerAnimatingRenderNode },
     { "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
     { "nCreateDisplayListLayer", "(JII)J", (void*) android_view_ThreadedRenderer_createDisplayListLayer },
diff --git a/core/res/res/drawable/ic_cab_done_material.xml b/core/res/res/drawable/ic_cab_done_material.xml
deleted file mode 100644
index a370288..0000000
--- a/core/res/res/drawable/ic_cab_done_material.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_cab_done_mtrl_alpha"
-    android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/layout/action_mode_close_item_material.xml b/core/res/res/layout/action_mode_close_item_material.xml
new file mode 100644
index 0000000..8eb780b
--- /dev/null
+++ b/core/res/res/layout/action_mode_close_item_material.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<ImageButton xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/action_mode_close_button"
+        android:focusable="true"
+        android:clickable="true"
+        android:paddingStart="8dip"
+        android:src="?android:attr/actionModeCloseDrawable"
+        style="?android:attr/actionModeCloseButtonStyle"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_marginEnd="16dip" />
diff --git a/core/res/res/values-mcc310-mnc004/config.xml b/core/res/res/values-mcc310-mnc004/config.xml
index 423e250..2778b6e 100644
--- a/core/res/res/values-mcc310-mnc004/config.xml
+++ b/core/res/res/values-mcc310-mnc004/config.xml
@@ -34,4 +34,11 @@
     </string-array>
 
     <bool name="config_auto_attach_data_on_creation">false</bool>
+
+    <!-- Values for GPS configuration (Verizon) -->
+    <string-array translatable="false" name="config_gpsParameters">
+        <item>CAPABILITIES=0x31</item>
+        <item>LPP_PROFILE=3</item>
+        <item>GPS_LOCK=3</item>
+    </string-array>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc120/config.xml b/core/res/res/values-mcc310-mnc120/config.xml
index 62001d9..3b95db5 100644
--- a/core/res/res/values-mcc310-mnc120/config.xml
+++ b/core/res/res/values-mcc310-mnc120/config.xml
@@ -25,4 +25,10 @@
     -->
     <integer name="config_mobile_mtu">1422</integer>
 
+    <!-- Values for GPS configuration (Sprint) -->
+    <string-array translatable="false" name="config_gpsParameters">
+        <item>CAPABILITIES=0x31</item>
+        <item>GPS_LOCK=3</item>
+        <item>LPP_PROFILE=2</item>
+    </string-array>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc150/config.xml b/core/res/res/values-mcc310-mnc150/config.xml
index f1936f4..00d2db8 100644
--- a/core/res/res/values-mcc310-mnc150/config.xml
+++ b/core/res/res/values-mcc310-mnc150/config.xml
@@ -33,4 +33,10 @@
         <item>315</item>
         <item>316</item>
     </string-array>
+    <!-- Values for GPS configuration (AT&T) -->
+    <string-array translatable="false" name="config_gpsParameters">
+        <item>CAPABILITIES=0x33</item>
+        <item>LPP_PROFILE=3</item>
+        <item>GPS_LOCK=1</item>
+    </string-array>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260/config.xml b/core/res/res/values-mcc310-mnc260/config.xml
index 00cdaeb..2f9394a 100644
--- a/core/res/res/values-mcc310-mnc260/config.xml
+++ b/core/res/res/values-mcc310-mnc260/config.xml
@@ -25,9 +25,10 @@
     -->
     <integer name="config_mobile_mtu">1440</integer>
 
-    <!-- Values for GPS configuration -->
+    <!-- Values for GPS configuration (T-Mobile) -->
     <string-array translatable="false" name="config_gpsParameters">
-        <item>"SUPL_PORT=7279"</item>
+        <item>CAPABILITEIS=0x33</item>
         <item>GPS_LOCK=1</item>
+        <item>LPP_PROFILE=2</item>
     </string-array>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410/config.xml b/core/res/res/values-mcc310-mnc410/config.xml
index 9e63047..8069d13 100644
--- a/core/res/res/values-mcc310-mnc410/config.xml
+++ b/core/res/res/values-mcc310-mnc410/config.xml
@@ -40,8 +40,10 @@
         <item>315</item>
         <item>316</item>
     </string-array>
-    <!-- Values for GPS configuration -->
+    <!-- Values for GPS configuration (AT&T) -->
     <string-array translatable="false" name="config_gpsParameters">
-        <item>"SUPL_HOST=supl.google.com"</item>
+        <item>CAPABILITIES=0x33</item>
+        <item>GPS_LOCK=1</item>
+        <item>LPP_PROFILE=3</item>
     </string-array>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc190/config.xml b/core/res/res/values-mcc311-mnc190/config.xml
index a6c4d1b..b4e436d 100644
--- a/core/res/res/values-mcc311-mnc190/config.xml
+++ b/core/res/res/values-mcc311-mnc190/config.xml
@@ -37,4 +37,11 @@
          note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
     <string translatable="false" name="config_tether_apndata">Tether,broadband.cellular1.net,,,,,,,,,311,190,,DUN</string>
 
+    <!-- Values for GPS configuration (Sprint) -->
+    <string-array translatable="false" name="config_gpsParameters">
+        <item>CAPABILITIES=0x31</item>
+        <item>GPS_LOCK=3</item>
+        <item>LPP_PROFILE=2</item>
+    </string-array>
+
 </resources>
diff --git a/core/res/res/values-mcc311-mnc480/config.xml b/core/res/res/values-mcc311-mnc480/config.xml
index e5af60b..cd5d55b 100644
--- a/core/res/res/values-mcc311-mnc480/config.xml
+++ b/core/res/res/values-mcc311-mnc480/config.xml
@@ -44,4 +44,11 @@
     <bool name="config_mobile_allow_volte_vt">false</bool>
 
     <bool name="config_auto_attach_data_on_creation">false</bool>
+
+    <!-- Values for GPS configuration (Verizon) -->
+    <string-array translatable="false" name="config_gpsParameters">
+        <item>CAPABILITIES=0x31</item>
+        <item>GPS_LOCK=3</item>
+        <item>LPP_PROFILE=3</item>
+    </string-array>
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 9b1b7ed..4622995 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1726,6 +1726,34 @@
         <enum name="KEYCODE_LAST_CHANNEL" value="229" />
         <enum name="KEYCODE_TV_DATA_SERVICE" value="230" />
         <enum name="KEYCODE_VOICE_ASSIST" value="231" />
+        <enum name="KEYCODE_TV_RADIO_SERVICE" value="232" />
+        <enum name="KEYCODE_TV_TELETEXT" value="233" />
+        <enum name="KEYCODE_TV_NUMBER_ENTRY" value="234" />
+        <enum name="KEYCODE_TV_TERRESTRIAL_ANALOG" value="235" />
+        <enum name="KEYCODE_TV_TERRESTRIAL_DIGITAL" value="236" />
+        <enum name="KEYCODE_TV_SATELLITE" value="237" />
+        <enum name="KEYCODE_TV_SATELLITE_BS" value="238" />
+        <enum name="KEYCODE_TV_SATELLITE_CS" value="239" />
+        <enum name="KEYCODE_TV_SATELLITE_SERVICE" value="240" />
+        <enum name="KEYCODE_TV_NETWORK" value="241" />
+        <enum name="KEYCODE_TV_ANTENNA_CABLE" value="242" />
+        <enum name="KEYCODE_TV_INPUT_HDMI_1" value="243" />
+        <enum name="KEYCODE_TV_INPUT_HDMI_2" value="244" />
+        <enum name="KEYCODE_TV_INPUT_HDMI_3" value="245" />
+        <enum name="KEYCODE_TV_INPUT_HDMI_4" value="246" />
+        <enum name="KEYCODE_TV_INPUT_COMPOSITE_1" value="247" />
+        <enum name="KEYCODE_TV_INPUT_COMPOSITE_2" value="248" />
+        <enum name="KEYCODE_TV_INPUT_COMPONENT_1" value="249" />
+        <enum name="KEYCODE_TV_INPUT_COMPONENT_2" value="250" />
+        <enum name="KEYCODE_TV_INPUT_VGA_1" value="251" />
+        <enum name="KEYCODE_TV_AUDIO_DESCRIPTION" value="252" />
+        <enum name="KEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP" value="253" />
+        <enum name="KEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN" value="254" />
+        <enum name="KEYCODE_TV_ZOOM_MODE" value="255" />
+        <enum name="KEYCODE_TV_CONTENTS_MENU" value="256" />
+        <enum name="KEYCODE_TV_MEDIA_CONTEXT_MENU" value="257" />
+        <enum name="KEYCODE_TV_TIMER_PROGRAMMING" value="258" />
+        <enum name="KEYCODE_HELP" value="259" />
     </attr>
 
     <!-- ***************************************************************** -->
@@ -1921,6 +1949,8 @@
         <attr name="listItemLayout" format="reference" />
         <attr name="progressLayout" format="reference" />
         <attr name="horizontalProgressLayout" format="reference" />
+        <!-- @hide Whether fullDark, etc. should use default values if null. -->
+        <attr name="needsDefaultBackgrounds" format="boolean" />
     </declare-styleable>
 
     <!-- Fragment animation class attributes. -->
@@ -7087,6 +7117,8 @@
         <attr name="backgroundSplit" />
         <!-- Specifies a fixed height for the action mode bar. -->
         <attr name="height" />
+        <!-- Specifies a layout to use for the "close" item at the starting edge. -->
+        <attr name="closeItemLayout" format="reference" />
     </declare-styleable>
 
     <declare-styleable name="SearchView">
@@ -7119,6 +7151,7 @@
         <attr name="queryBackground" format="reference" />
         <!-- Background for the section containing the action (e.g. voice search) -->
         <attr name="submitBackground" format="reference" />
+        <attr name="focusable" />
     </declare-styleable>
 
     <declare-styleable name="Switch">
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 988198a..d68d12a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1456,6 +1456,10 @@
     <!-- Set to true if after a provisioning apn the radio should be restarted -->
     <bool name="config_restartRadioAfterProvisioning">false</bool>
 
+    <!-- Boolean indicating if RADIO POWER OFF is required on receiving SIM REFRESH with RESET.
+         This will be handled by modem if it is false. -->
+    <bool name="config_requireRadioPowerOffOnSimRefreshReset">false</bool>
+
     <!-- Vibrator pattern to be used as the default for notifications
          that specify DEFAULT_VIBRATE.
      -->
@@ -1533,6 +1537,7 @@
         <item>com.android.server.notification.ValidateNotificationPeople</item>
         <item>com.android.server.notification.PackagePriorityExtractor</item>
         <item>com.android.server.notification.NotificationIntrusivenessExtractor</item>
+        <item>com.android.server.notification.PackageVisibilityExtractor</item>
     </string-array>
 
     <!-- Flag indicating that this device does not rotate and will always remain in its default
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 4aed037..c6d0b0b 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -62,6 +62,7 @@
         <item name="centerMedium">@drawable/popup_center_medium</item>
         <item name="progressLayout">@layout/progress_dialog</item>
         <item name="horizontalProgressLayout">@layout/alert_dialog_progress</item>
+        <item name="needsDefaultBackgrounds">false</item>
     </style>
 
     <style name="Widget.PreferenceFrameLayout">
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 452ee11..77484e6 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -838,7 +838,7 @@
     </style>
 
     <style name="Widget.Material.ActionButton.CloseMode">
-        <item name="background">@drawable/btn_cab_done_material</item>
+        <item name="background">?attr/selectableItemBackgroundBorderless</item>
     </style>
 
     <style name="Widget.Material.ActionButton.Overflow">
@@ -901,6 +901,7 @@
     <style name="Widget.Material.ActionMode" parent="Widget.ActionMode">
         <item name="titleTextStyle">@style/TextAppearance.Material.Widget.ActionMode.Title</item>
         <item name="subtitleTextStyle">@style/TextAppearance.Material.Widget.ActionMode.Subtitle</item>
+        <item name="closeItemLayout">@layout/action_mode_close_item_material</item>
     </style>
 
     <style name="Widget.Material.FastScroll" parent="Widget.FastScroll">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 06bd2ec..1b0f9c4 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -283,6 +283,7 @@
   <java-symbol type="bool" name="config_camera_sound_forced" />
   <java-symbol type="bool" name="config_dontPreferApn" />
   <java-symbol type="bool" name="config_restartRadioAfterProvisioning" />
+  <java-symbol type="bool" name="config_requireRadioPowerOffOnSimRefreshReset" />
   <java-symbol type="bool" name="config_speed_up_audio_on_mt_calls" />
   <java-symbol type="bool" name="config_useFixedVolume" />
   <java-symbol type="bool" name="config_forceDefaultOrientation" />
@@ -2000,4 +2001,5 @@
   <java-symbol type="id" name="parentMatrix" />
   <java-symbol type="bool" name="config_auto_attach_data_on_creation" />
   <java-symbol type="id" name="date_picker_month_day_year_layout" />
+  <java-symbol type="attr" name="closeItemLayout" />
 </resources>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 2296a12..ab5cd5a 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -306,7 +306,7 @@
         <item name="actionOverflowMenuStyle">@style/Widget.Material.PopupMenu.Overflow</item>
         <item name="actionModeBackground">@drawable/cab_background_top_material</item>
         <item name="actionModeSplitBackground">@drawable/cab_background_bottom_material</item>
-        <item name="actionModeCloseDrawable">@drawable/ic_cab_done_material</item>
+        <item name="actionModeCloseDrawable">@drawable/ic_ab_back_material</item>
         <item name="actionBarTabStyle">@style/Widget.Material.ActionBar.TabView</item>
         <item name="actionBarTabBarStyle">@style/Widget.Material.ActionBar.TabBar</item>
         <item name="actionBarTabTextStyle">@style/Widget.Material.ActionBar.TabText</item>
@@ -652,7 +652,7 @@
         <item name="actionOverflowMenuStyle">@style/Widget.Material.Light.PopupMenu.Overflow</item>
         <item name="actionModeBackground">@drawable/cab_background_top_material</item>
         <item name="actionModeSplitBackground">@drawable/cab_background_bottom_material</item>
-        <item name="actionModeCloseDrawable">@drawable/ic_cab_done_material</item>
+        <item name="actionModeCloseDrawable">@drawable/ic_ab_back_material</item>
         <item name="actionBarTabStyle">@style/Widget.Material.Light.ActionBar.TabView</item>
         <item name="actionBarTabBarStyle">@style/Widget.Material.Light.ActionBar.TabBar</item>
         <item name="actionBarTabTextStyle">@style/Widget.Material.Light.ActionBar.TabText</item>
diff --git a/core/tests/ConnectivityManagerTest/assets/accesspoints.xml b/core/tests/ConnectivityManagerTest/assets/accesspoints.xml
deleted file mode 100644
index ce6eebc..0000000
--- a/core/tests/ConnectivityManagerTest/assets/accesspoints.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-  <accesspoint>
-    <ssid>opennet</ssid>
-    <security>NONE</security>
-  </accesspoint>
-  <accesspoint>
-    <ssid>GoogleGuest</ssid>
-    <security>NONE</security>
-  </accesspoint>
-  <accesspoint>
-    <ssid>securenetdhcp</ssid>
-    <security>PSK</security>
-    <password>androidwifi</password>
-  </accesspoint>
-  <accesspoint>
-    <ssid>securenetstatic</ssid>
-    <security>PSK</security>
-    <password>androidwifi</password>
-    <ip>192.168.14.2</ip>
-    <gateway>192.168.14.1</gateway>
-    <networkprefixlength>24</networkprefixlength>
-    <dns1>192.168.14.1</dns1>
-    <dns2>192.168.1.9</dns2>
-  </accesspoint>
-<!-- TODO: This AP is outdated and only supports 2.4GHz.
-           Need to switch to a new dual-band AP.
-           Enable this test case again once the configuration is completed.
-     bug#: 9470594
-  <accesspoint>
-    <ssid>botnet</ssid>
-    <security>EAP</security>
-    <eap>PEAP</eap>
-    <phase2>MSCHAPV2</phase2>
-    <identity>donut</identity>
-    <password>android</password>
-  </accesspoint>
--->
-</resources>
-
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
deleted file mode 100644
index 1222c8b..0000000
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- * Copyright (C) 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.connectivitymanagertest;
-
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-
-import org.xml.sax.Attributes;
-import org.xml.sax.SAXException;
-import org.xml.sax.helpers.DefaultHandler;
-
-import android.net.IpConfiguration.IpAssignment;
-import android.net.IpConfiguration.ProxySettings;
-import android.net.LinkAddress;
-import android.net.RouteInfo;
-import android.net.StaticIpConfiguration;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiConfiguration.AuthAlgorithm;
-import android.net.wifi.WifiConfiguration.KeyMgmt;
-import android.net.wifi.WifiEnterpriseConfig;
-
-import java.io.InputStream;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.List;
-
-
-/**
- * Help class to process configurations of access points saved in an XML file.
- * The configurations of an access point is included in tag
- * <accesspoint></accesspoint>. The supported configuration includes: ssid,
- * security, eap, phase2, identity, password, anonymousidentity, cacert, usercert,
- * in which each is included in the corresponding tags. Static IP setting is also supported.
- * Tags that can be used include: ip, gateway, networkprefixlength, dns1, dns2. All access points
- * have to be enclosed in tags of <resources></resources>.
- *
- * The following is a sample configuration file for an access point using EAP-PEAP with MSCHAP2.
- * <resources>
- *   <accesspoint>
- *   <ssid>testnet</ssid>
- *   <security>EAP</security>
- *   <eap>PEAP</eap>
- *   <phase2>MSCHAP2</phase2>
- *   <identity>donut</identity</identity>
- *   <password>abcdefgh</password>
- *   </accesspoint>
- * </resources>
- *
- * Note:ssid and security have to be the first two tags
- *      for static ip setting, tag "ip" should be listed before other fields: dns, gateway,
- *      networkprefixlength.
- */
-public class AccessPointParserHelper {
-    static final int NONE = 0;
-    static final int WEP = 1;
-    static final int PSK = 2;
-    static final int EAP = 3;
-
-    List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>();
-
-    private int getSecurityType (String security) {
-        if (security.equalsIgnoreCase("NONE")) {
-            return NONE;
-        } else if (security.equalsIgnoreCase("WEP")) {
-            return WEP;
-        } else if (security.equalsIgnoreCase("PSK")) {
-            return PSK;
-        } else if (security.equalsIgnoreCase("EAP")) {
-            return EAP;
-        } else {
-            return -1;
-        }
-    }
-
-    private boolean validateEapValue(String value) {
-        if (value.equalsIgnoreCase("PEAP") ||
-                value.equalsIgnoreCase("TLS") ||
-                value.equalsIgnoreCase("TTLS")) {
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    DefaultHandler mHandler = new DefaultHandler() {
-
-        boolean ssid = false;
-        boolean security = false;
-        boolean password = false;
-        boolean ip = false;
-        boolean gateway = false;
-        boolean networkprefix = false;
-        boolean dns1 = false;
-        boolean dns2 = false;
-        boolean eap = false;
-        boolean phase2 = false;
-        boolean identity = false;
-        boolean anonymousidentity = false;
-        boolean cacert = false;
-        boolean usercert = false;
-        WifiConfiguration config = null;
-        int securityType = NONE;
-        StaticIpConfiguration mStaticIpConfiguration = null;
-        InetAddress mInetAddr = null;
-
-        @Override
-        public void startElement(String uri, String localName, String tagName,
-                Attributes attributes) throws SAXException {
-            if (tagName.equalsIgnoreCase("accesspoint")) {
-                config = new WifiConfiguration();
-            }
-            if (tagName.equalsIgnoreCase("ssid")) {
-                ssid = true;
-            }
-            if (tagName.equalsIgnoreCase("security")) {
-                security = true;
-            }
-            if (tagName.equalsIgnoreCase("password")) {
-                password = true;
-            }
-            if (tagName.equalsIgnoreCase("eap")) {
-                eap = true;
-            }
-            if (tagName.equalsIgnoreCase("phase2")) {
-                phase2 = true;
-            }
-            if (tagName.equalsIgnoreCase("identity")) {
-                identity = true;
-            }
-            if (tagName.equalsIgnoreCase("anonymousidentity")) {
-                anonymousidentity = true;
-            }
-            if (tagName.equalsIgnoreCase("cacert")) {
-                cacert = true;
-            }
-            if (tagName.equalsIgnoreCase("usercert")) {
-                usercert = true;
-            }
-            if (tagName.equalsIgnoreCase("ip")) {
-                mStaticIpConfiguration = new StaticIpConfiguration();
-                ip = true;
-            }
-            if (tagName.equalsIgnoreCase("gateway")) {
-                gateway = true;
-            }
-            if (tagName.equalsIgnoreCase("networkprefixlength")) {
-                networkprefix = true;
-            }
-            if (tagName.equalsIgnoreCase("dns1")) {
-                dns1 = true;
-            }
-            if (tagName.equalsIgnoreCase("dns2")) {
-                dns2 = true;
-            }
-        }
-
-        @Override
-        public void endElement(String uri, String localName, String tagName) throws SAXException {
-            if (tagName.equalsIgnoreCase("accesspoint")) {
-                if (mStaticIpConfiguration != null) {
-                    config.setIpAssignment(IpAssignment.STATIC);
-                    config.setStaticIpConfiguration(mStaticIpConfiguration);
-                } else {
-                    config.setIpAssignment(IpAssignment.DHCP);
-                }
-                config.setProxySettings(ProxySettings.NONE);
-                networks.add(config);
-                mStaticIpConfiguration = null;
-            }
-        }
-
-        @Override
-        public void characters(char ch[], int start, int length) throws SAXException {
-            if (ssid) {
-                config.SSID = new String(ch, start, length);
-                ssid = false;
-            }
-            if (security) {
-                String securityStr = (new String(ch, start, length)).toUpperCase();
-                securityType = getSecurityType(securityStr);
-                switch (securityType) {
-                    case NONE:
-                        config.allowedKeyManagement.set(KeyMgmt.NONE);
-                        break;
-                    case WEP:
-                        config.allowedKeyManagement.set(KeyMgmt.NONE);
-                        config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
-                        config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
-                        break;
-                    case PSK:
-                        config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
-                        break;
-                    case EAP:
-                        config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
-                        config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
-                        // Initialize other fields.
-                        config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.NONE);
-                        config.enterpriseConfig.setCaCertificateAlias("");
-                        config.enterpriseConfig.setClientCertificateAlias("");
-                        config.enterpriseConfig.setIdentity("");
-                        config.enterpriseConfig.setAnonymousIdentity("");
-                        break;
-                    default:
-                        throw new SAXException();
-                }
-                security = false;
-            }
-            if (password) {
-                String passwordStr = new String(ch, start, length);
-                int len = passwordStr.length();
-                if (len == 0) {
-                    throw new SAXException();
-                }
-                if (securityType == WEP) {
-                    if ((len == 10 || len == 26 || len == 58) &&
-                            passwordStr.matches("[0-9A-Fa-f]*")) {
-                        config.wepKeys[0] = passwordStr;
-                    } else {
-                        config.wepKeys[0] = '"' + passwordStr + '"';
-                    }
-                } else if (securityType == PSK) {
-                    if (passwordStr.matches("[0-9A-Fa-f]{64}")) {
-                        config.preSharedKey = passwordStr;
-                    } else {
-                        config.preSharedKey = '"' + passwordStr + '"';
-                    }
-                } else if (securityType == EAP) {
-                    config.enterpriseConfig.setPassword(passwordStr);
-                } else {
-                    throw new SAXException();
-                }
-                password = false;
-            }
-            if (eap) {
-                String eapValue = new String(ch, start, length);
-                if (!validateEapValue(eapValue)) {
-                    throw new SAXException();
-                }
-                if (eapValue.equals("TLS")) {
-                    config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
-                } else if (eapValue.equals("TTLS")) {
-                    config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TTLS);
-                } else if (eapValue.equals("PEAP")) {
-                    config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.PEAP);
-                }
-                eap = false;
-            }
-            if (phase2) {
-                String phase2Value = new String(ch, start, length);
-                if (phase2Value.equals("PAP")) {
-                    config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.PAP);
-                } else if (phase2Value.equals("MSCHAP")) {
-                    config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.MSCHAP);
-                } else if (phase2Value.equals("MSCHAPV2")) {
-                    config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.MSCHAPV2);
-                } else if (phase2Value.equals("GTC")) {
-                    config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.GTC);
-                }
-                phase2 = false;
-            }
-            if (identity) {
-                String identityValue = new String(ch, start, length);
-                config.enterpriseConfig.setIdentity(identityValue);
-                identity = false;
-            }
-            if (anonymousidentity) {
-                String anonyId = new String(ch, start, length);
-                config.enterpriseConfig.setAnonymousIdentity(anonyId);
-                anonymousidentity = false;
-            }
-            if (cacert) {
-                String cacertValue = new String(ch, start, length);
-                config.enterpriseConfig.setCaCertificateAlias(cacertValue);
-                cacert = false;
-            }
-            if (usercert) {
-                String usercertValue = new String(ch, start, length);
-                config.enterpriseConfig.setClientCertificateAlias(usercertValue);
-                usercert = false;
-            }
-            if (ip) {
-                try {
-                    String ipAddr = new String(ch, start, length);
-                    if (!InetAddress.isNumeric(ipAddr)) {
-                        throw new SAXException();
-                    }
-                    mInetAddr = InetAddress.getByName(ipAddr);
-                } catch (UnknownHostException e) {
-                    throw new SAXException();
-                }
-                ip = false;
-            }
-            if (gateway) {
-                try {
-                    String gwAddr = new String(ch, start, length);
-                    if (!InetAddress.isNumeric(gwAddr)) {
-                        throw new SAXException();
-                    }
-                    mStaticIpConfiguration.gateway = InetAddress.getByName(gwAddr);
-                } catch (UnknownHostException e) {
-                    throw new SAXException();
-                }
-                gateway = false;
-            }
-            if (networkprefix) {
-                try {
-                    int nwPrefixLength = Integer.parseInt(new String(ch, start, length));
-                    if ((nwPrefixLength < 0) || (nwPrefixLength > 32)) {
-                        throw new SAXException();
-                    }
-                    mStaticIpConfiguration.ipAddress = new LinkAddress(mInetAddr, nwPrefixLength);
-                } catch (NumberFormatException e) {
-                    throw new SAXException();
-                }
-                networkprefix = false;
-            }
-            if (dns1) {
-                try {
-                    String dnsAddr = new String(ch, start, length);
-                    if (!InetAddress.isNumeric(dnsAddr)) {
-                        throw new SAXException();
-                    }
-                    mStaticIpConfiguration.dnsServers.add(InetAddress.getByName(dnsAddr));
-                } catch (UnknownHostException e) {
-                    throw new SAXException();
-                }
-                dns1 = false;
-            }
-            if (dns2) {
-                try {
-                    String dnsAddr = new String(ch, start, length);
-                    if (!InetAddress.isNumeric(dnsAddr)) {
-                        throw new SAXException();
-                    }
-                    mStaticIpConfiguration.dnsServers.add(InetAddress.getByName(dnsAddr));
-                } catch (UnknownHostException e) {
-                    throw new SAXException();
-                }
-                dns2 = false;
-            }
-        }
-    };
-
-    /**
-     * Process the InputStream in
-     * @param in is the InputStream that can be used for XML parsing
-     * @throws Exception
-     */
-    public AccessPointParserHelper(InputStream in) throws Exception {
-        SAXParserFactory factory = SAXParserFactory.newInstance();
-        SAXParser saxParser = factory.newSAXParser();
-        saxParser.parse(in, mHandler);
-    }
-
-    public List<WifiConfiguration> getNetworkConfigurations() throws Exception {
-        return networks;
-    }
-}
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java
index 0f9d8e9..a3c5351 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java
@@ -26,7 +26,6 @@
 import android.net.NetworkInfo.State;
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiConfiguration.KeyMgmt;
 import android.net.wifi.WifiManager;
 import android.os.PowerManager;
 import android.os.SystemClock;
@@ -35,10 +34,8 @@
 import android.view.KeyEvent;
 
 import java.io.IOException;
-import java.io.InputStream;
 import java.net.UnknownHostException;
 import java.util.List;
-import java.util.regex.Pattern;
 
 
 /**
@@ -52,8 +49,6 @@
  */
 public class ConnectivityManagerTestBase extends InstrumentationTestCase {
 
-    private static final String LOG_TAG = "ConnectivityManagerTestBase";
-    private static final String ACCESS_POINT_FILE = "accesspoints.xml";
     private static final String PING_IP_ADDR = "8.8.8.8";
 
     protected static final int WAIT_FOR_SCAN_RESULT = 10 * 1000; //10 seconds
@@ -69,9 +64,10 @@
     protected static final int FAILURE = 1;
     protected static final int INIT = -1;
 
+    protected final String mLogTag;
+
     private ConnectivityReceiver mConnectivityReceiver = null;
     private WifiReceiver mWifiReceiver = null;
-    private AccessPointParserHelper mParseHelper = null;
 
     private long mLastConnectivityChangeTime = -1;
     protected ConnectivityManager mCm;
@@ -82,6 +78,11 @@
     /* Control Wifi States */
     public WifiManager mWifiManager;
 
+    public ConnectivityManagerTestBase(String logTag) {
+        super();
+        mLogTag = logTag;
+    }
+
     protected long getLastConnectivityChangeTime() {
         return mLastConnectivityChangeTime;
     }
@@ -94,7 +95,7 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             mLastConnectivityChangeTime = SystemClock.uptimeMillis();
-            log("ConnectivityReceiver: " + intent);
+            logv("ConnectivityReceiver: " + intent);
             String action = intent.getAction();
             if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
                 Log.v("ConnectivityReceiver", "onReceive() called with " + intent);
@@ -108,7 +109,7 @@
             String action = intent.getAction();
             Log.v("WifiReceiver", "onReceive() is calleld with " + intent);
             if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
-                log("scan results are available");
+                logv("scan results are available");
                 synchronized (mWifiScanResultLock) {
                     mLastScanResult = mWifiManager.getScanResults();
                     mWifiScanResultLock.notifyAll();
@@ -130,7 +131,7 @@
         if (mWifiManager.isWifiApEnabled()) {
             // if soft AP is enabled, disable it
             mWifiManager.setWifiApEnabled(null, false);
-            log("Disable soft ap");
+            logv("Disable soft ap");
         }
 
         // register a connectivity receiver for CONNECTIVITY_ACTION;
@@ -148,32 +149,25 @@
         mIntentFilter.addAction(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
         mContext.registerReceiver(mWifiReceiver, mIntentFilter);
 
-        log("Clear Wifi before we start the test.");
+        logv("Clear Wifi before we start the test.");
         removeConfiguredNetworksAndDisableWifi();
      }
 
-    protected List<WifiConfiguration> loadNetworkConfigurations() throws Exception {
-        InputStream in = mContext.getAssets().open(ACCESS_POINT_FILE);
-        mParseHelper = new AccessPointParserHelper(in);
-        return mParseHelper.getNetworkConfigurations();
-    }
-
     // wait for network connectivity state: CONNECTING, CONNECTED, SUSPENDED, DISCONNECTING,
     //                                      DISCONNECTED, UNKNOWN
     protected boolean waitForNetworkState(int networkType, State expectedState, long timeout) {
         long startTime = SystemClock.uptimeMillis();
         while (true) {
             NetworkInfo ni = mCm.getNetworkInfo(networkType);
-            String niString = ni == null ? "null" : ni.toString();
             if (ni != null && expectedState.equals(ni.getState())) {
-                log("waitForNetworkState success: " + niString);
+                logv("waitForNetworkState success: %s", ni);
                 return true;
             }
             if ((SystemClock.uptimeMillis() - startTime) > timeout) {
-                log("waitForNetworkState timeout: " + niString);
+                logv("waitForNetworkState timeout: %s", ni);
                 return false;
             }
-            log("waitForNetworkState interim: " + niString);
+            logv("waitForNetworkState interim: %s", ni);
             SystemClock.sleep(SHORT_TIMEOUT);
         }
     }
@@ -185,16 +179,14 @@
         while (true) {
             int state = mWifiManager.getWifiState();
             if (state == expectedState) {
-                log("waitForWifiState success: state=" + state);
+                logv("waitForWifiState success: state=" + state);
                 return true;
             }
             if ((SystemClock.uptimeMillis() - startTime) > timeout) {
-                log(String.format("waitForWifiState timeout: expected=%d, actual=%d",
-                        expectedState, state));
+                logv("waitForWifiState timeout: expected=%d, actual=%d", expectedState, state);
                 return false;
             }
-            log(String.format("waitForWifiState interim: expected=%d, actual=%d",
-                    expectedState, state));
+            logv("waitForWifiState interim: expected=%d, actual=%d", expectedState, state);
             SystemClock.sleep(SHORT_TIMEOUT);
         }
     }
@@ -206,15 +198,15 @@
         while (true) {
             int state = mWifiManager.getWifiApState();
             if (state == expectedState) {
-                log("waitForWifiAPState success: state=" + state);
+                logv("waitForWifiAPState success: state=" + state);
                 return true;
             }
             if ((SystemClock.uptimeMillis() - startTime) > timeout) {
-                log(String.format("waitForWifiAPState timeout: expected=%d, actual=%d",
+                logv(String.format("waitForWifiAPState timeout: expected=%d, actual=%d",
                         expectedState, state));
                 return false;
             }
-            log(String.format("waitForWifiAPState interim: expected=%d, actual=%d",
+            logv(String.format("waitForWifiAPState interim: expected=%d, actual=%d",
                     expectedState, state));
             SystemClock.sleep(SHORT_TIMEOUT);
         }
@@ -269,7 +261,7 @@
 
     // Turn screen off
     protected void turnScreenOff() {
-        log("Turn screen off");
+        logv("Turn screen off");
         PowerManager pm =
             (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         pm.goToSleep(SystemClock.uptimeMillis());
@@ -277,7 +269,7 @@
 
     // Turn screen on
     protected void turnScreenOn() {
-        log("Turn screen on");
+        logv("Turn screen on");
         PowerManager pm =
                 (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         pm.wakeUp(SystemClock.uptimeMillis());
@@ -305,7 +297,7 @@
                 // assume the chance that all servers are down is very small
                 for (int i = 0; i < hostList.length; i++ ) {
                     String host = hostList[i];
-                    log("Start ping test, ping " + host);
+                    logv("Start ping test, ping " + host);
                     Process p = Runtime.getRuntime().exec("ping -c 10 -w 100 " + host);
                     int status = p.waitFor();
                     if (status == 0) {
@@ -314,11 +306,11 @@
                     }
                 }
             } catch (UnknownHostException e) {
-                log("Ping test Fail: Unknown Host");
+                logv("Ping test Fail: Unknown Host");
             } catch (IOException e) {
-                log("Ping test Fail:  IOException");
+                logv("Ping test Fail:  IOException");
             } catch (InterruptedException e) {
-                log("Ping test Fail: InterruptedException");
+                logv("Ping test Fail: InterruptedException");
             }
         }
         // ping test timeout
@@ -331,29 +323,22 @@
      * We don't verify whether the connection is successful or not, leave this to the test
      */
     protected boolean connectToWifi(String knownSSID) {
-        WifiConfiguration config = new WifiConfiguration();
-        config.SSID = knownSSID;
-        config.allowedKeyManagement.set(KeyMgmt.NONE);
+        WifiConfiguration config = WifiConfigurationHelper.createOpenConfig(knownSSID);
         return connectToWifiWithConfiguration(config);
     }
 
     /**
      * Connect to Wi-Fi with the given configuration. Note the SSID in the configuration
      * is pure string, we need to convert it to quoted string.
-     * @param config
-     * @return
      */
     protected boolean connectToWifiWithConfiguration(WifiConfiguration config) {
-        String ssid = config.SSID;
-        config.SSID = convertToQuotedString(ssid);
-
         // If Wifi is not enabled, enable it
         if (!mWifiManager.isWifiEnabled()) {
-            log("Wifi is not enabled, enable it");
+            logv("Wifi is not enabled, enable it");
             mWifiManager.setWifiEnabled(true);
             // wait for the wifi state change before start scanning.
             if (!waitForWifiState(WifiManager.WIFI_STATE_ENABLED, LONG_TIMEOUT)) {
-                log("wait for WIFI_STATE_ENABLED failed");
+                logv("wait for WIFI_STATE_ENABLED failed");
                 return false;
             }
         }
@@ -361,10 +346,13 @@
         // Save network configuration and connect to network without scanning
         mWifiManager.connect(config,
             new WifiManager.ActionListener() {
+                @Override
                 public void onSuccess() {
                 }
+
+                @Override
                 public void onFailure(int reason) {
-                    log("connect failure " + reason);
+                    logv("connect failure " + reason);
                 }
             });
         return true;
@@ -376,25 +364,28 @@
     protected boolean disconnectAP() {
         // remove saved networks
         if (!mWifiManager.isWifiEnabled()) {
-            log("Enabled wifi before remove configured networks");
+            logv("Enabled wifi before remove configured networks");
             mWifiManager.setWifiEnabled(true);
             SystemClock.sleep(SHORT_TIMEOUT);
         }
 
         List<WifiConfiguration> wifiConfigList = mWifiManager.getConfiguredNetworks();
         if (wifiConfigList == null) {
-            log("no configuration list is null");
+            logv("no configuration list is null");
             return true;
         }
-        log("size of wifiConfigList: " + wifiConfigList.size());
+        logv("size of wifiConfigList: " + wifiConfigList.size());
         for (WifiConfiguration wifiConfig: wifiConfigList) {
-            log("remove wifi configuration: " + wifiConfig.networkId);
+            logv("remove wifi configuration: " + wifiConfig.networkId);
             int netId = wifiConfig.networkId;
             mWifiManager.forget(netId, new WifiManager.ActionListener() {
+                    @Override
                     public void onSuccess() {
                     }
+
+                    @Override
                     public void onFailure(int reason) {
-                        log("Failed to forget " + reason);
+                        logv("Failed to forget " + reason);
                     }
                 });
         }
@@ -431,15 +422,14 @@
         long startTime = SystemClock.uptimeMillis();
         while (true) {
             NetworkInfo ni = mCm.getActiveNetworkInfo();
-            String niString = ni == null ? "null" : ni.toString();
             if (ni != null && ni.isConnected()) {
                 return true;
             }
             if ((SystemClock.uptimeMillis() - startTime) > timeout) {
-                log("waitForActiveNetworkConnection timeout: " + niString);
+                logv("waitForActiveNetworkConnection timeout: %s", ni);
                 return false;
             }
-            log("waitForActiveNetworkConnection interim: " + niString);
+            logv("waitForActiveNetworkConnection interim: %s", ni);
             SystemClock.sleep(SHORT_TIMEOUT);
         }
     }
@@ -451,12 +441,11 @@
             if (ni == null) {
                 return true;
             }
-            String niString = ni.toString();
             if ((SystemClock.uptimeMillis() - startTime) > timeout) {
-                log("waitForActiveNetworkConnection timeout: " + niString);
+                logv("waitForActiveNetworkConnection timeout: %s", ni);
                 return false;
             }
-            log("waitForActiveNetworkConnection interim: " + niString);
+            logv("waitForActiveNetworkConnection interim: %s", ni);
             SystemClock.sleep(SHORT_TIMEOUT);
         }
     }
@@ -467,12 +456,9 @@
         try {
             Process proc = Runtime.getRuntime().exec(new String[]{
                     "/system/bin/ping", "-W", "30", "-c", "1", PING_IP_ADDR});
-            int exitCode = proc.waitFor();
-            return exitCode == 0;
-        } catch (InterruptedException ie) {
-            Log.e(LOG_TAG, "InterruptedException while waiting for ping");
-        } catch (IOException ioe) {
-            Log.e(LOG_TAG, "IOException during ping", ioe);
+            return proc.waitFor() == 0;
+        } catch (InterruptedException | IOException e) {
+            Log.e(mLogTag, "Ping failed", e);
         }
         return false;
     }
@@ -489,8 +475,8 @@
         super.tearDown();
     }
 
-    private void log(String message) {
-        Log.v(LOG_TAG, message);
+    protected void logv(String format, Object... args) {
+        Log.v(mLogTag, String.format(format, args));
     }
 
     /**
@@ -506,22 +492,10 @@
         // step 2: verify Wifi state and network state;
         assertTrue("wifi state not connected with " + config.SSID,
                 waitForNetworkState(ConnectivityManager.TYPE_WIFI,
-                State.CONNECTED, LONG_TIMEOUT));
+                State.CONNECTED, WIFI_CONNECTION_TIMEOUT));
 
         // step 3: verify the current connected network is the given SSID
         assertNotNull("no active wifi info", mWifiManager.getConnectionInfo());
         assertEquals("SSID mismatch", config.SSID, mWifiManager.getConnectionInfo().getSSID());
     }
-
-    /**
-     * checks if the input is a hexadecimal string of given length
-     *
-     * @param input string to be checked
-     * @param length required length of the string
-     * @return
-     */
-    protected static boolean isHex(String input, int length) {
-        Pattern p = Pattern.compile(String.format("[0-9A-Fa-f]{%d}", length));
-        return p.matcher(input).matches();
-    }
 }
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/WifiConfigurationHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/WifiConfigurationHelper.java
new file mode 100644
index 0000000..f0a8367
--- /dev/null
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/WifiConfigurationHelper.java
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.connectivitymanagertest;
+
+import android.net.IpConfiguration.IpAssignment;
+import android.net.IpConfiguration.ProxySettings;
+import android.net.LinkAddress;
+import android.net.StaticIpConfiguration;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiConfiguration.AuthAlgorithm;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.net.wifi.WifiEnterpriseConfig;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Helper for dealing with creating {@link WifiConfiguration} objects.
+ */
+public class WifiConfigurationHelper {
+    private static final int NONE = 0;
+    private static final int WEP = 1;
+    private static final int PSK = 2;
+    private static final int EAP = 3;
+
+    /**
+     * Private constructor since this a static class.
+     */
+    private WifiConfigurationHelper() {}
+
+    /**
+     * Create a {@link WifiConfiguration} for an open network
+     *
+     * @param ssid The SSID of the wifi network
+     * @return The {@link WifiConfiguration}
+     */
+    public static WifiConfiguration createOpenConfig(String ssid) {
+        WifiConfiguration config = createGenericConfig(ssid);
+
+        config.allowedKeyManagement.set(KeyMgmt.NONE);
+        return config;
+    }
+
+    /**
+     * Create a {@link WifiConfiguration} for a WEP secured network
+     *
+     * @param ssid The SSID of the wifi network
+     * @param password Either a 10, 26, or 58 character hex string or the plain text password
+     * @return The {@link WifiConfiguration}
+     */
+    public static WifiConfiguration createWepConfig(String ssid, String password) {
+        WifiConfiguration config = createGenericConfig(ssid);
+
+        if (isHex(password, 10) || isHex(password, 26) || isHex(password, 58)) {
+            config.wepKeys[0] = password;
+        } else {
+            config.wepKeys[0] = quotedString(password);
+        }
+
+        config.allowedKeyManagement.set(KeyMgmt.NONE);
+        config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
+        config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
+        return config;
+    }
+
+    /**
+     * Create a {@link WifiConfiguration} for a PSK secured network
+     *
+     * @param ssid The SSID of the wifi network
+     * @param password Either a 64 character hex string or the plain text password
+     * @return The {@link WifiConfiguration}
+     */
+    public static WifiConfiguration createPskConfig(String ssid, String password) {
+        WifiConfiguration config = createGenericConfig(ssid);
+
+        if (isHex(password, 64)) {
+            config.preSharedKey = password;
+        } else {
+            config.preSharedKey = quotedString(password);
+        }
+        config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
+        return config;
+    }
+
+    /**
+     * Create a {@link WifiConfiguration} for an EAP secured network
+     *
+     * @param ssid The SSID of the wifi network
+     * @param password The password
+     * @param eapMethod The EAP method
+     * @param phase2 The phase 2 method or null
+     * @param identity The identity or null
+     * @param anonymousIdentity The anonymous identity or null
+     * @param caCert The CA certificate or null
+     * @param clientCert The client certificate or null
+     * @return The {@link WifiConfiguration}
+     */
+    public static WifiConfiguration createEapConfig(String ssid, String password, int eapMethod,
+            Integer phase2, String identity, String anonymousIdentity, String caCert,
+            String clientCert) {
+        WifiConfiguration config = new WifiConfiguration();
+        config.SSID = quotedString(ssid);
+
+        config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
+        config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
+
+        // Set defaults
+        if (phase2 == null) phase2 = WifiEnterpriseConfig.Phase2.NONE;
+        if (identity == null) identity = "";
+        if (anonymousIdentity == null) anonymousIdentity = "";
+        if (caCert == null) caCert = "";
+        if (clientCert == null) clientCert = "";
+
+        config.enterpriseConfig.setPassword(password);
+        config.enterpriseConfig.setEapMethod(eapMethod);
+        config.enterpriseConfig.setPhase2Method(phase2);
+        config.enterpriseConfig.setIdentity(identity);
+        config.enterpriseConfig.setAnonymousIdentity(anonymousIdentity);
+        config.enterpriseConfig.setCaCertificateAlias(caCert);
+        config.enterpriseConfig.setClientCertificateAlias(clientCert);
+        return config;
+    }
+
+    /**
+     * Create a generic {@link WifiConfiguration} used by the other create methods.
+     */
+    private static WifiConfiguration createGenericConfig(String ssid) {
+        WifiConfiguration config = new WifiConfiguration();
+        config.SSID = quotedString(ssid);
+        config.setIpAssignment(IpAssignment.DHCP);
+        config.setProxySettings(ProxySettings.NONE);
+        return config;
+    }
+
+    /**
+     * Parse a JSON string for WiFi configurations stored as a JSON string.
+     * <p>
+     * This json string should be a list of dictionaries, with each dictionary containing a single
+     * wifi configuration. The wifi configuration requires the fields "ssid" and "security" with
+     * security being one of NONE, WEP, PSK, or EAP. If WEP, PSK, or EAP are selected, the field
+     * "password" must also be provided.  If EAP is selected, then the fiels "eap", "phase2",
+     * "identity", "ananymous_identity", "ca_cert", and "client_cert" are also required. Lastly,
+     * static IP settings are also supported.  If the field "ip" is set, then the fields "gateway",
+     * "prefix_length", "dns1", and "dns2" are required.
+     * </p>
+     * @throws IllegalArgumentException if the input string was not valid JSON or if any mandatory
+     * fields are missing.
+     */
+    public static List<WifiConfiguration> parseJson(String in) {
+        try {
+            JSONArray jsonConfigs = new JSONArray(in);
+            List<WifiConfiguration> wifiConfigs = new ArrayList<>(jsonConfigs.length());
+
+            for (int i = 0; i < jsonConfigs.length(); i++) {
+                JSONObject jsonConfig = jsonConfigs.getJSONObject(i);
+
+                wifiConfigs.add(getWifiConfiguration(jsonConfig));
+            }
+            return wifiConfigs;
+        } catch (JSONException e) {
+            throw new IllegalArgumentException(e);
+        }
+    }
+
+    /**
+     * Parse a {@link JSONObject} and return the wifi configuration.
+     *
+     * @throws IllegalArgumentException if any mandatory fields are missing.
+     */
+    private static WifiConfiguration getWifiConfiguration(JSONObject jsonConfig)
+            throws JSONException {
+        String ssid = jsonConfig.getString("ssid");
+        String password = null;
+        WifiConfiguration config;
+
+        int securityType = getSecurityType(jsonConfig.getString("security"));
+        switch (securityType) {
+            case NONE:
+                config = createOpenConfig(ssid);
+                break;
+            case WEP:
+                password = jsonConfig.getString("password");
+                config = createWepConfig(ssid, password);
+                break;
+            case PSK:
+                password = jsonConfig.getString("password");
+                config = createPskConfig(ssid, password);
+                break;
+            case EAP:
+                password = jsonConfig.getString("password");
+                int eapMethod = getEapMethod(jsonConfig.getString("eap"));
+                Integer phase2 = null;
+                if (jsonConfig.has("phase2")) {
+                    phase2 = getPhase2(jsonConfig.getString("phase2"));
+                }
+                String identity = null;
+                if (jsonConfig.has("identity")) {
+                    identity = jsonConfig.getString("identity");
+                }
+                String anonymousIdentity = null;
+                if (jsonConfig.has("anonymous_identity")) {
+                    anonymousIdentity = jsonConfig.getString("anonymous_identity");
+                }
+                String caCert = null;
+                if (jsonConfig.has("ca_cert")) {
+                    caCert = (jsonConfig.getString("ca_cert"));
+                }
+                String clientCert = null;
+                if (jsonConfig.has("client_cert")) {
+                    clientCert = jsonConfig.getString("client_cert");
+                }
+                config = createEapConfig(ssid, password, eapMethod, phase2, identity,
+                        anonymousIdentity, caCert, clientCert);
+                break;
+            default:
+                // Should never reach here as getSecurityType will already throw an exception
+                throw new IllegalArgumentException();
+        }
+
+        if (jsonConfig.has("ip")) {
+            StaticIpConfiguration staticIpConfig = new StaticIpConfiguration();
+
+            InetAddress ipAddress = getInetAddress(jsonConfig.getString("ip"));
+            int prefixLength = getPrefixLength(jsonConfig.getInt("prefix_length"));
+            staticIpConfig.ipAddress = new LinkAddress(ipAddress, prefixLength);
+            staticIpConfig.gateway = getInetAddress(jsonConfig.getString("gateway"));
+            staticIpConfig.dnsServers.add(getInetAddress(jsonConfig.getString("dns1")));
+            staticIpConfig.dnsServers.add(getInetAddress(jsonConfig.getString("dns2")));
+
+            config.setIpAssignment(IpAssignment.STATIC);
+            config.setStaticIpConfiguration(staticIpConfig);
+        } else {
+            config.setIpAssignment(IpAssignment.DHCP);
+        }
+
+        config.setProxySettings(ProxySettings.NONE);
+        return config;
+    }
+
+    private static String quotedString(String s) {
+        return String.format("\"%s\"", s);
+    }
+
+    /**
+     * Get the security type from a string.
+     *
+     * @throws IllegalArgumentException if the string is not a supported security type.
+     */
+    private static int getSecurityType(String security) {
+        if ("NONE".equalsIgnoreCase(security)) {
+            return NONE;
+        }
+        if ("WEP".equalsIgnoreCase(security)) {
+            return WEP;
+        }
+        if ("PSK".equalsIgnoreCase(security)) {
+            return PSK;
+        }
+        if ("EAP".equalsIgnoreCase(security)) {
+            return EAP;
+        }
+        throw new IllegalArgumentException("Security type must be one of NONE, WEP, PSK, or EAP");
+    }
+
+    /**
+     * Get the EAP method from a string.
+     *
+     * @throws IllegalArgumentException if the string is not a supported EAP method.
+     */
+    private static int getEapMethod(String eapMethod) {
+        if ("TLS".equalsIgnoreCase(eapMethod)) {
+            return WifiEnterpriseConfig.Eap.TLS;
+        }
+        if ("TTLS".equalsIgnoreCase(eapMethod)) {
+            return WifiEnterpriseConfig.Eap.TTLS;
+        }
+        if ("PEAP".equalsIgnoreCase(eapMethod)) {
+            return WifiEnterpriseConfig.Eap.PEAP;
+        }
+        throw new IllegalArgumentException("EAP method must be one of TLS, TTLS, or PEAP");
+    }
+
+    /**
+     * Get the phase 2 method from a string.
+     *
+     * @throws IllegalArgumentException if the string is not a supported phase 2 method.
+     */
+    private static int getPhase2(String phase2) {
+        if ("PAP".equalsIgnoreCase(phase2)) {
+            return WifiEnterpriseConfig.Phase2.PAP;
+        }
+        if ("MSCHAP".equalsIgnoreCase(phase2)) {
+            return WifiEnterpriseConfig.Phase2.MSCHAP;
+        }
+        if ("MSCHAPV2".equalsIgnoreCase(phase2)) {
+            return WifiEnterpriseConfig.Phase2.MSCHAPV2;
+        }
+        if ("GTC".equalsIgnoreCase(phase2)) {
+            return WifiEnterpriseConfig.Phase2.GTC;
+        }
+        throw new IllegalArgumentException("Phase2 must be one of PAP, MSCHAP, MSCHAPV2, or GTC");
+    }
+
+    /**
+     * Get an {@link InetAddress} from a string
+     *
+     * @throws IllegalArgumentException if the string is not a valid IP address.
+     */
+    private static InetAddress getInetAddress(String ipAddress) {
+        if (!InetAddress.isNumeric(ipAddress)) {
+            throw new IllegalArgumentException(
+                    String.format("IP address %s is not numeric", ipAddress));
+        }
+
+        try {
+            return InetAddress.getByName(ipAddress);
+        } catch (UnknownHostException e) {
+            throw new IllegalArgumentException(
+                    String.format("IP address %s could not be resolved", ipAddress));
+        }
+    }
+
+    /**
+     * Get the prefix length from an int.
+     *
+     * @throws IllegalArgumentException if the prefix length is less than 0 or greater than 32.
+     */
+    private static int getPrefixLength(int prefixLength) {
+        if (prefixLength < 0 || prefixLength > 32) {
+            throw new IllegalArgumentException("Prefix length cannot be less than 0 or more than 32");
+        }
+        return prefixLength;
+    }
+
+    /**
+     * Utility method to check if a given string is a hexadecimal string of given length
+     */
+    public static boolean isHex(String input, int length) {
+        if (input == null || length < 0) {
+            return false;
+        }
+        return input.matches(String.format("[0-9A-Fa-f]{%d}", length));
+    }
+}
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
index 01995c7..b280106 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
@@ -23,14 +23,15 @@
 import android.os.SystemClock;
 import android.provider.Settings;
 import android.test.suitebuilder.annotation.LargeTest;
-import android.util.Log;
 
 import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
 import com.android.connectivitymanagertest.ConnectivityManagerTestRunner;
 
-public class ConnectivityManagerMobileTest extends
-        ConnectivityManagerTestBase {
-    private static final String TAG = "ConnectivityManagerMobileTest";
+public class ConnectivityManagerMobileTest extends  ConnectivityManagerTestBase {
+
+    public ConnectivityManagerMobileTest() {
+        super(ConnectivityManagerMobileTest.class.getSimpleName());
+    }
 
     private String mTestAccessPoint;
     private boolean mWifiOnlyFlag;
@@ -46,7 +47,7 @@
         // Each test case will start with cellular connection
         if (Settings.Global.getInt(getInstrumentation().getContext().getContentResolver(),
                 Settings.Global.AIRPLANE_MODE_ON) == 1) {
-            log("airplane is not disabled, disable it.");
+            logv("airplane is not disabled, disable it.");
             mCm.setAirplaneMode(false);
         }
 
@@ -77,16 +78,14 @@
         assertTrue("not connected to cellular network", extraNetInfo.isConnected());
     }
 
-    private void log(String message) {
-        Log.v(TAG, message);
-    }
+
 
     // Test case 1: Test enabling Wifi without associating with any AP, no broadcast on network
     //              event should be expected.
     @LargeTest
     public void test3GToWifiNotification() {
         if (mWifiOnlyFlag) {
-            Log.v(TAG, getName() + " is excluded for wifi-only test");
+            logv(getName() + " is excluded for wifi-only test");
             return;
         }
 
@@ -225,7 +224,7 @@
     @LargeTest
     public void testDataConnectionWith3GToAmTo3G() {
         if (mWifiOnlyFlag) {
-            Log.v(TAG, getName() + " is excluded for wifi-only test");
+            logv(getName() + " is excluded for wifi-only test");
             return;
         }
         // disable wifi
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java
index eb75b0d..c2b80dc 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java
@@ -21,16 +21,15 @@
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiConfiguration.AuthAlgorithm;
 import android.net.wifi.WifiConfiguration.GroupCipher;
-import android.net.wifi.WifiConfiguration.KeyMgmt;
 import android.net.wifi.WifiConfiguration.PairwiseCipher;
 import android.net.wifi.WifiConfiguration.Protocol;
 import android.net.wifi.WifiInfo;
 import android.os.Bundle;
 import android.test.suitebuilder.annotation.LargeTest;
-import android.util.Log;
 
 import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
 import com.android.connectivitymanagertest.WifiAssociationTestRunner;
+import com.android.connectivitymanagertest.WifiConfigurationHelper;
 
 /**
  * Test Wi-Fi connection with different configuration
@@ -40,7 +39,6 @@
  * -w com.android.connectivitymanagertest/.WifiAssociationTestRunner"
  */
 public class WifiAssociationTest extends ConnectivityManagerTestBase {
-    private static final String TAG = "WifiAssociationTest";
     private String mSsid = null;
     private String mPassword = null;
     private String mSecurityType = null;
@@ -51,6 +49,10 @@
         OPEN, WEP64, WEP128, WPA_TKIP, WPA2_AES
     }
 
+    public WifiAssociationTest() {
+        super(WifiAssociationTest.class.getSimpleName());
+    }
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
@@ -77,90 +79,58 @@
     private void validateFrequencyBand() {
         if (mFrequencyBand != null) {
             int currentFreq = mWifiManager.getFrequencyBand();
-            Log.v(TAG, "read frequency band: " + currentFreq);
+            logv("read frequency band: " + currentFreq);
             assertEquals("specified frequency band does not match operational band of WifiManager",
                     currentFreq, mBand);
          }
     }
 
-    private void log(String message) {
-        Log.v(TAG, message);
-    }
-
     @LargeTest
     public void testWifiAssociation() {
         assertNotNull("no test ssid", mSsid);
-        WifiConfiguration config = new WifiConfiguration();
-        config.SSID = mSsid;
+        WifiConfiguration config = null;
         SECURITY_TYPE security = SECURITY_TYPE.valueOf(mSecurityType);
-        log("Security type is " + security.toString());
+        logv("Security type is " + security.toString());
         switch (security) {
             // set network configurations
             case OPEN:
-                config.allowedKeyManagement.set(KeyMgmt.NONE);
+                config = WifiConfigurationHelper.createOpenConfig(mSsid);
                 break;
             case WEP64:
                 assertNotNull("password is empty", mPassword);
-                config.allowedKeyManagement.set(KeyMgmt.NONE);
-                config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
-                config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
+                // always use hex pair for WEP-40
+                assertTrue(WifiConfigurationHelper.isHex(mPassword, 10));
+                config = WifiConfigurationHelper.createWepConfig(mSsid, mPassword);
                 config.allowedGroupCiphers.set(GroupCipher.WEP40);
-                if (mPassword != null) {
-                    // always use hex pair for WEP-40
-                    if (isHex(mPassword, 10)) {
-                        config.wepKeys[0] = mPassword;
-                    } else {
-                        fail("password should be 10-character hex");
-                    }
-                }
                 break;
             case WEP128:
                 assertNotNull("password is empty", mPassword);
-                config.allowedKeyManagement.set(KeyMgmt.NONE);
-                config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
-                config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
+                // always use hex pair for WEP-104
+                assertTrue(WifiConfigurationHelper.isHex(mPassword, 26));
+                config = WifiConfigurationHelper.createWepConfig(mSsid, mPassword);
                 config.allowedGroupCiphers.set(GroupCipher.WEP104);
-                if (mPassword != null) {
-                    // always use hex pair for WEP-104
-                    if (isHex(mPassword, 26)) {
-                        config.wepKeys[0] = mPassword;
-                    } else {
-                        fail("password should be 26-character hex");
-                    }
-                }
                 break;
             case WPA_TKIP:
                 assertNotNull("password is empty", mPassword);
-                config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
+                config = WifiConfigurationHelper.createPskConfig(mSsid, mPassword);
                 config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
                 config.allowedProtocols.set(Protocol.WPA);
                 config.allowedPairwiseCiphers.set(PairwiseCipher.TKIP);
                 config.allowedGroupCiphers.set(GroupCipher.TKIP);
-                if (isHex(mPassword, 64)) {
-                    config.preSharedKey = mPassword;
-                } else {
-                    config.preSharedKey = '"' + mPassword + '"';
-                }
                 break;
             case WPA2_AES:
                 assertNotNull("password is empty", mPassword);
-                config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
+                config = WifiConfigurationHelper.createPskConfig(mSsid, mPassword);
                 config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
                 config.allowedProtocols.set(Protocol.RSN);
                 config.allowedPairwiseCiphers.set(PairwiseCipher.CCMP);
                 config.allowedGroupCiphers.set(GroupCipher.CCMP);
-                config.allowedProtocols.set(Protocol.RSN);
-                if (isHex(mPassword, 64)) {
-                    config.preSharedKey = mPassword;
-                } else {
-                    config.preSharedKey = '"' + mPassword + '"';
-                }
                 break;
             default:
                 fail("Not a valid security type: " + mSecurityType);
                 break;
         }
-        Log.v(TAG, "network config: " + config.toString());
+        logv("network config: %s", config.toString());
         connectToWifi(config);
         // verify that connection actually works
         assertTrue("no network connectivity at end of test", checkNetworkConnectivity());
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
index 740ffb8..b37daa3 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
@@ -16,54 +16,38 @@
 
 package com.android.connectivitymanagertest.functional;
 
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo.State;
 import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiInfo;
+import android.os.SystemClock;
 import android.test.suitebuilder.annotation.LargeTest;
-import android.util.Log;
 
 import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
+import com.android.connectivitymanagertest.WifiConfigurationHelper;
 
-import java.util.ArrayList;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
 import java.util.List;
 
 /**
  * Test Wi-Fi connection with different configuration
  * To run this tests:
- *     adb shell am instrument -e class
- *          com.android.connectivitymanagertest.functional.WifiConnectionTest
- *          -w com.android.connectivitymanagertest/.ConnectivityManagerTestRunner
+ *     adb shell am instrument \
+ *         -e class com.android.connectivitymanagertest.functional.WifiConnectionTest \
+ *         -w com.android.connectivitymanagertest/.ConnectivityManagerTestRunner
  */
-public class WifiConnectionTest
-    extends ConnectivityManagerTestBase {
-    private static final String TAG = "WifiConnectionTest";
-    private static final boolean DEBUG = false;
-    private List<WifiConfiguration> mNetworks = new ArrayList<WifiConfiguration>();
+public class WifiConnectionTest extends ConnectivityManagerTestBase {
+    private static final String WIFI_CONFIG_FILE = "/data/wifi_configs.json";
+    private static final long PAUSE_DURATION_MS = 60 * 1000;
+
+    public WifiConnectionTest() {
+        super(WifiConnectionTest.class.getSimpleName());
+    }
 
     @Override
     public void setUp() throws Exception {
         super.setUp();
-        mNetworks = loadNetworkConfigurations();
-        if (DEBUG) {
-            printNetworkConfigurations();
-        }
-
-        // enable wifi and verify wpa_supplicant is started
-        assertTrue("enable Wifi failed", enableWifi());
-        assertTrue("wifi not connected", waitForNetworkState(
-                ConnectivityManager.TYPE_WIFI, State.CONNECTED, LONG_TIMEOUT));
-        WifiInfo wi = mWifiManager.getConnectionInfo();
-        assertNotNull("no active wifi info", wi);
-        assertTrue("failed to ping wpa_supplicant ", mWifiManager.pingSupplicant());
-    }
-
-    private void printNetworkConfigurations() {
-        log("==== print network configurations parsed from XML file ====");
-        log("number of access points: " + mNetworks.size());
-        for (WifiConfiguration config : mNetworks) {
-            log(config.toString());
-        }
+        assertTrue("Failed to enable wifi", enableWifi());
     }
 
     @Override
@@ -72,25 +56,67 @@
         super.tearDown();
     }
 
-    private void log(String message) {
-        Log.v(TAG, message);
-    }
-
     @LargeTest
     public void testWifiConnections() {
-        for (int i = 0; i < mNetworks.size(); i++) {
-            String ssid = mNetworks.get(i).SSID;
-            log("-- START Wi-Fi connection test to : " + ssid + " --");
-            connectToWifi(mNetworks.get(i));
-            // verify that connection actually works
-            assertTrue("no network connectivity at end of test", checkNetworkConnectivity());
-            log("-- END Wi-Fi connection test to " + ssid + " -- ");
-            log("pausing for 1 minute");
-            try {
-                Thread.sleep(60 * 1000);
-            } catch (InterruptedException e) {
-                // ignore
+        List<WifiConfiguration> wifiConfigs = loadConfigurations();
+
+        printWifiConfigurations(wifiConfigs);
+
+        assertFalse("No configurations to test against", wifiConfigs.isEmpty());
+
+        boolean shouldPause = false;
+        for (WifiConfiguration config : wifiConfigs) {
+            if (shouldPause) {
+                logv("Pausing for %d seconds", PAUSE_DURATION_MS / 1000);
+                SystemClock.sleep(PAUSE_DURATION_MS);
             }
+            logv("Start wifi connection test to: %s", config.SSID);
+            connectToWifi(config);
+
+            // verify that connection actually works
+            assertTrue("No connectivity at end of test", checkNetworkConnectivity());
+
+            // Disconnect and remove the network
+            assertTrue("Unable to remove network", disconnectAP());
+            logv("End wifi connection test to: %s", config.SSID);
+
+            shouldPause = true;
+        }
+    }
+
+    /**
+     * Load the configuration file from the root of the data partition
+     */
+    private List<WifiConfiguration> loadConfigurations() {
+        BufferedReader reader = null;
+        try {
+            reader = new BufferedReader(new FileReader(new File(WIFI_CONFIG_FILE)));
+            StringBuffer jsonBuffer = new StringBuffer();
+            String line;
+            while ((line = reader.readLine()) != null) {
+                jsonBuffer.append(line);
+            }
+            return WifiConfigurationHelper.parseJson(jsonBuffer.toString());
+        } catch (IllegalArgumentException | IOException e) {
+            throw new AssertionError("Error parsing file", e);
+        } finally {
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (IOException e) {
+                    // Ignore
+                }
+            }
+        }
+    }
+
+    /**
+     * Print the wifi configurations to test against.
+     */
+    private void printWifiConfigurations(List<WifiConfiguration> wifiConfigs) {
+        logv("Wifi configurations to be tested");
+        for (WifiConfiguration config : wifiConfigs) {
+            logv(config.toString());
         }
     }
 }
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
index aead65b..41f01e6 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
@@ -17,16 +17,15 @@
 package com.android.connectivitymanagertest.stress;
 
 
-import com.android.connectivitymanagertest.ConnectivityManagerStressTestRunner;
-import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
-
 import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiConfiguration.KeyMgmt;
 import android.net.wifi.WifiConfiguration.AuthAlgorithm;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
 import android.net.wifi.WifiManager;
 import android.os.Environment;
 import android.test.suitebuilder.annotation.LargeTest;
-import android.util.Log;
+
+import com.android.connectivitymanagertest.ConnectivityManagerStressTestRunner;
+import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
 
 import java.io.BufferedWriter;
 import java.io.File;
@@ -35,9 +34,7 @@
 /**
  * Stress test setting up device as wifi hotspot
  */
-public class WifiApStress
-    extends ConnectivityManagerTestBase {
-    private final static String TAG = "WifiApStress";
+public class WifiApStress extends ConnectivityManagerTestBase {
     private static String NETWORK_ID = "AndroidAPTest";
     private static String PASSWD = "androidwifi";
     private final static String OUTPUT_FILE = "WifiStressTestOutput.txt";
@@ -46,6 +43,10 @@
     private int mLastIteration = 0;
     private boolean mWifiOnlyFlag;
 
+    public WifiApStress() {
+        super(WifiApStress.class.getSimpleName());
+    }
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
@@ -71,7 +72,7 @@
     @LargeTest
     public void testWifiHotSpot() {
         if (mWifiOnlyFlag) {
-            Log.v(TAG, this.getName() + " is excluded for wi-fi only test");
+            logv(getName() + " is excluded for wi-fi only test");
             return;
         }
         WifiConfiguration config = new WifiConfiguration();
@@ -95,7 +96,7 @@
         }
         int i;
         for (i = 0; i < mTotalIterations; i++) {
-            Log.v(TAG, "iteration: " + i);
+            logv("iteration: " + i);
             mLastIteration = i;
             // enable Wifi tethering
             assertTrue("failed to enable wifi hotspot",
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
index 6ef4f06..fbd4669 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
@@ -19,13 +19,10 @@
 import android.app.Activity;
 import android.content.Context;
 import android.net.ConnectivityManager;
-import android.net.IpConfiguration.IpAssignment;
-import android.net.IpConfiguration.ProxySettings;
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.State;
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiConfiguration.KeyMgmt;
 import android.net.wifi.WifiManager;
 import android.os.Bundle;
 import android.os.Environment;
@@ -37,6 +34,7 @@
 
 import com.android.connectivitymanagertest.ConnectivityManagerStressTestRunner;
 import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
+import com.android.connectivitymanagertest.WifiConfigurationHelper;
 
 import java.io.BufferedWriter;
 import java.io.File;
@@ -52,8 +50,6 @@
  *                  -w com.android.connectivitymanagertest/.ConnectivityManagerStressTestRunner
  */
 public class WifiStressTest extends ConnectivityManagerTestBase {
-    private final static String TAG = "WifiStressTest";
-
     private final static long SCREEN_OFF_TIMER = 500; //500ms
     /**
      * Wi-Fi idle time for default sleep policy
@@ -78,6 +74,10 @@
     private BufferedWriter mOutputWriter = null;
     private boolean mWifiOnlyFlag;
 
+    public WifiStressTest() {
+        super(WifiStressTest.class.getSimpleName());
+    }
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
@@ -89,14 +89,14 @@
         mScanIterations = mRunner.getScanIterations();
         mWifiSleepTime = mRunner.getSleepTime();
         mWifiOnlyFlag = mRunner.isWifiOnly();
-        log(String.format("mReconnectIterations(%d), mSsid(%s), mPassword(%s),"
+        logv(String.format("mReconnectIterations(%d), mSsid(%s), mPassword(%s),"
             + "mScanIterations(%d), mWifiSleepTime(%d)", mReconnectIterations, mSsid,
             mPassword, mScanIterations, mWifiSleepTime));
         mOutputWriter = new BufferedWriter(new FileWriter(new File(
                 Environment.getExternalStorageDirectory(), OUTPUT_FILE), true));
         turnScreenOn();
         if (!mWifiManager.isWifiEnabled()) {
-            log("Enable wi-fi before stress tests.");
+            logv("Enable wi-fi before stress tests.");
             if (!enableWifi()) {
                 tearDown();
                 fail("enable wifi failed.");
@@ -107,7 +107,7 @@
 
     @Override
     protected void tearDown() throws Exception {
-        log("tearDown()");
+        logv("tearDown()");
         if (mOutputWriter != null) {
             mOutputWriter.close();
         }
@@ -115,23 +115,19 @@
     }
 
     private void writeOutput(String s) {
-        log("write message: " + s);
+        logv("write message: " + s);
         if (mOutputWriter == null) {
-            log("no writer attached to file " + OUTPUT_FILE);
+            logv("no writer attached to file " + OUTPUT_FILE);
             return;
         }
         try {
             mOutputWriter.write(s + "\n");
             mOutputWriter.flush();
         } catch (IOException e) {
-            log("failed to write output.");
+            logv("failed to write output.");
         }
     }
 
-    public void log(String message) {
-        Log.v(TAG, message);
-    }
-
     private void sleep(long sometime, String errorMsg) {
         try {
             Thread.sleep(sometime);
@@ -149,7 +145,7 @@
         long scanTimeSum = 0, i, averageScanTime = -1;
         int ssidAppearInScanResultsCount = 0; // count times of given ssid appear in scan results.
         for (i = 1; i <= mScanIterations; i++) {
-            log("testWifiScanning: iteration: " + i);
+            logv("testWifiScanning: iteration: " + i);
             averageScanTime = scanTimeSum / i;
             writeOutput(String.format("iteration %d out of %d", i, mScanIterations));
             writeOutput(String.format("average scanning time is %d", averageScanTime));
@@ -173,9 +169,9 @@
             if (scanResultLocal == null || scanResultLocal.isEmpty()) {
                 fail("Scan results are empty ");
             }
-            log("size of scan result list: " + scanResultLocal.size());
+            logv("size of scan result list: " + scanResultLocal.size());
             for (ScanResult sr : scanResultLocal) {
-                log(String.format("scan result: " + sr.toString()));
+                logv(String.format("scan result: " + sr.toString()));
                 if (mSsid.equals(sr.SSID)) {
                     ssidAppearInScanResultsCount += 1;
                     break;
@@ -208,21 +204,12 @@
         Settings.Global.putLong(mRunner.getContext().getContentResolver(),
                 Settings.Global.WIFI_IDLE_MS, WIFI_IDLE_MS);
 
-        // Connect to a Wi-Fi network
-        WifiConfiguration config = new WifiConfiguration();
-        config.SSID = mSsid;
-        if (mPassword != null) {
-            config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
-            if (isHex(mPassword, 64)) {
-                config.preSharedKey = mPassword;
-            } else {
-                config.preSharedKey = '"' + mPassword + '"';
-            }
+        WifiConfiguration config;
+        if (mPassword == null) {
+            config = WifiConfigurationHelper.createOpenConfig(mSsid);
         } else {
-            config.allowedKeyManagement.set(KeyMgmt.NONE);
+            config = WifiConfigurationHelper.createPskConfig(mSsid, mPassword);
         }
-        config.setIpAssignment(IpAssignment.DHCP);
-        config.setProxySettings(ProxySettings.NONE);
 
         assertTrue("Failed to connect to Wi-Fi network: " + mSsid,
                 connectToWifiWithConfiguration(config));
@@ -240,7 +227,7 @@
             // 5. Wake up the device, verify Wi-Fi is enabled and connected.
             writeOutput(String.format("iteration %d out of %d",
                     i, mReconnectIterations));
-            log("iteration: " + i);
+            logv("iteration: " + i);
             turnScreenOff();
             // Use clock time since boot for intervals.
             long start = SystemClock.uptimeMillis();
@@ -271,7 +258,7 @@
             if (mWifiOnlyFlag) {
                 NetworkInfo ni = mCm.getActiveNetworkInfo();
                 if (ni != null) {
-                    Log.e(TAG, "has active network while in wifi sleep: " + ni.toString());
+                    Log.e(mLogTag, "has active network while in wifi sleep: " + ni.toString());
                     fail("active network detected");
                 }
             } else {
@@ -292,7 +279,7 @@
             long connectionTime = SystemClock.uptimeMillis() - startTime;
             sum += connectionTime;
             avgReconnectTime = sum / i;
-            log("average reconnection time is: " + avgReconnectTime);
+            logv("average reconnection time is: " + avgReconnectTime);
 
             assertTrue("Reconnect to Wi-Fi network, but no data connection.", pingTest(null));
         }
diff --git a/docs/html/design/style/iconography.jd b/docs/html/design/style/iconography.jd
index d8d8c76..e5161f4 100644
--- a/docs/html/design/style/iconography.jd
+++ b/docs/html/design/style/iconography.jd
@@ -29,7 +29,7 @@
 scaling ratio</strong> between the five primary densities (medium, high, x-high, xx-high, and
 xxx-high respectively). For example, consider that the size for a launcher icon is specified to be
 48x48 dp. This means the baseline (MDPI) asset is 48x48 px, and the
-high density (HDPI) asset should be 1.5x the baseline at 72x72 px, and the x-high
+high-density(HDPI) asset should be 1.5x the baseline at 72x72 px, and the x-high
 density (XHDPI) asset should be 2x the baseline at 96x96 px, and so on.</p>
 
 <p class="note"><strong>Note:</strong> Android also supports low-density (LDPI) screens,
@@ -489,11 +489,12 @@
     xhdpi/...
         _pre_production/...
             <em>working_file</em>.psd
-        <em>finished_asset</em>.png</pre>
+        <em>finished_asset</em>.png
     xxhdpi/...
         _pre_production/...
             <em>working_file</em>.psd
-        <em>finished_asset</em>.png</pre>
+        <em>finished_asset</em>.png
+</pre>
 
 <p>Because the structure in your working space is similar to that of the application, you
 can quickly determine which assets should be copied to each
@@ -513,6 +514,8 @@
         <em>finished_asset</em>.png
     drawable-xhdpi/...
         <em>finished_asset</em>.png
+    drawable-xxhdpi/...
+        <em>finished_asset</em>.png
 </pre>
 
 <p>For more information about how to save resources in the application project,
@@ -520,6 +523,21 @@
 </p>
 
 
+<h3 id="xxxhdpi-launcher">Provide an xxx-high-density launcher icon</h3>
+
+<p>Some devices scale-up the launcher icon by as much as 25%. For example, if your highest density 
+launcher icon image is already extra-extra-high density, the scaling process will make it appear
+less crisp. So you should provide a higher density launcher icon in the <code>drawable-xxxhdpi
+</code> directory, which the system uses instead of scaling up a smaller version of the icon.</p>
+
+<p class="note"><strong>Note:</strong> the <code>drawable-xxxhdpi</code> qualifier is necessary only
+to provide a launcher icon that can appear larger than usual on an xxhdpi device. You do not need to
+provide xxxhdpi assets for all your app's images.</p>
+
+<p>See <a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a> for
+more information.</p>
+
+
 <h3>Remove unnecessary metadata from final assets</h3>
 
 <p>Although the Android SDK tools will automatically compress PNGs when packaging
diff --git a/docs/html/guide/practices/screens_support.jd b/docs/html/guide/practices/screens_support.jd
index dbe6c1a..7ebda53 100644
--- a/docs/html/guide/practices/screens_support.jd
+++ b/docs/html/guide/practices/screens_support.jd
@@ -111,15 +111,15 @@
   <dd>Actual physical size, measured as the screen's diagonal.
 
   <p>For simplicity, Android groups all actual screen sizes into four generalized sizes: small,
-normal, large, and extra large.</p></dd>
+normal, large, and extra-large.</p></dd>
 
 <dt><em>Screen density</em></dt>
   <dd>The quantity of pixels within a physical area of the screen; usually referred to as dpi (dots
 per inch). For example, a "low" density screen has fewer pixels within a given physical area,
 compared to a "normal" or "high" density screen.</p>
 
-  <p>For simplicity, Android groups all actual screen densities into four generalized densities:
-low, medium, high, and extra high.</p></dd>
+  <p>For simplicity, Android groups all actual screen densities into six generalized densities:
+low, medium, high, extra-high, extra-extra-high, and extra-extra-extra-high.</p></dd>
 
 <dt><em>Orientation</em></dt>
   <dd>The orientation of the screen from the user's point of view. This is either landscape or
@@ -168,9 +168,15 @@
 href="#DeclaringTabletLayouts">Declaring Tablet Layouts for Android 3.2</a> for more
 information.</p>
 </li>
-<li>A set of four generalized <strong>densities</strong>: <em>ldpi</em> (low), <em>mdpi</em>
-(medium),
-<em>hdpi</em> (high), and <em>xhdpi</em> (extra high)
+<li>A set of six generalized <strong>densities</strong>:
+  <ul>
+    <li><em>ldpi</em> (low) ~120dpi</li>
+    <li><em>mdpi</em> (medium) ~160dpi</li>
+    <li><em>hdpi</em> (high) ~240dpi</li>
+    <li><em>xhdpi</em> (extra-high) ~320dpi</li>
+    <li><em>xxhdpi</em> (extra-extra-high) ~480dpi</li>
+    <li><em>xxxhdpi</em> (extra-extra-extra-high) ~640dpi</li>
+  </ul>
 </li>
 </ul>
 
@@ -243,14 +249,14 @@
 densities.</p>
 
 <p>Maintaining density independence is important because, without it, a UI element (such as a
-button) appears physically larger on a low density screen and smaller on a high density screen. Such
+button) appears physically larger on a low-density screen and smaller on a high-density screen. Such
 density-related size changes can cause problems in your application layout and usability. Figures 2
 and 3 show the difference between an application when it does not provide density independence and
 when it does, respectively.</p>
 
 <img src="{@docRoot}images/screens_support/density-test-bad.png" alt=""  />
 <p class="img-caption"><strong>Figure 2.</strong> Example application without support for
-different densities, as shown on low, medium, and high density screens.</p>
+different densities, as shown on low, medium, and high-density screens.</p>
 
 <img src="{@docRoot}images/screens_support/density-test-good.png" alt="" />
 <p class="img-caption"><strong>Figure 3.</strong> Example application with good support for
@@ -266,8 +272,8 @@
 </ul>
 
 <p>In figure 2, the text view and bitmap drawable have dimensions specified in pixels ({@code px}
-units), so the views are physically larger on a low density screen and smaller on a high density
-screen. This is because although the actual screen sizes may be the same, the high density screen
+units), so the views are physically larger on a low-density screen and smaller on a high-density
+screen. This is because although the actual screen sizes may be the same, the high-density screen
 has more pixels per inch (the same amount of pixels fit in a smaller area). In figure 3, the layout
 dimensions are specified in density-independent pixels ({@code dp} units). Because the baseline for
 density-independent pixels is a medium-density screen, the device with a medium-density screen looks
@@ -311,7 +317,7 @@
 <a href="{@docRoot}guide/topics/manifest/supports-screens-element.html">{@code
 &lt;supports-screens&gt;}</a> element in your manifest file.</p>
   </li>
-  
+
   <li><strong>Provide different layouts for different screen sizes</strong>
     <p>By default, Android resizes your application layout to fit the current device screen. In most
 cases, this works fine. In other cases, your UI might not look as good and might need adjustments
@@ -320,7 +326,7 @@
 you might need to adjust sizes so that everything can fit on the screen.</p>
     <p>The configuration qualifiers you can use to provide size-specific resources are
 <code>small</code>, <code>normal</code>, <code>large</code>, and <code>xlarge</code>. For
-example, layouts for an extra large screen should go in {@code layout-xlarge/}.</p>
+example, layouts for an extra-large screen should go in {@code layout-xlarge/}.</p>
     <p>Beginning with Android 3.2 (API level 13), the above size groups are deprecated and you
 should instead use the {@code sw&lt;N&gt;dp} configuration qualifier to define the smallest
 available width required by your layout resources. For example, if your multi-pane tablet layout
@@ -328,7 +334,7 @@
 new techniques for declaring layout resources is discussed further in the section about <a
 href="#DeclaringTabletLayouts">Declaring Tablet Layouts for Android 3.2</a>.</p>
   </li>
-  
+
   <li><strong>Provide different bitmap drawables for different screen densities</strong>
     <p>By default, Android scales your bitmap drawables ({@code .png}, {@code .jpg}, and {@code
 .gif} files) and Nine-Patch drawables ({@code .9.png} files) so that they render at the appropriate
@@ -337,10 +343,22 @@
 screen, and scales them down when on a low-density screen. This scaling can cause artifacts in the
 bitmaps. To ensure your bitmaps look their best, you should include alternative versions at
 different resolutions for different screen densities.</p>
-    <p>The configuration qualifiers you can use for density-specific resources are
-<code>ldpi</code> (low), <code>mdpi</code> (medium), <code>hdpi</code> (high), and
-<code>xhdpi</code> (extra high). For example, bitmaps for high-density screens should go in
-{@code drawable-hdpi/}.</p>
+    <p>The <a href="#qualifiers">configuration qualifiers</a> (described in detail below) that you
+can use for density-specific resources are <code>ldpi</code> (low), <code>mdpi</code> (medium),
+<code>hdpi</code> (high), <code>xhdpi</code> extra-high), <code>xxhdpi</code>
+(extra-extra-high), and <code>xxxhdpi</code> (extra-extra-extra-high). For example, bitmaps
+for high-density screens should go in {@code drawable-hdpi/}.</p>
+    <p class="note" id="xxxhdpi-note"><strong>Note:</strong>  the <code>drawable-xxxhdpi</code>
+qualifier is necessary only to provide a launcher icon that can appear larger than usual on an
+xxhdpi device. You do not need to provide xxxhdpi assets for all your app's images.</p>
+    <p>Some devices scale-up the launcher icon by as much as 25%. For example, if your highest
+density launcher icon image is already extra-extra-high-density, the scaling process will make it
+appear less crisp. So you should provide a higher density launcher icon in the
+<code>drawable-xxxhdpi</code> directory, which the system uses instead of scaling up a smaller
+version of the icon.</p>
+    <p>See <a href="{@docRoot}design/style/iconography.html#xxxhdpi-launcher">Provide an
+xxx-high-density launcher icon</a> for more information. You should not use the
+<code>xxxhdpi</code> qualifier for UI elements other than the launcher icon.</p>
   </li>
 </ul>
 
@@ -371,14 +389,14 @@
   <p>The "default" resources are those that are not tagged with a configuration qualifier. For
 example, the resources in {@code drawable/} are the default drawable resources. The system
 assumes that default resources are designed for the baseline screen size and density, which is a
-normal screen size and a medium density. As such, the system scales default density
+normal screen size and a medium-density. As such, the system scales default density
 resources up for high-density screens and down for low-density screens, as appropriate.</p>
   <p>However, when the system is looking for a density-specific resource and does not find it in
 the density-specific directory, it won't always use the default resources. The system may
 instead use one of the other density-specific resources in order to provide better results
 when scaling. For example, when looking for a low-density resource and it is not available, the
 system prefers to scale-down the high-density version of the resource, because the
-system can easily scale a high-density resource down to low-density by a factor of 0.5, with 
+system can easily scale a high-density resource down to low-density by a factor of 0.5, with
 fewer artifacts, compared to scaling a medium-density resource by a factor of 0.75.</p>
 </li>
 </ol>
@@ -416,9 +434,9 @@
 files must be named exactly the same as the default resource files.</li>
 </ol>
 
-<p>For example, {@code xlarge} is a configuration qualifier for extra large screens. When you append
+<p>For example, {@code xlarge} is a configuration qualifier for extra-large screens. When you append
 this string to a resource directory name (such as {@code layout-xlarge}), it indicates to the
-system that these resources are to be used on devices that have an extra large screen.</p>
+system that these resources are to be used on devices that have an extra-large screen.</p>
 
 <p class="table-caption"><strong>Table 1.</strong> Configuration qualifiers that allow you to
 provide special resources for different screen configurations.</p>
@@ -445,11 +463,11 @@
 </tr>
 <tr>
 <td><code>xlarge</code></td>
-<td>Resources for <em>extra large</em> size screens.</td>
+<td>Resources for <em>extra-large</em> size screens.</td>
 </tr>
 
 <tr>
-<td rowspan="6">Density</td>
+<td rowspan="8">Density</td>
 <td><code>ldpi</code></td>
 <td>Resources for low-density (<em>ldpi</em>) screens (~120dpi).</td>
 </tr>
@@ -464,7 +482,14 @@
 </tr>
 <tr>
 <td><code>xhdpi</code></td>
-<td>Resources for extra high-density (<em>xhdpi</em>) screens (~320dpi).</td>
+<td>Resources for extra-high-density (<em>xhdpi</em>) screens (~320dpi).</td>
+</tr>
+<td><code>xxhdpi</code></td>
+<td>Resources for extra-extra-high-density (<em>xxhdpi</em>) screens (~480dpi).</td>
+</tr>
+<td><code>xxxhdpi</code></td>
+<td>Resources for extra-extra-extra-high-density (<em>xxxhdpi</em>) uses (~640dpi). Use this for the
+  launcher icon only, see <a href="#xxxhdpi-note">note</a> above.</td>
 </tr>
 <tr>
 <td><code>nodpi</code></td>
@@ -515,18 +540,18 @@
 
 <p>For example, the following is a list of resource directories in an application that
 provides different layout designs for different screen sizes and different bitmap drawables
-for medium, high, and extra high density screens.</p>
+for medium, high, and extra-high-density screens.</p>
 
 <pre class="classic">
-res/layout/my_layout.xml             // layout for normal screen size ("default")
-res/layout-small/my_layout.xml       // layout for small screen size
-res/layout-large/my_layout.xml       // layout for large screen size
-res/layout-xlarge/my_layout.xml      // layout for extra large screen size
-res/layout-xlarge-land/my_layout.xml // layout for extra large in landscape orientation
+res/layout/my_layout.xml              // layout for normal screen size ("default")
+res/layout-large/my_layout.xml        // layout for large screen size
+res/layout-xlarge/my_layout.xml       // layout for extra-large screen size
+res/layout-xlarge-land/my_layout.xml  // layout for extra-large in landscape orientation
 
-res/drawable-mdpi/my_icon.png        // bitmap for medium density
-res/drawable-hdpi/my_icon.png        // bitmap for high density
-res/drawable-xhdpi/my_icon.png       // bitmap for extra high density
+res/drawable-mdpi/my_icon.png         // bitmap for medium-density
+res/drawable-hdpi/my_icon.png         // bitmap for high-density
+res/drawable-xhdpi/my_icon.png        // bitmap for extra-high-density
+res/drawable-xxhdpi/my_icon.png       // bitmap for extra-extra-high-density
 </pre>
 
 <p>For more information about how to use alternative resources and a complete list of
@@ -575,10 +600,10 @@
 screen. For example, a row of buttons might not fit within the width of the screen on a small screen
 device. In this case you should provide an alternative layout for small screens that adjusts the
 size or position of the buttons.</li>
-  <li>When testing on an extra large screen, you might realize that your layout doesn't make
+  <li>When testing on an extra-large screen, you might realize that your layout doesn't make
 efficient use of the big screen and is obviously stretched to fill it.
-In this case, you should provide an alternative layout for extra large screens that provides a
-redesigned UI that is optimized for bigger screens such as tablets. 
+In this case, you should provide an alternative layout for extra-large screens that provides a
+redesigned UI that is optimized for bigger screens such as tablets.
     <p>Although your application should work fine without an alternative layout on big screens, it's
 quite important to users that your application looks as though it's designed specifically for their
 devices. If the UI is obviously stretched, users are more likely to be unsatisfied with the
@@ -598,7 +623,7 @@
 <p>If your UI uses bitmaps that need to fit the size of a view even after the system scales
 the layout (such as the background image for a button), you should use <a
 href="{@docRoot}guide/topics/graphics/2d-graphics.html#nine-patch">Nine-Patch</a> bitmap files. A
-Nine-Patch file is basically a PNG file in which you specific two-dimensional regions that are
+Nine-Patch file is basically a PNG file in which you specify two-dimensional regions that are
 stretchable. When the system needs to scale the view in which the bitmap is used, the system
 stretches the Nine-Patch bitmap, but stretches only the specified regions. As such, you don't
 need to provide different drawables for different screen sizes, because the Nine-Patch bitmap can
@@ -621,21 +646,24 @@
 each one, for different densities.</p>
 
 <p class="note"><strong>Note:</strong> You only need to provide density-specific drawables for
-bitmap files ({@code .png}, {@code .jpg}, or {@code .gif}) and Nine-Path files ({@code
+bitmap files ({@code .png}, {@code .jpg}, or {@code .gif}) and Nine-Patch files ({@code
 .9.png}). If you use XML files to define shapes, colors, or other <a
 href="{@docRoot}guide/topics/resources/drawable-resource.html">drawable resources</a>, you should
 put one copy in the default drawable directory ({@code drawable/}).</p>
 
 <p>To create alternative bitmap drawables for different densities, you should follow the
-<b>3:4:6:8 scaling ratio</b> between the four generalized densities. For example, if you have
-a bitmap drawable that's 48x48 pixels for medium-density screen (the size for a launcher icon),
-all the different sizes should be:</p>
+<b>3:4:6:8:12:16 scaling ratio</b> between the six generalized densities. For example, if you have
+a bitmap drawable that's 48x48 pixels for medium-density screens, all the different sizes should be:
+</p>
 
 <ul>
-  <li>36x36 for low-density</li>
-  <li>48x48 for medium-density</li>
-  <li>72x72 for high-density</li>
-  <li>96x96 for extra high-density</li>
+  <li>36x36 (0.75x) for low-density</li>
+  <li>48x48 (1.0x baseline) for medium-density</li>
+  <li>72x72 (1.5x) for high-density</li>
+  <li>96x96 (2.0x) for extra-high-density</li>
+  <li>180x180 (3.0x) for extra-extra-high-density</li>
+  <li>192x192 (4.0x) for extra-extra-extra-high-density (launcher icon only; see
+    <a href="#xxxhdpi-note">note</a> above)</li>
 </ul>
 
 <p>For more information about designing icons, see the <a
@@ -715,7 +743,7 @@
 screen area. Specifically, the device's smallestWidth is the shortest of the screen's available
 height and width (you may also think of it as the "smallest possible width" for the screen). You can
 use this qualifier to ensure that, regardless of the screen's current orientation, your
-application's has at least {@code &lt;N&gt;} dps of width available for it UI.</p>
+application's has at least {@code &lt;N&gt;} dps of width available for its UI.</p>
         <p>For example, if your layout requires that its smallest dimension of screen area be at
 least 600 dp at all times, then you can use this qualifer to create the layout resources, {@code
 res/layout-sw600dp/}. The system will use these resources only when the smallest dimension of
@@ -1011,8 +1039,8 @@
 <p>If you need to control exactly how your application will look on various
 screen configurations, adjust your layouts and bitmap drawables in configuration-specific
 resource directories. For example, consider an icon that you want to display on
-medium and high density screens. Simply create your icon at two different sizes
-(for instance 100x100 for medium density and 150x150 for high density) and put
+medium and high-density screens. Simply create your icon at two different sizes
+(for instance 100x100 for medium-density and 150x150 for high-density) and put
 the two variations in the appropriate directories, using the proper
 qualifiers:</p>
 
@@ -1115,9 +1143,7 @@
 <div class="figure" style="width:300px">
 <img src="{@docRoot}images/screens_support/scale-test.png" alt="" />
 <p class="img-caption"><strong>Figure 5.</strong> Comparison of pre-scaled and auto-scaled
-bitmaps, from <a
-href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/graphics/DensityActivity.html">
-ApiDemos</a>.
+bitmaps.
 </p>
 </div>
 
@@ -1153,10 +1179,7 @@
 (120), medium (160) and high (240) density bitmaps on a high-density screen. The differences are
 subtle, because all of the bitmaps are being scaled to match the current screen density, however the
 scaled bitmaps have slightly different appearances depending on whether they are pre-scaled or
-auto-scaled at draw time. You can find the source code for this sample application, which
-demonstrates using pre-scaled and auto-scaled bitmaps, in <a
-href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/graphics/DensityActivity.html">
-ApiDemos</a>.</p>
+auto-scaled at draw time.</p>
 
 <p class="note"><strong>Note:</strong> In Android 3.0 and above, there should be no perceivable
 difference between pre-scaled and auto-scaled bitmaps, due to improvements in the graphics
@@ -1172,9 +1195,9 @@
 pixels. Imagine an application in which a scroll or fling gesture is recognized after the user's
 finger has moved by at least 16 pixels. On a baseline screen, a user's must move by {@code 16 pixels
 / 160 dpi}, which equals 1/10th of an inch (or 2.5 mm) before the gesture is recognized. On a device
-with a high density display (240dpi), the user's must move by {@code 16 pixels / 240 dpi}, which
+with a high-density display (240dpi), the user's must move by {@code 16 pixels / 240 dpi}, which
 equals 1/15th of an inch (or 1.7 mm). The distance is much shorter and the application thus appears
-more sensitive to the user.</p> 
+more sensitive to the user.</p>
 
 <p>To fix this issue, the gesture threshold must be expressed in code in <code>dp</code> and then
 converted to actual pixels. For example:</p>
@@ -1194,7 +1217,7 @@
 <p>The {@link android.util.DisplayMetrics#density DisplayMetrics.density} field specifies the scale
 factor you must use to convert {@code dp} units to pixels, according to the current screen density.
 On a medium-density screen, {@link android.util.DisplayMetrics#density DisplayMetrics.density}
-equals 1.0; on a high-density screen it equals 1.5; on an extra high-density screen, it equals 2.0;
+equals 1.0; on a high-density screen it equals 1.5; on an extra-high-density screen, it equals 2.0;
 and on a low-density screen, it equals 0.75. This figure is the factor by which you should multiply
 the {@code dp} units on order to get the actual pixel count for the current screen. (Then add {@code
 0.5f} to round the figure up to the nearest whole number, when converting to an integer.) For more
@@ -1277,7 +1300,7 @@
         <nobr>High density (240), <em>hdpi</em><nobr>
       </th>
       <th>
-        <nobr>Extra high density (320), <em>xhdpi</em><nobr>
+        <nobr>Extra-high-density (320), <em>xhdpi</em><nobr>
       </th>
     </tr>
     <tr>
@@ -1315,7 +1338,7 @@
     </tr>
     <tr>
       <th>
-        <em>Extra Large</em> screen
+        <em>Extra-Large</em> screen
       </th>
       <td>1024x600</td>
       <td><strong>WXGA (1280x800)</strong><sup>&dagger;</sup><br>
@@ -1369,4 +1392,4 @@
 
 <p>For more information about creating AVDs from the command line, see <a
 href="{@docRoot}tools/devices/managing-avds-cmdline.html">Managing AVDs from the
-Command Line</a></p>
+Command Line</a>.</p>
\ No newline at end of file
diff --git a/docs/html/guide/topics/resources/providing-resources.jd b/docs/html/guide/topics/resources/providing-resources.jd
index bf16630..6d9527f 100644
--- a/docs/html/guide/topics/resources/providing-resources.jd
+++ b/docs/html/guide/topics/resources/providing-resources.jd
@@ -389,7 +389,7 @@
             <ul>
               <li>240x320 ldpi (QVGA handset)</li>
               <li>320x480 mdpi (handset)</li>
-              <li>480x800 hdpi (high density handset)</li>
+              <li>480x800 hdpi (high-density handset)</li>
             </ul>
           </li>
           <li>480, for screens such as 480x800 mdpi (tablet/handset).</li>
@@ -483,20 +483,20 @@
         <ul class="nolist">
         <li>{@code small}: Screens that are of similar size to a
         low-density QVGA screen. The minimum layout size for a small screen
-        is approximately 320x426 dp units.  Examples are QVGA low density and VGA high
+        is approximately 320x426 dp units.  Examples are QVGA low-density and VGA high
         density.</li>
         <li>{@code normal}: Screens that are of similar size to a
         medium-density HVGA screen. The minimum
         layout size for a normal screen is approximately 320x470 dp units.  Examples
-        of such screens a WQVGA low density, HVGA medium density, WVGA
-        high density.</li>
+        of such screens a WQVGA low-density, HVGA medium-density, WVGA
+        high-density.</li>
         <li>{@code large}: Screens that are of similar size to a
         medium-density VGA screen.
         The minimum layout size for a large screen is approximately 480x640 dp units.
-        Examples are VGA and WVGA medium density screens.</li>
+        Examples are VGA and WVGA medium-density screens.</li>
         <li>{@code xlarge}: Screens that are considerably larger than the traditional
         medium-density HVGA screen. The minimum layout size for an xlarge screen
-        is approximately 720x960 dp units.  In most cases, devices with extra large
+        is approximately 720x960 dp units.  In most cases, devices with extra-large
         screens would be too large to carry in a pocket and would most likely
         be tablet-style devices. <em>Added in API level 9.</em></li>
         </ul>
@@ -613,6 +613,8 @@
         <code>mdpi</code><br/>
         <code>hdpi</code><br/>
         <code>xhdpi</code><br/>
+        <code>xxhdpi</code><br/>
+        <code>xxxhdpi</code><br/>
         <code>nodpi</code><br/>
         <code>tvdpi</code>
       </td>
@@ -622,8 +624,14 @@
           <li>{@code mdpi}: Medium-density (on traditional HVGA) screens; approximately
 160dpi.</li>
           <li>{@code hdpi}: High-density screens; approximately 240dpi.</li>
-          <li>{@code xhdpi}: Extra high-density screens; approximately 320dpi. <em>Added in API
+          <li>{@code xhdpi}: Extra-high-density screens; approximately 320dpi. <em>Added in API
 Level 8</em></li>
+          <li>{@code xxhdpi}: Extra-extra-high-density screens; approximately 480dpi. <em>Added in API
+Level 16</em></li>
+          <li>{@code xxxhdpi}: Extra-extra-extra-high-density uses (launcher icon only, see the 
+            <a href="{@docRoot}guide/practices/screens_support.html#xxxhdpi-note">note</a> 
+            in <em>Supporting Multiple Screens</em>); approximately 640dpi. <em>Added in API
+Level 18</em></li>
           <li>{@code nodpi}: This can be used for bitmap resources that you do not want to be scaled
 to match the device density.</li>
           <li>{@code tvdpi}: Screens somewhere between mdpi and hdpi; approximately 213dpi. This is
@@ -631,8 +639,9 @@
 apps shouldn't need it&mdash;providing mdpi and hdpi resources is sufficient for most apps and
 the system will scale them as appropriate. This qualifier was introduced with API level 13.</li>
         </ul>
-        <p>There is a 3:4:6:8 scaling ratio between the four primary densities (ignoring the
-tvdpi density). So, a 9x9 bitmap in ldpi is 12x12 in mdpi, 18x18 in hdpi and 24x24 in xhdpi.</p>
+        <p>There is a 3:4:6:8:12:16 scaling ratio between the six primary densities (ignoring the
+tvdpi density). So, a 9x9 bitmap in ldpi is 12x12 in mdpi, 18x18 in hdpi, 24x24 in xhdpi and so on.
+</p>
         <p>If you decide that your image resources don't look good enough on a television or
 other certain devices and want to try tvdpi resources, the scaling factor is 1.33*mdpi. For
 example, a 100px x 100px image for mdpi screens should be 133px x 133px for tvdpi.</p>
diff --git a/docs/html/guide/topics/ui/accessibility/services.jd b/docs/html/guide/topics/ui/accessibility/services.jd
index c868080..d69af9f 100644
--- a/docs/html/guide/topics/ui/accessibility/services.jd
+++ b/docs/html/guide/topics/ui/accessibility/services.jd
@@ -71,24 +71,30 @@
 
 <h3 id="service-declaration">Accessibility service declaration</h3>
 
-<p>In order to be treated as an accessibility service, your application must include the
+<p>In order to be treated as an accessibility service, you must include a
 {@code service} element (rather than the {@code activity} element) within the {@code application}
-element in its manifest. In addition, within the {@code service} element, you must also include an
+element in your manifest. In addition, within the {@code service} element, you must also include an
 accessibility service intent filter. For compatiblity with Android 4.1 and higher, the manifest
 must also request the {@link android.Manifest.permission#BIND_ACCESSIBILITY_SERVICE} permission
 as shown in the following sample:</p>
 
 <pre>
-&lt;application&gt;
-  &lt;service android:name=&quot;.MyAccessibilityService&quot;
-      android:label=&quot;@string/accessibility_service_label&quot;
-      android:permission=&quot;android.permission.BIND_ACCESSIBILITY_SERVICE&quot&gt;
-    &lt;intent-filter&gt;
-      &lt;action android:name=&quot;android.accessibilityservice.AccessibilityService&quot; /&gt;
-    &lt;/intent-filter&gt;
-  &lt;/service&gt;
-  &lt;uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" /&gt;
-&lt;/application&gt;
+&lt;manifest&gt;
+  ...
+  &lt;uses-permission ... /&gt;
+  ...
+  &lt;application&gt;
+    ...
+    &lt;service android:name=&quot;.MyAccessibilityService&quot;
+        android:label=&quot;@string/accessibility_service_label&quot;
+        android:permission=&quot;android.permission.BIND_ACCESSIBILITY_SERVICE&quot&gt;
+      &lt;intent-filter&gt;
+        &lt;action android:name=&quot;android.accessibilityservice.AccessibilityService&quot; /&gt;
+      &lt;/intent-filter&gt;
+    &lt;/service&gt;
+    &lt;uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" /&gt;
+  &lt;/application&gt;
+&lt;/manifest&gt;
 </pre>
 
 <p>These declarations are required for all accessibility services deployed on Android 1.6 (API Level
diff --git a/docs/html/images/tools/projectview01.png b/docs/html/images/tools/projectview01.png
new file mode 100644
index 0000000..90589fb
--- /dev/null
+++ b/docs/html/images/tools/projectview01.png
Binary files differ
diff --git a/docs/html/images/tools/projectview03.png b/docs/html/images/tools/projectview03.png
new file mode 100644
index 0000000..f527ff1
--- /dev/null
+++ b/docs/html/images/tools/projectview03.png
Binary files differ
diff --git a/docs/html/sdk/installing/studio-androidview.jd b/docs/html/sdk/installing/studio-androidview.jd
new file mode 100644
index 0000000..09aeaba
--- /dev/null
+++ b/docs/html/sdk/installing/studio-androidview.jd
@@ -0,0 +1,55 @@
+page.title=Using the Android Project View
+
+@jd:body
+
+
+<p>The Android project view in Android Studio shows a flattened version of your project's structure
+that provides quick access to the key source files of Android projects and helps you work with
+the new <a href="{@docRoot}sdk/installing/studio-build.html">Gradle-based build system</a>. The
+Android project view:</p>
+
+<ul>
+<li>Groups the build files for all modules at the top level of the project hierarchy.</li>
+<li>Shows the most important source directories at the top level of the module hierarchy.</li>
+<li>Groups all the manifest files for each module.</li>
+<li>Shows resource files from all Gradle source sets.</li>
+<li>Groups resource files for different locales, orientations, and screen types in a single group
+per resource type.</li>
+</ul>
+
+<div style="float:right;margin-left:30px;width:240px">
+<img src="{@docRoot}images/tools/projectview01.png" alt="" width="220" height="264"/>
+<p class="img-caption"><strong>Figure 1:</strong> Show the Android project view.</p>
+</div>
+
+
+<h2 id="enable-view">Enable the Android Project View</h2>
+
+<p>The Android project view is not yet enabled by default. To show the Android project view,
+click <strong>Project</strong> and select <strong>Android</strong>, as shown in Figure 1.</p>
+
+
+<h2 id="project-view">Use the Android Project View</h2>
+
+<p>The Android project view shows all the build files at the top level of the project hierarchy
+under <strong>Gradle Scripts</strong>. Each project module appears as a folder at the top
+level of the project hierarchy and contains these three elements at the top level:</p>
+
+<ul>
+<li><code>java/</code> - Source files for the module.</li>
+<li><code>manifests/</code> - Manifest files for the module.</li>
+<li><code>res/</code> - Resource files for the module.</li>
+</ul>
+
+<p>Figure 2 shows how the Android project view groups all the instances of the
+<code>ic_launcher.png</code> resource for different screen densities under the same element.</p>
+
+<p class="note"><strong>Note:</strong> The Android project view shows a hierarchy that helps you
+work with Android projects by providing a flattened structure that highlights the most commonly
+used files while developing Android applications. However, the project structure on disk differs
+from this representation.</p>
+
+<img src="{@docRoot}images/tools/projectview03.png" alt=""
+     style="margin-top:10px" width="650" height="508"/>
+<p class="img-caption"><strong>Figure 2:</strong> The traditional project view (left) and the
+Android project view (right).</p>
\ No newline at end of file
diff --git a/docs/html/tools/tools_toc.cs b/docs/html/tools/tools_toc.cs
index 93e5976..8eb9cbf 100644
--- a/docs/html/tools/tools_toc.cs
+++ b/docs/html/tools/tools_toc.cs
@@ -24,6 +24,8 @@
           Creating a Project</a></li>
       <li><a href="<?cs var:toroot ?>sdk/installing/studio-tips.html">
           Tips and Tricks</a></li>
+      <li><a href="<?cs var:toroot ?>sdk/installing/studio-androidview.html">
+          Using the Android Project View</a></li>
       <li><a href="<?cs var:toroot ?>sdk/installing/studio-layout.html">
           Using the Layout Editor</a></li>
       <li><a href="<?cs var:toroot ?>sdk/installing/studio-build.html">
diff --git a/docs/html/wear/images/partners/sony.png b/docs/html/wear/images/partners/sony.png
new file mode 100644
index 0000000..e097fbb
--- /dev/null
+++ b/docs/html/wear/images/partners/sony.png
Binary files differ
diff --git a/docs/html/wear/index.jd b/docs/html/wear/index.jd
index 5dd7690..c372395 100644
--- a/docs/html/wear/index.jd
+++ b/docs/html/wear/index.jd
@@ -228,6 +228,9 @@
             <div class="col-4">
               <img src="/wear/images/partners/samsung.png" alt="Samsung">
             </div>
+            <div class="col-4">
+              <img src="/wear/images/partners/sony.png" alt="Sony">
+            </div>
           </div>
         </div> <!-- end .wrap -->
       </div>
diff --git a/graphics/java/android/graphics/drawable/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java
index ab43e01..4e68a60 100644
--- a/graphics/java/android/graphics/drawable/RippleBackground.java
+++ b/graphics/java/android/graphics/drawable/RippleBackground.java
@@ -37,10 +37,8 @@
  */
 class RippleBackground {
     private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
-    private static final TimeInterpolator DECEL_INTERPOLATOR = new LogInterpolator();
 
     private static final float GLOBAL_SPEED = 1.0f;
-    private static final float WAVE_TOUCH_DOWN_ACCELERATION = 1024.0f * GLOBAL_SPEED;
     private static final float WAVE_OPACITY_DECAY_VELOCITY = 3.0f / GLOBAL_SPEED;
     private static final float WAVE_OUTER_OPACITY_EXIT_VELOCITY_MAX = 4.5f * GLOBAL_SPEED;
     private static final float WAVE_OUTER_OPACITY_EXIT_VELOCITY_MIN = 1.5f * GLOBAL_SPEED;
@@ -70,11 +68,6 @@
     /** Screen density used to adjust pixel-based velocities. */
     private float mDensity;
 
-    private float mStartingX;
-    private float mStartingY;
-    private float mClampedStartingX;
-    private float mClampedStartingY;
-
     // Hardware rendering properties.
     private CanvasProperty<Paint> mPropOuterPaint;
     private CanvasProperty<Float> mPropOuterRadius;
@@ -83,8 +76,6 @@
 
     // Software animators.
     private ObjectAnimator mAnimOuterOpacity;
-    private ObjectAnimator mAnimX;
-    private ObjectAnimator mAnimY;
 
     // Temporary paint used for creating canvas properties.
     private Paint mTempPaint;
@@ -94,10 +85,6 @@
     private float mOuterX;
     private float mOuterY;
 
-    // Values used to tween between the start and end positions.
-    private float mTweenX = 0;
-    private float mTweenY = 0;
-
     /** Whether we should be drawing hardware animations. */
     private boolean mHardwareAnimating;
 
@@ -110,12 +97,9 @@
     /**
      * Creates a new ripple.
      */
-    public RippleBackground(RippleDrawable owner, Rect bounds, float startingX, float startingY) {
+    public RippleBackground(RippleDrawable owner, Rect bounds) {
         mOwner = owner;
         mBounds = bounds;
-
-        mStartingX = startingX;
-        mStartingY = startingY;
     }
 
     public void setup(int maxRadius, int color, float density) {
@@ -133,25 +117,6 @@
         mOuterX = 0;
         mOuterY = 0;
         mDensity = density;
-
-        clampStartingPosition();
-    }
-
-    private void clampStartingPosition() {
-        final float cX = mBounds.exactCenterX();
-        final float cY = mBounds.exactCenterY();
-        final float dX = mStartingX - cX;
-        final float dY = mStartingY - cY;
-        final float r = mOuterRadius;
-        if (dX * dX + dY * dY > r * r) {
-            // Point is outside the circle, clamp to the circumference.
-            final double angle = Math.atan2(dY, dX);
-            mClampedStartingX = cX + (float) (Math.cos(angle) * r);
-            mClampedStartingY = cY + (float) (Math.sin(angle) * r);
-        } else {
-            mClampedStartingX = mStartingX;
-            mClampedStartingY = mStartingY;
-        }
     }
 
     public void onHotspotBoundsChanged() {
@@ -159,8 +124,6 @@
             final float halfWidth = mBounds.width() / 2.0f;
             final float halfHeight = mBounds.height() / 2.0f;
             mOuterRadius = (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight);
-
-            clampStartingPosition();
         }
     }
 
@@ -175,28 +138,6 @@
         return mOuterOpacity;
     }
 
-    @SuppressWarnings("unused")
-    public void setXGravity(float x) {
-        mTweenX = x;
-        invalidateSelf();
-    }
-
-    @SuppressWarnings("unused")
-    public float getXGravity() {
-        return mTweenX;
-    }
-
-    @SuppressWarnings("unused")
-    public void setYGravity(float y) {
-        mTweenY = y;
-        invalidateSelf();
-    }
-
-    @SuppressWarnings("unused")
-    public float getYGravity() {
-        return mTweenY;
-    }
-
     /**
      * Draws the ripple centered at (0,0) using the specified paint.
      */
@@ -270,53 +211,23 @@
     }
 
     /**
-     * Specifies the starting position relative to the drawable bounds. No-op if
-     * the ripple has already entered.
-     */
-    public void move(float x, float y) {
-        mStartingX = x;
-        mStartingY = y;
-
-        clampStartingPosition();
-    }
-
-    /**
      * Starts the enter animation.
      */
     public void enter() {
         cancel();
 
-        final int radiusDuration = (int)
-                (1000 * Math.sqrt(mOuterRadius / WAVE_TOUCH_DOWN_ACCELERATION * mDensity) + 0.5);
         final int outerDuration = (int) (1000 * 1.0f / WAVE_OUTER_OPACITY_ENTER_VELOCITY);
-
-        final ObjectAnimator cX = ObjectAnimator.ofFloat(this, "xGravity", 1);
-        cX.setAutoCancel(true);
-        cX.setDuration(radiusDuration);
-        cX.setInterpolator(LINEAR_INTERPOLATOR);
-        cX.setStartDelay(RIPPLE_ENTER_DELAY);
-
-        final ObjectAnimator cY = ObjectAnimator.ofFloat(this, "yGravity", 1);
-        cY.setAutoCancel(true);
-        cY.setDuration(radiusDuration);
-        cY.setInterpolator(LINEAR_INTERPOLATOR);
-        cY.setStartDelay(RIPPLE_ENTER_DELAY);
-
         final ObjectAnimator outer = ObjectAnimator.ofFloat(this, "outerOpacity", 0, 1);
         outer.setAutoCancel(true);
         outer.setDuration(outerDuration);
         outer.setInterpolator(LINEAR_INTERPOLATOR);
 
         mAnimOuterOpacity = outer;
-        mAnimX = cX;
-        mAnimY = cY;
 
         // Enter animations always run on the UI thread, since it's unlikely
         // that anything interesting is happening until the user lifts their
         // finger.
         outer.start();
-        cX.start();
-        cY.start();
     }
 
     /**
@@ -352,12 +263,6 @@
     private void exitHardware(int opacityDuration, int outerInflection, int inflectionOpacity) {
         mPendingAnimations.clear();
 
-        // TODO: Adjust background by starting position.
-        final float startX = MathUtils.lerp(
-                mClampedStartingX - mBounds.exactCenterX(), mOuterX, mTweenX);
-        final float startY = MathUtils.lerp(
-                mClampedStartingY - mBounds.exactCenterY(), mOuterY, mTweenY);
-
         final Paint outerPaint = getTempPaint();
         outerPaint.setAntiAlias(true);
         outerPaint.setColor(mColor);
@@ -422,14 +327,6 @@
         if (mAnimOuterOpacity != null) {
             mAnimOuterOpacity.end();
         }
-
-        if (mAnimX != null) {
-            mAnimX.end();
-        }
-
-        if (mAnimY != null) {
-            mAnimY.end();
-        }
     }
 
     private void endHardwareAnimations() {
@@ -457,16 +354,6 @@
     }
 
     private void exitSoftware(int opacityDuration, int outerInflection, int inflectionOpacity) {
-        final ObjectAnimator xAnim = ObjectAnimator.ofFloat(this, "xGravity", 1);
-        xAnim.setAutoCancel(true);
-        xAnim.setDuration(opacityDuration);
-        xAnim.setInterpolator(DECEL_INTERPOLATOR);
-
-        final ObjectAnimator yAnim = ObjectAnimator.ofFloat(this, "yGravity", 1);
-        yAnim.setAutoCancel(true);
-        yAnim.setDuration(opacityDuration);
-        yAnim.setInterpolator(DECEL_INTERPOLATOR);
-
         final ObjectAnimator outerOpacityAnim;
         if (outerInflection > 0) {
             // Outer opacity continues to increase for a bit.
@@ -510,12 +397,8 @@
         }
 
         mAnimOuterOpacity = outerOpacityAnim;
-        mAnimX = xAnim;
-        mAnimY = yAnim;
 
         outerOpacityAnim.start();
-        xAnim.start();
-        yAnim.start();
     }
 
     /**
@@ -531,14 +414,6 @@
         if (mAnimOuterOpacity != null) {
             mAnimOuterOpacity.cancel();
         }
-
-        if (mAnimX != null) {
-            mAnimX.cancel();
-        }
-
-        if (mAnimY != null) {
-            mAnimY.cancel();
-        }
     }
 
     /**
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index e87a114..fa762b7 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -248,15 +248,14 @@
         boolean pressed = false;
         boolean focused = false;
 
-        final int N = stateSet.length;
-        for (int i = 0; i < N; i++) {
-            if (stateSet[i] == R.attr.state_enabled) {
+        for (int state : stateSet) {
+            if (state == R.attr.state_enabled) {
                 enabled = true;
             }
-            if (stateSet[i] == R.attr.state_focused) {
+            if (state == R.attr.state_focused) {
                 focused = true;
             }
-            if (stateSet[i] == R.attr.state_pressed) {
+            if (state == R.attr.state_pressed) {
                 pressed = true;
             }
         }
@@ -478,10 +477,6 @@
         if (mRipple != null) {
             mRipple.move(x, y);
         }
-
-        if (mBackground != null) {
-            mBackground.move(x, y);
-        }
     }
 
     /**
@@ -489,17 +484,7 @@
      */
     private void tryBackgroundEnter() {
         if (mBackground == null) {
-            final float x;
-            final float y;
-            if (mHasPending) {
-                mHasPending = false;
-                x = mPendingX;
-                y = mPendingY;
-            } else {
-                x = mHotspotBounds.exactCenterX();
-                y = mHotspotBounds.exactCenterY();
-            }
-            mBackground = new RippleBackground(this, mHotspotBounds, x, y);
+            mBackground = new RippleBackground(this, mHotspotBounds);
         }
 
         final int color = mState.mColor.getColorForState(getState(), Color.TRANSPARENT);
diff --git a/libs/hwui/AnimationContext.cpp b/libs/hwui/AnimationContext.cpp
index d7d9743..716dcf5 100644
--- a/libs/hwui/AnimationContext.cpp
+++ b/libs/hwui/AnimationContext.cpp
@@ -31,11 +31,14 @@
 }
 
 AnimationContext::~AnimationContext() {
+}
+
+void AnimationContext::destroy() {
     startFrame();
     while (mCurrentFrameAnimations.mNextHandle) {
         AnimationHandle* current = mCurrentFrameAnimations.mNextHandle;
         AnimatorManager& animators = current->mRenderNode->animators();
-        animators.endAllAnimators();
+        animators.endAllActiveAnimators();
         LOG_ALWAYS_FATAL_IF(mCurrentFrameAnimations.mNextHandle == current,
                 "endAllAnimators failed to remove from current frame list!");
     }
diff --git a/libs/hwui/AnimationContext.h b/libs/hwui/AnimationContext.h
index 900d953..9b3d5f4 100644
--- a/libs/hwui/AnimationContext.h
+++ b/libs/hwui/AnimationContext.h
@@ -98,6 +98,8 @@
 
     ANDROID_API virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener);
 
+    ANDROID_API virtual void destroy();
+
 private:
     friend class AnimationHandle;
     void addAnimationHandle(AnimationHandle* handle);
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index da65f38..4f3a573 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -161,6 +161,13 @@
     return false;
 }
 
+void BaseRenderNodeAnimator::forceEndNow(AnimationContext& context) {
+    if (mPlayState < FINISHED) {
+        mPlayState = FINISHED;
+        callOnFinishedListener(context);
+    }
+}
+
 void BaseRenderNodeAnimator::callOnFinishedListener(AnimationContext& context) {
     if (mListener.get()) {
         context.callOnFinished(this, mListener.get());
diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h
index c52a93f..1ab6235 100644
--- a/libs/hwui/Animator.h
+++ b/libs/hwui/Animator.h
@@ -68,6 +68,8 @@
 
     ANDROID_API virtual uint32_t dirtyMask() = 0;
 
+    void forceEndNow(AnimationContext& context);
+
 protected:
     BaseRenderNodeAnimator(float finalValue);
     virtual ~BaseRenderNodeAnimator();
diff --git a/libs/hwui/AnimatorManager.cpp b/libs/hwui/AnimatorManager.cpp
index 678b1ee..e06d800 100644
--- a/libs/hwui/AnimatorManager.cpp
+++ b/libs/hwui/AnimatorManager.cpp
@@ -49,6 +49,9 @@
 void AnimatorManager::setAnimationHandle(AnimationHandle* handle) {
     LOG_ALWAYS_FATAL_IF(mAnimationHandle && handle, "Already have an AnimationHandle!");
     mAnimationHandle = handle;
+    LOG_ALWAYS_FATAL_IF(!mAnimationHandle && mAnimators.size(),
+            "Lost animation handle on %p (%s) with outstanding animators!",
+            &mParent, mParent.getName());
 }
 
 template<typename T>
@@ -62,6 +65,9 @@
 
 void AnimatorManager::pushStaging() {
     if (mNewAnimators.size()) {
+        LOG_ALWAYS_FATAL_IF(!mAnimationHandle,
+                "Trying to start new animators on %p (%s) without an animation handle!",
+                &mParent, mParent.getName());
         // Since this is a straight move, we don't need to inc/dec the ref count
         move_all(mNewAnimators, mAnimators);
     }
@@ -128,22 +134,7 @@
     return functor.dirtyMask;
 }
 
-class EndAnimatorsFunctor {
-public:
-    EndAnimatorsFunctor(AnimationContext& context) : mContext(context) {}
-
-    void operator() (BaseRenderNodeAnimator* animator) {
-        animator->end();
-        animator->pushStaging(mContext);
-        animator->animate(mContext);
-        animator->decStrong(0);
-    }
-
-private:
-    AnimationContext& mContext;
-};
-
-static void endAnimatorsHard(BaseRenderNodeAnimator* animator) {
+static void endStagingAnimator(BaseRenderNodeAnimator* animator) {
     animator->end();
     if (animator->listener()) {
         animator->listener()->onAnimationFinished(animator);
@@ -151,24 +142,34 @@
     animator->decStrong(0);
 }
 
-void AnimatorManager::endAllAnimators() {
-    if (mNewAnimators.size()) {
-        // Since this is a straight move, we don't need to inc/dec the ref count
-        move_all(mNewAnimators, mAnimators);
+void AnimatorManager::endAllStagingAnimators() {
+    ALOGD("endAllStagingAnimators on %p (%s)", &mParent, mParent.getName());
+    // This works because this state can only happen on the UI thread,
+    // which means we're already on the right thread to invoke listeners
+    for_each(mNewAnimators.begin(), mNewAnimators.end(), endStagingAnimator);
+    mNewAnimators.clear();
+}
+
+class EndActiveAnimatorsFunctor {
+public:
+    EndActiveAnimatorsFunctor(AnimationContext& context) : mContext(context) {}
+
+    void operator() (BaseRenderNodeAnimator* animator) {
+        animator->forceEndNow(mContext);
+        animator->decStrong(0);
     }
-    // First try gracefully ending them
-    if (mAnimationHandle) {
-        EndAnimatorsFunctor functor(mAnimationHandle->context());
-        for_each(mAnimators.begin(), mAnimators.end(), functor);
-        mAnimators.clear();
-        mAnimationHandle->release();
-    } else {
-        // We have no context, so bust out the sledgehammer
-        // This works because this state can only happen on the UI thread,
-        // which means we're already on the right thread to invoke listeners
-        for_each(mAnimators.begin(), mAnimators.end(), endAnimatorsHard);
-        mAnimators.clear();
-    }
+
+private:
+    AnimationContext& mContext;
+};
+
+void AnimatorManager::endAllActiveAnimators() {
+    ALOGD("endAllStagingAnimators on %p (%s) with handle %p",
+            &mParent, mParent.getName(), mAnimationHandle);
+    EndActiveAnimatorsFunctor functor(mAnimationHandle->context());
+    for_each(mAnimators.begin(), mAnimators.end(), functor);
+    mAnimators.clear();
+    mAnimationHandle->release();
 }
 
 } /* namespace uirenderer */
diff --git a/libs/hwui/AnimatorManager.h b/libs/hwui/AnimatorManager.h
index d5f56ed..d03d427 100644
--- a/libs/hwui/AnimatorManager.h
+++ b/libs/hwui/AnimatorManager.h
@@ -50,8 +50,12 @@
 
     void animateNoDamage(TreeInfo& info);
 
-    // Hard-ends all animators. Used for cleanup if the root is being destroyed.
-    ANDROID_API void endAllAnimators();
+    // Hard-ends all animators. May only be called on the UI thread.
+    ANDROID_API void endAllStagingAnimators();
+
+    // Hard-ends all animators that have been pushed. Used for cleanup if
+    // the ActivityContext is being destroyed
+    void endAllActiveAnimators();
 
     bool hasAnimators() { return mAnimators.size(); }
 
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 5689e17..9855f71 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -24,6 +24,7 @@
 #include "Properties.h"
 #include "LayerRenderer.h"
 #include "ShadowTessellator.h"
+#include "RenderState.h"
 
 namespace android {
 
@@ -49,7 +50,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 Caches::Caches(): Singleton<Caches>(),
-        mExtensions(Extensions::getInstance()), mInitialized(false) {
+        mExtensions(Extensions::getInstance()), mInitialized(false), mRenderState(NULL) {
     init();
     initFont();
     initConstraints();
@@ -267,8 +268,11 @@
     log.appendFormat("Current memory usage / total memory usage (bytes):\n");
     log.appendFormat("  TextureCache         %8d / %8d\n",
             textureCache.getSize(), textureCache.getMaxSize());
-    log.appendFormat("  LayerCache           %8d / %8d\n",
-            layerCache.getSize(), layerCache.getMaxSize());
+    log.appendFormat("  LayerCache           %8d / %8d (numLayers = %zu)\n",
+            layerCache.getSize(), layerCache.getMaxSize(), layerCache.getCount());
+    log.appendFormat("  Garbage layers       %8zu\n", mLayerGarbage.size());
+    log.appendFormat("  Active layers        %8zu\n",
+            mRenderState ? mRenderState->mActiveLayers.size() : 0);
     log.appendFormat("  RenderBufferCache    %8d / %8d\n",
             renderBufferCache.getSize(), renderBufferCache.getMaxSize());
     log.appendFormat("  GradientCache        %8d / %8d\n",
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 0482430..726b74d 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -107,6 +107,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 class RenderNode;
+class RenderState;
 
 class ANDROID_API Caches: public Singleton<Caches> {
     Caches();
@@ -132,6 +133,8 @@
      */
     bool initProperties();
 
+    void setRenderState(RenderState* renderState) { mRenderState = renderState; }
+
     /**
      * Flush the cache.
      *
@@ -431,6 +434,8 @@
     GLuint mBoundTextures[REQUIRED_TEXTURE_UNITS_COUNT];
 
     OverdrawColorSet mOverdrawDebugColorSet;
+
+    RenderState* mRenderState;
 }; // class Caches
 
 }; // namespace uirenderer
diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp
index 13869aa..efa30ac 100644
--- a/libs/hwui/LayerCache.cpp
+++ b/libs/hwui/LayerCache.cpp
@@ -49,6 +49,10 @@
 // Size management
 ///////////////////////////////////////////////////////////////////////////////
 
+size_t LayerCache::getCount() {
+    return mCache.size();
+}
+
 uint32_t LayerCache::getSize() {
     return mSize;
 }
diff --git a/libs/hwui/LayerCache.h b/libs/hwui/LayerCache.h
index 1b0fc2c..6b93e8f 100644
--- a/libs/hwui/LayerCache.h
+++ b/libs/hwui/LayerCache.h
@@ -87,6 +87,8 @@
      */
     uint32_t getSize();
 
+    size_t getCount();
+
     /**
      * Prints out the content of the cache.
      */
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 23fe1b9..a8b8b16 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -328,8 +328,7 @@
         "",
         // Matrix
         "    fragColor *= colorMatrix;\n"
-        "    fragColor += colorMatrixVector;\n"
-        "    fragColor.rgb *= fragColor.a;\n",
+        "    fragColor += colorMatrixVector;\n",
         // PorterDuff
         "    fragColor = blendColors(colorBlend, fragColor);\n"
 };
diff --git a/libs/hwui/RenderState.cpp b/libs/hwui/RenderState.cpp
index 50b8f39..9948b44 100644
--- a/libs/hwui/RenderState.cpp
+++ b/libs/hwui/RenderState.cpp
@@ -32,10 +32,14 @@
     // This is delayed because the first access of Caches makes GL calls
     mCaches = &Caches::getInstance();
     mCaches->init();
+    mCaches->setRenderState(this);
 }
 
 void RenderState::onGLContextDestroyed() {
-    LOG_ALWAYS_FATAL_IF(!mActiveLayers.empty(), "layers have survived gl context destruction");
+    if (CC_UNLIKELY(!mActiveLayers.empty())) {
+        mCaches->dumpMemoryUsage();
+        LOG_ALWAYS_FATAL("layers have survived gl context destruction");
+    }
 }
 
 void RenderState::setViewport(GLsizei width, GLsizei height) {
diff --git a/libs/hwui/RenderState.h b/libs/hwui/RenderState.h
index cd71c73..3915fb5 100644
--- a/libs/hwui/RenderState.h
+++ b/libs/hwui/RenderState.h
@@ -59,6 +59,7 @@
 
 private:
     friend class renderthread::RenderThread;
+    friend class Caches;
 
     void interruptForFunctorInvoke();
     void resumeFromFunctorInvoke();
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 0a17e132..428e426 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -51,13 +51,15 @@
 }
 
 CanvasContext::~CanvasContext() {
-    destroyCanvasAndSurface();
-    mRenderThread.removeFrameCallback(this);
+    destroy();
     delete mAnimationContext;
-    freePrefetechedLayers();
 }
 
-void CanvasContext::destroyCanvasAndSurface() {
+void CanvasContext::destroy() {
+    stopDrawing();
+    freePrefetechedLayers();
+    destroyHardwareResources();
+    mAnimationContext->destroy();
     if (mCanvas) {
         delete mCanvas;
         mCanvas = 0;
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 7c27190..5984fd0 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -66,7 +66,7 @@
     void processLayerUpdate(DeferredLayerUpdater* layerUpdater);
     void prepareTree(TreeInfo& info);
     void draw();
-    void destroyCanvasAndSurface();
+    void destroy();
 
     // IFrameCallback, Chroreographer-driven frame callback entry point
     virtual void doFrame();
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 3d04316..9528874 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -194,13 +194,13 @@
     return mDrawFrameTask.drawFrame(frameTimeNanos, recordDurationNanos);
 }
 
-CREATE_BRIDGE1(destroyCanvasAndSurface, CanvasContext* context) {
-    args->context->destroyCanvasAndSurface();
+CREATE_BRIDGE1(destroy, CanvasContext* context) {
+    args->context->destroy();
     return NULL;
 }
 
-void RenderProxy::destroyCanvasAndSurface() {
-    SETUP_TASK(destroyCanvasAndSurface);
+void RenderProxy::destroy() {
+    SETUP_TASK(destroy);
     args->context = mContext;
     // destroyCanvasAndSurface() needs a fence as when it returns the
     // underlying BufferQueue is going to be released from under
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 9e6bcf5..8b8d99c 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -73,7 +73,7 @@
     ANDROID_API void setOpaque(bool opaque);
     ANDROID_API int syncAndDrawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos,
             float density);
-    ANDROID_API void destroyCanvasAndSurface();
+    ANDROID_API void destroy();
 
     ANDROID_API static void invokeFunctor(Functor* functor, bool waitForCompletion);
 
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index dd14c11..329033c 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -545,7 +545,7 @@
             "ro.config.vc_call_vol_steps",
            MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
         MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = SystemProperties.getInt(
-            "ro.config.music_vol_steps",
+            "ro.config.media_vol_steps",
            MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]);
 
         sSoundEffectVolumeDb = context.getResources().getInteger(
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 1861bd7..f37cbe5 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -1286,7 +1286,7 @@
 
     public int write(short[] audioData, int offsetInShorts, int sizeInShorts) {
 
-        if (mState == STATE_UNINITIALIZED || mAudioFormat != AudioFormat.ENCODING_PCM_16BIT) {
+        if (mState == STATE_UNINITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
             return ERROR_INVALID_OPERATION;
         }
 
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 6a4bf07..958ffab 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -2131,7 +2131,7 @@
             if (mVolume != volume) {
                 mVolume = volume;
                 if (mSvp != null) {
-                    mSvp.notifyVolumeChanged();
+                    mSvp.setCurrentVolume(mVolume);
                 }
                 dispatchRouteVolumeChanged(this);
                 if (mGroup != null) {
@@ -2217,7 +2217,7 @@
                 // Only register a new listener if necessary
                 if (mSvp == null || mSvp.getVolumeControl() != volumeControl
                         || mSvp.getMaxVolume() != mVolumeMax) {
-                    mSvp = new SessionVolumeProvider(volumeControl, mVolumeMax);
+                    mSvp = new SessionVolumeProvider(volumeControl, mVolumeMax, mVolume);
                     session.setPlaybackToRemote(mSvp);
                 }
             } else {
@@ -2231,13 +2231,8 @@
 
         class SessionVolumeProvider extends VolumeProvider {
 
-            public SessionVolumeProvider(int volumeControl, int maxVolume) {
-                super(volumeControl, maxVolume);
-            }
-
-            @Override
-            public int onGetCurrentVolume() {
-                return mVcb == null ? 0 : mVcb.route.mVolume;
+            public SessionVolumeProvider(int volumeControl, int maxVolume, int currentVolume) {
+                super(volumeControl, maxVolume, currentVolume);
             }
 
             @Override
diff --git a/media/java/android/media/VolumeProvider.java b/media/java/android/media/VolumeProvider.java
index 9bda1d4..5d1e004 100644
--- a/media/java/android/media/VolumeProvider.java
+++ b/media/java/android/media/VolumeProvider.java
@@ -19,7 +19,9 @@
 
 /**
  * Handles requests to adjust or set the volume on a session. This is also used
- * to push volume updates back to the session after a request has been handled.
+ * to push volume updates back to the session. The provider must call
+ * {@link #setCurrentVolume(int)} each time the volume being provided changes.
+ * <p>
  * You can set a volume provider on a session by calling
  * {@link MediaSession#setPlaybackToRemote}.
  */
@@ -46,29 +48,26 @@
 
     private final int mControlType;
     private final int mMaxVolume;
+    private int mCurrentVolume;
     private Callback mCallback;
 
     /**
      * Create a new volume provider for handling volume events. You must specify
-     * the type of volume control and the maximum volume that can be used.
+     * the type of volume control, the maximum volume that can be used, and the
+     * current volume on the output.
      *
      * @param volumeControl The method for controlling volume that is used by
      *            this provider.
      * @param maxVolume The maximum allowed volume.
+     * @param currentVolume The current volume on the output.
      */
-    public VolumeProvider(int volumeControl, int maxVolume) {
+    public VolumeProvider(int volumeControl, int maxVolume, int currentVolume) {
         mControlType = volumeControl;
         mMaxVolume = maxVolume;
+        mCurrentVolume = currentVolume;
     }
 
     /**
-     * Get the current volume of the remote playback.
-     *
-     * @return The current volume.
-     */
-    public abstract int onGetCurrentVolume();
-
-    /**
      * Get the volume control type that this volume provider uses.
      *
      * @return The volume control type for this volume provider
@@ -87,9 +86,23 @@
     }
 
     /**
-     * Notify the system that the volume has been changed.
+     * Gets the current volume. This will be the last value set by
+     * {@link #setCurrentVolume(int)}.
+     *
+     * @return The current volume.
      */
-    public final void notifyVolumeChanged() {
+    public final int getCurrentVolume() {
+        return mCurrentVolume;
+    }
+
+    /**
+     * Notify the system that the current volume has been changed. This must be
+     * called every time the volume changes to ensure it is displayed properly.
+     *
+     * @param currentVolume The current volume on the output.
+     */
+    public final void setCurrentVolume(int currentVolume) {
+        mCurrentVolume = currentVolume;
         if (mCallback != null) {
             mCallback.onVolumeChanged(this);
         }
@@ -97,6 +110,8 @@
 
     /**
      * Override to handle requests to set the volume of the current output.
+     * After the volume has been modified {@link #setCurrentVolume} must be
+     * called to notify the system.
      *
      * @param volume The volume to set the output to.
      */
@@ -107,7 +122,9 @@
      * Override to handle requests to adjust the volume of the current output.
      * Direction will be one of {@link AudioManager#ADJUST_LOWER},
      * {@link AudioManager#ADJUST_RAISE}, {@link AudioManager#ADJUST_SAME}.
-     * 
+     * After the volume has been modified {@link #setCurrentVolume} must be
+     * called to notify the system.
+     *
      * @param direction The direction to change the volume in.
      */
     public void onAdjustVolume(int direction) {
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 095f885..8cb039ab 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -300,7 +300,7 @@
         try {
             mBinder.setPlaybackToRemote(volumeProvider.getVolumeControl(),
                     volumeProvider.getMaxVolume());
-            mBinder.setCurrentVolume(volumeProvider.onGetCurrentVolume());
+            mBinder.setCurrentVolume(volumeProvider.getCurrentVolume());
         } catch (RemoteException e) {
             Log.wtf(TAG, "Failure in setPlaybackToRemote.", e);
         }
@@ -478,7 +478,7 @@
             return;
         }
         try {
-            mBinder.setCurrentVolume(provider.onGetCurrentVolume());
+            mBinder.setCurrentVolume(provider.getCurrentVolume());
         } catch (RemoteException e) {
             Log.e(TAG, "Error in notifyVolumeChanged", e);
         }
diff --git a/media/java/android/media/tv/TvContentRating.java b/media/java/android/media/tv/TvContentRating.java
index d5bf38c..7d1c7c6 100644
--- a/media/java/android/media/tv/TvContentRating.java
+++ b/media/java/android/media/tv/TvContentRating.java
@@ -44,45 +44,47 @@
  * {@literal
  * <rating-system-definitions xmlns:android="http://schemas.android.com/apk/res/android"
  *     android:versionCode="1">
- *     <!-- TV content rating system for US TV -->
  *     <rating-system-definition android:name="US_TV"
- *         android:title="US-TV"
- *         android:description="@string/description_ustv"
- *         android:country="US">
+ *         android:country="US"
+ *         android:description="@string/description_us_tv">
  *         <sub-rating-definition android:name="US_TV_D"
  *             android:title="D"
- *             android:description="@string/description_ustv_d" />
+ *             android:description="@string/description_us_tv_d" />
  *         <sub-rating-definition android:name="US_TV_L"
  *             android:title="L"
- *             android:description="@string/description_ustv_l" />
+ *             android:description="@string/description_us_tv_l" />
  *         <sub-rating-definition android:name="US_TV_S"
  *             android:title="S"
- *             android:description="@string/description_ustv_s" />
+ *             android:description="@string/description_us_tv_s" />
  *         <sub-rating-definition android:name="US_TV_V"
  *             android:title="V"
- *             android:description="@string/description_ustv_v" />
+ *             android:description="@string/description_us_tv_v" />
  *         <sub-rating-definition android:name="US_TV_FV"
  *             android:title="FV"
- *             android:description="@string/description_ustv_fv" />
+ *             android:description="@string/description_us_tv_fv" />
  *
  *         <rating-definition android:name="US_TV_Y"
  *             android:title="TV-Y"
- *             android:description="@string/description_ustv_y"
- *             android:ageHint="0" />
+ *             android:description="@string/description_us_tv_y"
+ *             android:icon="@drawable/icon_us_tv_y"
+ *             android:contentAgeHint="0" />
  *         <rating-definition android:name="US_TV_Y7"
  *             android:title="TV-Y7"
- *             android:description="@string/description_ustv_y7"
- *             android:ageHint="7">
+ *             android:description="@string/description_us_tv_y7"
+ *             android:icon="@drawable/icon_us_tv_y7"
+ *             android:contentAgeHint="7">
  *             <sub-rating android:name="US_TV_FV" />
  *         </rating-definition>
  *         <rating-definition android:name="US_TV_G"
  *             android:title="TV-G"
- *             android:description="@string/description_ustv_g"
- *             android:ageHint="0" />
+ *             android:description="@string/description_us_tv_g"
+ *             android:icon="@drawable/icon_us_tv_g"
+ *             android:contentAgeHint="0" />
  *         <rating-definition android:name="US_TV_PG"
  *             android:title="TV-PG"
- *             android:description="@string/description_ustv_pg"
- *             android:ageHint="14">
+ *             android:description="@string/description_us_tv_pg"
+ *             android:icon="@drawable/icon_us_tv_pg"
+ *             android:contentAgeHint="14">
  *             <sub-rating android:name="US_TV_D" />
  *             <sub-rating android:name="US_TV_L" />
  *             <sub-rating android:name="US_TV_S" />
@@ -90,8 +92,9 @@
  *         </rating-definition>
  *         <rating-definition android:name="US_TV_14"
  *             android:title="TV-14"
- *             android:description="@string/description_ustv_14"
- *             android:ageHint="14">
+ *             android:description="@string/description_us_tv_14"
+ *             android:icon="@drawable/icon_us_tv_14"
+ *             android:contentAgeHint="14">
  *             <sub-rating android:name="US_TV_D" />
  *             <sub-rating android:name="US_TV_L" />
  *             <sub-rating android:name="US_TV_S" />
@@ -99,8 +102,9 @@
  *         </rating-definition>
  *         <rating-definition android:name="US_TV_MA"
  *             android:title="TV-MA"
- *             android:description="@string/description_ustv_ma"
- *             android:ageHint="17">
+ *             android:description="@string/description_us_tv_ma"
+ *             android:icon="@drawable/icon_us_tv_ma"
+ *             android:contentAgeHint="17">
  *             <sub-rating android:name="US_TV_L" />
  *             <sub-rating android:name="US_TV_S" />
  *             <sub-rating android:name="US_TV_V" />
@@ -175,8 +179,12 @@
  *         <td>TV content rating system for Brazil</td>
  *     </tr>
  *     <tr>
- *         <td>CA_TV</td>
- *         <td>TV content rating system for Canada</td>
+ *         <td>CA_TV_CA</td>
+ *         <td>TV content rating system for Canada (Canadian)</td>
+ *     </tr>
+ *     <tr>
+ *         <td>CA_TV_QC</td>
+ *         <td>TV content rating system for Canada (Quebec)</td>
  *     </tr>
  *     <tr>
  *         <td>CH_TV</td>
@@ -503,42 +511,67 @@
  *         <td>Content suitable for viewers over the age of 18</td>
  *     </tr>
  *     <tr>
- *         <td valign="top" rowspan="7">CA_TV</td>
- *         <td>CA_TV_EXEMPT</td>
- *         <td>Shows which are exempt from ratings (such as news and sports programming) will not
- *         display an on-screen rating at all</td>
+ *         <td valign="top" rowspan="7">CA_TV_CA</td>
+ *         <td>CA_TV_CA_EXEMPT</td>
+ *         <td>Exempt from ratings and won't display an on-screen rating</td>
  *     </tr>
  *     <tr>
- *         <td>CA_TV_C</td>
- *         <td>Programming suitable for children ages of 2-7 years. No profanity or sexual content
- *         of any level allowed. Contains little violence</td>
+ *         <td>CA_TV_CA_C</td>
+ *         <td>Suitable for children ages 2-7. May contain mild violence</td>
  *     </tr>
  *     <tr>
- *         <td>CA_TV_C8</td>
- *         <td>Suitable for children ages 8+. Low level violence and fantasy horror is allowed. No
- *         foul language is allowed, but occasional "socially offensive and discriminatory" language
- *         is allowed if in the context of the story. No sexual content of any level allowed</td>
+ *         <td>CA_TV_CA_C8</td>
+ *         <td>Suitable for children ages 8 and older. May contain mild violence, fantasy horror,
+ *         and socially offensive language</td>
  *     </tr>
  *     <tr>
- *         <td>CA_TV_G</td>
- *         <td>Suitable for general audiences. Programming suitable for the entire family with mild
- *         violence, and mild profanity and/or censored language</td>
+ *         <td>CA_TV_CA_G</td>
+ *         <td>Suitable for the entire family and may contain mild violence, profanity, and censored
+ *         language</td>
  *     </tr>
  *     <tr>
- *         <td>CA_TV_PG</td>
- *         <td>Parental guidance. Moderate violence and moderate profanity is allowed, as is brief
- *         nudity and sexual references if important to the context of the story</td>
+ *         <td>CA_TV_CA_PG</td>
+ *         <td>May contain moderate violence, profanity, nudity, and sexual references</td>
  *     </tr>
  *     <tr>
- *         <td>CA_TV_14</td>
- *         <td>Programming intended for viewers ages 14 and older. May contain strong violence and
- *         strong profanity, and depictions of sexual activity as long as they are within the
- *         context of a story</td>
+ *         <td>CA_TV_CA_14</td>
+ *         <td>Intended for viewers ages 14 and older. May contain strong violence and profanity,
+ *         and depictions of sexual activity</td>
  *     </tr>
  *     <tr>
- *         <td>CA_TV_18</td>
- *         <td>Programming intended for viewers ages 18 and older. May contain explicit violence and
- *         sexual activity</td>
+ *         <td>CA_TV_CA_18</td>
+ *         <td>Intended for viewers ages 18 and older. May contain explicit violence and sexual
+ *         activity</td>
+ *     </tr>
+ *     <tr>
+ *         <td valign="top" rowspan="6">CA_TV_QC</td>
+ *         <td>CA_TV_QC_E</td>
+ *         <td>Exempt from ratings and won't display an on-screen rating</td>
+ *     </tr>
+ *     <tr>
+ *         <td>CA_TV_QC_G</td>
+ *         <td>Appropriate for all ages and must contain little or no violence and little to no
+ *         sexual content</td>
+ *     </tr>
+ *     <tr>
+ *         <td>CA_TV_QC_8</td>
+ *         <td>Appropriate for children 8 and may contain with little violence, language, and little
+ *         to no sexual situations</td>
+ *     </tr>
+ *     <tr>
+ *         <td>CA_TV_QC_13</td>
+ *         <td>Suitable for children 13 and may contain with moderate violence, language, and some
+ *         sexual situations</td>
+ *     </tr>
+ *     <tr>
+ *         <td>CA_TV_QC_16</td>
+ *         <td>Recommended for children over the age of 16 and may contain with strong violence,
+ *         strong language, and strong sexual content</td>
+ *     </tr>
+ *     <tr>
+ *         <td>CA_TV_QC_18</td>
+ *         <td>Only to be viewed by adults and may contain extreme violence and graphic sexual
+ *         content. It is mostly used for 18+ movies and pornography</td>
  *     </tr>
  *     <tr>
  *         <td valign="top" rowspan="2">CH_TV</td>
diff --git a/packages/DocumentsUI/res/values-cs/strings.xml b/packages/DocumentsUI/res/values-cs/strings.xml
index b08fdab..36bb72f 100644
--- a/packages/DocumentsUI/res/values-cs/strings.xml
+++ b/packages/DocumentsUI/res/values-cs/strings.xml
@@ -17,10 +17,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="2783841764617238354">"Dokumenty"</string>
-    <string name="title_open" msgid="4353228937663917801">"Otevřít z"</string>
+    <string name="title_open" msgid="4353228937663917801">"Otevřít"</string>
     <string name="title_save" msgid="2433679664882857999">"Uložit do"</string>
     <string name="menu_create_dir" msgid="5947289605844398389">"Vytvořit složku"</string>
-    <string name="menu_grid" msgid="6878021334497835259">"Mřížka"</string>
+    <string name="menu_grid" msgid="6878021334497835259">"Mřížkové zobrazení"</string>
     <string name="menu_list" msgid="7279285939892417279">"Seznam"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Řadit podle"</string>
     <string name="menu_search" msgid="3816712084502856974">"Hledat"</string>
@@ -34,7 +34,7 @@
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Zobrazit SD kartu"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Skrýt interní úložiště"</string>
     <string name="menu_advanced_hide" product="default" msgid="4845869969015718848">"Skrýt SD kartu"</string>
-    <string name="menu_file_size_show" msgid="3240323619260823076">"Zobr. velikost souboru"</string>
+    <string name="menu_file_size_show" msgid="3240323619260823076">"Zobrazit velikost souboru"</string>
     <string name="menu_file_size_hide" msgid="8881975928502581042">"Skrýt velikost souboru"</string>
     <string name="mode_selected_count" msgid="459111894725594625">"Vybráno: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="sort_name" msgid="9183560467917256779">"Podle názvu"</string>
diff --git a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
index 73b11f3..e0507a8 100644
--- a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
@@ -99,8 +99,7 @@
         // TODO: implement a shorter timeout once new PowerManager API is ready.
         // should be the equivalent to the old userActivity(EMERGENCY_CALL_TIMEOUT)
         mPowerManager.userActivity(SystemClock.uptimeMillis(), true);
-        if (TelephonyManager.getDefault().getCallState()
-                == TelephonyManager.CALL_STATE_OFFHOOK) {
+        if (mLockPatternUtils.isInCall()) {
             mLockPatternUtils.resumeCall();
         } else {
             final boolean bypassHandler = true;
@@ -115,7 +114,7 @@
 
     private void updateEmergencyCallButton(State simState, int phoneState) {
         boolean enabled = false;
-        if (phoneState == TelephonyManager.CALL_STATE_OFFHOOK) {
+        if (mLockPatternUtils.isInCall()) {
             enabled = true; // always show "return to call" if phone is off-hook
         } else if (mLockPatternUtils.isEmergencyCallCapable()) {
             boolean simLocked = KeyguardUpdateMonitor.getInstance(mContext).isSimLocked();
diff --git a/packages/PrintSpooler/Android.mk b/packages/PrintSpooler/Android.mk
index 4948a02..6e1402c 100644
--- a/packages/PrintSpooler/Android.mk
+++ b/packages/PrintSpooler/Android.mk
@@ -26,3 +26,5 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 android-support-v7-recyclerview
 
 include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under, $(LOCAL_PATH))
\ No newline at end of file
diff --git a/packages/PrintSpooler/jni/Android.mk b/packages/PrintSpooler/jni/Android.mk
new file mode 100644
index 0000000..fe7d06b
--- /dev/null
+++ b/packages/PrintSpooler/jni/Android.mk
@@ -0,0 +1,19 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+    com_android_printspooler_util_BitmapSerializeUtils.cpp \
+
+LOCAL_C_INCLUDES += \
+    $(JNI_H_INCLUDE)
+
+LOCAL_SHARED_LIBRARIES := \
+    libnativehelper \
+    libjnigraphics \
+    liblog
+
+LOCAL_MODULE := libprintspooler_jni
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp b/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp
new file mode 100644
index 0000000..57281c8
--- /dev/null
+++ b/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "BitmapSerializeUtils"
+
+#include <jni.h>
+#include <JNIHelp.h>
+
+#include <android/bitmap.h>
+#include <android/log.h>
+
+namespace android {
+
+#define RGBA_8888_COLOR_DEPTH 4
+
+static bool writeAllBytes(const int fd, void* buffer, const size_t byteCount) {
+    char* writeBuffer = static_cast<char*>(buffer);
+    size_t remainingBytes = byteCount;
+    while (remainingBytes > 0) {
+        ssize_t writtenByteCount = write(fd, writeBuffer, remainingBytes);
+        if (writtenByteCount == -1) {
+            if (errno == EINTR) {
+                continue;
+            }
+            __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
+                    "Error writing to buffer: %d", errno);
+            return false;
+        }
+        remainingBytes -= writtenByteCount;
+        writeBuffer += writtenByteCount;
+    }
+    return true;
+}
+
+static bool readAllBytes(const int fd, void* buffer, const size_t byteCount) {
+    char* readBuffer = static_cast<char*>(buffer);
+    size_t remainingBytes = byteCount;
+    while (remainingBytes > 0) {
+        ssize_t readByteCount = read(fd, readBuffer, remainingBytes);
+        if (readByteCount == -1) {
+            if (errno == EINTR) {
+                continue;
+            }
+            __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
+                    "Error reading from buffer: %d", errno);
+            return false;
+        }
+        remainingBytes -= readByteCount;
+        readBuffer += readByteCount;
+    }
+    return true;
+}
+
+static void throwException(JNIEnv* env, const char* className, const char* message) {
+    jclass exceptionClass = env->FindClass(className);
+    env->ThrowNew(exceptionClass, message);
+}
+
+static void throwIllegalStateException(JNIEnv* env, char *message) {
+    const char* className = "java/lang/IllegalStateException";
+    throwException(env, className, message);
+}
+
+static void throwIllegalArgumentException(JNIEnv* env, char* message) {
+    const char* className = "java/lang/IllegalArgumentException";
+    throwException(env, className, message);
+}
+
+static void readBitmapPixels(JNIEnv* env, jclass clazz, jobject jbitmap, jint fd) {
+    // Read the info.
+    AndroidBitmapInfo readInfo;
+    bool read = readAllBytes(fd, (void*) &readInfo, sizeof(AndroidBitmapInfo));
+    if (!read) {
+        throwIllegalStateException(env, (char*) "Cannot read bitmap info");
+        return;
+    }
+
+    // Get the info of the target bitmap.
+    AndroidBitmapInfo targetInfo;
+    int result = AndroidBitmap_getInfo(env, jbitmap, &targetInfo);
+    if (result < 0) {
+        throwIllegalStateException(env, (char*) "Cannot get bitmap info");
+        return;
+    }
+
+    // Enforce we can reuse the bitmap.
+    if (readInfo.width != targetInfo.width || readInfo.height != targetInfo.height
+            || readInfo.stride != targetInfo.stride || readInfo.format != targetInfo.format
+            || readInfo.flags != targetInfo.flags) {
+        throwIllegalArgumentException(env, (char*) "Cannot reuse bitmap");
+        return;
+    }
+
+    // Lock the pixels.
+    void* pixels;
+    result = AndroidBitmap_lockPixels(env, jbitmap, &pixels);
+    if (result < 0) {
+        throwIllegalStateException(env, (char*) "Cannot lock bitmap pixels");
+        return;
+    }
+
+    // Read the pixels.
+    size_t byteCount = readInfo.stride * readInfo.height;
+    read = readAllBytes(fd, (void*) pixels, byteCount);
+    if (!read) {
+        throwIllegalStateException(env, (char*) "Cannot read bitmap pixels");
+        return;
+    }
+
+    // Unlock the pixels.
+    result = AndroidBitmap_unlockPixels(env, jbitmap);
+    if (result < 0) {
+        throwIllegalStateException(env, (char*) "Cannot unlock bitmap pixels");
+    }
+}
+
+static void writeBitmapPixels(JNIEnv* env, jclass clazz, jobject jbitmap, jint fd) {
+    // Get the info.
+    AndroidBitmapInfo info;
+    int result = AndroidBitmap_getInfo(env, jbitmap, &info);
+    if (result < 0) {
+        throwIllegalStateException(env, (char*) "Cannot get bitmap info");
+        return;
+    }
+
+    // Write the info.
+    bool written = writeAllBytes(fd, (void*) &info, sizeof(AndroidBitmapInfo));
+    if (!written) {
+        throwIllegalStateException(env, (char*) "Cannot write bitmap info");
+        return;
+    }
+
+    // Lock the pixels.
+    void* pixels;
+    result = AndroidBitmap_lockPixels(env, jbitmap, &pixels);
+    if (result < 0) {
+        throwIllegalStateException(env, (char*) "Cannot lock bitmap pixels");
+        return;
+    }
+
+    // Write the pixels.
+    size_t byteCount = info.stride * info.height;
+    written = writeAllBytes(fd, (void*) pixels, byteCount);
+    if (!written) {
+        throwIllegalStateException(env, (char*) "Cannot write bitmap pixels");
+        return;
+    }
+
+    // Unlock the pixels.
+    result = AndroidBitmap_unlockPixels(env, jbitmap);
+    if (result < 0) {
+        throwIllegalStateException(env, (char*) "Cannot unlock bitmap pixels");
+    }
+}
+
+static JNINativeMethod sMethods[] = {
+    {"nativeReadBitmapPixels", "(Landroid/graphics/Bitmap;I)V", (void *) readBitmapPixels},
+    {"nativeWriteBitmapPixels", "(Landroid/graphics/Bitmap;I)V", (void *) writeBitmapPixels},
+};
+
+int register_com_android_printspooler_util_BitmapSerializeUtils(JNIEnv* env) {
+    return jniRegisterNativeMethods(env, "com/android/printspooler/util/BitmapSerializeUtils",
+        sMethods, NELEM(sMethods));
+}
+
+}
+
+jint JNI_OnLoad(JavaVM* jvm, void*) {
+    JNIEnv *env = NULL;
+    if (jvm->GetEnv((void**) &env, JNI_VERSION_1_6)) {
+        return JNI_ERR;
+    }
+
+    if (android::register_com_android_printspooler_util_BitmapSerializeUtils(env) == -1) {
+        return JNI_ERR;
+    }
+
+    return JNI_VERSION_1_6;
+}
diff --git a/packages/PrintSpooler/res/layout/print_activity.xml b/packages/PrintSpooler/res/layout/print_activity.xml
index 761d58a..30b96292 100644
--- a/packages/PrintSpooler/res/layout/print_activity.xml
+++ b/packages/PrintSpooler/res/layout/print_activity.xml
@@ -33,7 +33,7 @@
 
         <Spinner
             android:id="@+id/destination_spinner"
-            android:layout_width="wrap_content"
+            android:layout_width="@dimen/preview_destination_spinner_width"
             android:layout_height="wrap_content"
             android:layout_marginTop="4dip"
             android:dropDownWidth="wrap_content"
diff --git a/packages/PrintSpooler/res/values-sw600dp-land/constants.xml b/packages/PrintSpooler/res/values-sw600dp-land/constants.xml
index f60d8e4..f7f8a18 100644
--- a/packages/PrintSpooler/res/values-sw600dp-land/constants.xml
+++ b/packages/PrintSpooler/res/values-sw600dp-land/constants.xml
@@ -17,6 +17,9 @@
 <resources>
 
     <integer name="print_option_column_count">6</integer>
+
     <integer name="preview_page_per_row_count">4</integer>
 
+    <dimen name="preview_destination_spinner_width">256dip</dimen>
+
 </resources>
diff --git a/packages/PrintSpooler/res/values/constants.xml b/packages/PrintSpooler/res/values/constants.xml
index b4e4777..357d3e1 100644
--- a/packages/PrintSpooler/res/values/constants.xml
+++ b/packages/PrintSpooler/res/values/constants.xml
@@ -45,4 +45,6 @@
     <dimen name="preview_page_footer_height">32dip</dimen>
     <dimen name="preview_page_min_width">128dip</dimen>
 
+    <dimen name="preview_destination_spinner_width">192dip</dimen>
+
 </resources>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
index cd2ccbd..a581e8a 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
@@ -22,15 +22,15 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
 import android.graphics.Color;
-import android.graphics.Rect;
 import android.graphics.drawable.BitmapDrawable;
 import android.os.AsyncTask;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.print.PrintAttributes;
+import android.print.PrintAttributes.MediaSize;
+import android.print.PrintAttributes.Margins;
 import android.print.PrintDocumentInfo;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -38,10 +38,10 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.printspooler.renderer.IPdfRenderer;
 import com.android.printspooler.renderer.PdfRendererService;
+import com.android.printspooler.util.BitmapSerializeUtils;
 import dalvik.system.CloseGuard;
 import libcore.io.IoUtils;
 
-import java.io.FileDescriptor;
 import java.io.IOException;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
@@ -354,13 +354,14 @@
     public static final class RenderSpec {
         final int bitmapWidth;
         final int bitmapHeight;
-        final PrintAttributes printAttributes;
+        final PrintAttributes printAttributes = new PrintAttributes.Builder().build();
 
         public RenderSpec(int bitmapWidth, int bitmapHeight,
-                PrintAttributes printAttributes) {
+                MediaSize mediaSize, Margins minMargins) {
             this.bitmapWidth = bitmapWidth;
             this.bitmapHeight = bitmapHeight;
-            this.printAttributes = printAttributes;
+            printAttributes.setMediaSize(mediaSize);
+            printAttributes.setMinMargins(minMargins);
         }
 
         @Override
@@ -451,6 +452,8 @@
         @GuardedBy("mLock")
         private IPdfRenderer mRenderer;
 
+        private boolean mBoundToService;
+
         public AsyncRenderer(Context context, OnMalformedPdfFileListener malformedPdfFileListener) {
             mContext = context;
             mOnMalformedPdfFileListener = malformedPdfFileListener;
@@ -463,6 +466,7 @@
 
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
+            mBoundToService = true;
             synchronized (mLock) {
                 mRenderer = IPdfRenderer.Stub.asInterface(service);
                 mLock.notifyAll();
@@ -505,6 +509,10 @@
                         } catch (RemoteException re) {
                             Log.e(LOG_TAG, "Cannot open PDF document");
                             return MALFORMED_PDF_FILE_ERROR;
+                        } finally {
+                            // Close the fd as we passed it to another process
+                            // which took ownership.
+                            IoUtils.closeQuietly(source);
                         }
                     }
                 }
@@ -559,7 +567,10 @@
 
                 @Override
                 public void onPostExecute(Void result) {
-                    mContext.unbindService(AsyncRenderer.this);
+                    if (mBoundToService) {
+                        mBoundToService = false;
+                        mContext.unbindService(AsyncRenderer.this);
+                    }
                     mPageContentCache.invalidate();
                     mPageContentCache.clear();
                 }
@@ -804,9 +815,7 @@
                     // ownership, so close our copy for the write to complete.
                     destination.close();
 
-                    BitmapFactory.Options options = new BitmapFactory.Options();
-                    options.inBitmap = bitmap;
-                    BitmapFactory.decodeFileDescriptor(source.getFileDescriptor(), null, options);
+                    BitmapSerializeUtils.readBitmapPixels(bitmap, source);
                 } catch (IOException|RemoteException e) {
                     Log.e(LOG_TAG, "Error rendering page:" + mPageIndex, e);
                 } finally {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
index d1aa33b..09e8b39 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
@@ -55,7 +55,7 @@
 public final class RemotePrintDocument {
     private static final String LOG_TAG = "RemotePrintDocument";
 
-    private static final boolean DEBUG = true;
+    private static final boolean DEBUG = false;
 
     private static final int STATE_INITIAL = 0;
     private static final int STATE_STARTED = 1;
diff --git a/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfRendererService.java b/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfRendererService.java
index a4c6932..4d02c01 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfRendererService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfRendererService.java
@@ -20,6 +20,7 @@
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
+import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.graphics.pdf.PdfRenderer;
@@ -32,8 +33,7 @@
 import android.util.Log;
 import android.view.View;
 import libcore.io.IoUtils;
-
-import java.io.FileOutputStream;
+import com.android.printspooler.util.BitmapSerializeUtils;
 import java.io.IOException;
 
 /**
@@ -76,7 +76,6 @@
         @Override
         public void renderPage(int pageIndex, int bitmapWidth, int bitmapHeight,
                 PrintAttributes attributes, ParcelFileDescriptor destination) {
-            FileOutputStream out = null;
             synchronized (mLock) {
                 try {
                     throwIfNotOpened();
@@ -136,10 +135,8 @@
 
                     page.close();
 
-                    out = new FileOutputStream(destination.getFileDescriptor());
-                    bitmap.compress(Bitmap.CompressFormat.PNG, 0, out);
+                    BitmapSerializeUtils.writeBitmapPixels(bitmap, destination);
                 } finally {
-                    IoUtils.closeQuietly(out);
                     IoUtils.closeQuietly(destination);
                 }
             }
@@ -171,11 +168,13 @@
         private Bitmap getBitmapForSize(int width, int height) {
             if (mBitmap != null) {
                 if (mBitmap.getWidth() == width && mBitmap.getHeight() == height) {
+                    mBitmap.eraseColor(Color.WHITE);
                     return mBitmap;
                 }
                 mBitmap.recycle();
             }
             mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+            mBitmap.eraseColor(Color.WHITE);
             return mBitmap;
         }
 
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java
index ddf637e..2b5b41b 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java
@@ -24,6 +24,7 @@
 import android.print.PrintAttributes.MediaSize;
 import android.print.PrintAttributes.Margins;
 import android.print.PrintDocumentInfo;
+import android.support.v7.widget.GridLayoutManager;
 import android.support.v7.widget.OrientationHelper;
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.RecyclerView.ViewHolder;
@@ -51,7 +52,7 @@
     private final MyHandler mHandler;
 
     private final PageAdapter mPageAdapter;
-    private final StaggeredGridLayoutManager mLayoutManger;
+    private final GridLayoutManager mLayoutManger;
 
     private final PrintOptionsLayout mPrintOptionsLayout;
     private final RecyclerView mRecyclerView;
@@ -73,7 +74,7 @@
         final int columnCount = mActivity.getResources().getInteger(
                 R.integer.preview_page_per_row_count);
 
-        mLayoutManger = new StaggeredGridLayoutManager(columnCount, OrientationHelper.VERTICAL);
+        mLayoutManger = new GridLayoutManager(mActivity, columnCount);
 
         mRecyclerView = (RecyclerView) activity.findViewById(R.id.preview_content);
         mRecyclerView.setLayoutManager(mLayoutManger);
diff --git a/packages/PrintSpooler/src/com/android/printspooler/util/BitmapSerializeUtils.java b/packages/PrintSpooler/src/com/android/printspooler/util/BitmapSerializeUtils.java
new file mode 100644
index 0000000..a1845f6
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/util/BitmapSerializeUtils.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.printspooler.util;
+
+import android.graphics.Bitmap;
+import android.os.ParcelFileDescriptor;
+
+/**
+ * Helper for serialization of bitmaps in the very specific
+ * use case of having the same bitmap on both ends and just
+ * marshaling the pixels from one side to the other.
+ */
+public final class BitmapSerializeUtils {
+
+    static {
+        System.loadLibrary("printspooler_jni");
+    }
+
+    private BitmapSerializeUtils() {
+        /* do nothing */
+    }
+
+    /**
+     * Reads a bitmap pixels from a file descriptor.
+     *
+     * @param bitmap A bitmap whose pixels to populate.
+     * @param source The source file descriptor.
+     */
+    public static void readBitmapPixels(Bitmap bitmap, ParcelFileDescriptor source) {
+        nativeReadBitmapPixels(bitmap, source.getFd());
+    }
+
+    /**
+     * Writes a bitmap pixels to a file descriptor.
+     *
+     * @param bitmap The bitmap.
+     * @param destination The destination file descriptor.
+     */
+    public static void writeBitmapPixels(Bitmap bitmap, ParcelFileDescriptor destination) {
+        nativeWriteBitmapPixels(bitmap, destination.getFd());
+    }
+
+    private static native void nativeReadBitmapPixels(Bitmap bitmap, int fd);
+
+    private static native void nativeWriteBitmapPixels(Bitmap bitmap, int fd);
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/widget/PageContentView.java b/packages/PrintSpooler/src/com/android/printspooler/widget/PageContentView.java
index 76ff167..23a01bd 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/widget/PageContentView.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/widget/PageContentView.java
@@ -20,7 +20,6 @@
 import android.graphics.Canvas;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.ColorDrawable;
-import android.print.PrintAttributes;
 import android.print.PrintAttributes.MediaSize;
 import android.print.PrintAttributes.Margins;
 import android.util.AttributeSet;
@@ -39,14 +38,18 @@
 public class PageContentView extends View
         implements PageContentRepository.OnPageContentAvailableCallback {
 
-    private final PrintAttributes mAttributes = new PrintAttributes.Builder().build();
-
     private final ColorDrawable mEmptyState;
 
     private PageContentProvider mProvider;
 
+    private MediaSize mMediaSize;
+
+    private Margins mMinMargins;
+
     private boolean mContentRequested;
 
+    private boolean mNeedsLayout;
+
     public PageContentView(Context context, AttributeSet attrs) {
         super(context, attrs);
 
@@ -68,14 +71,14 @@
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
+        mNeedsLayout = false;
         requestPageContentIfNeeded();
     }
 
     @Override
     public void onPageContentAvailable(BitmapDrawable content) {
-        if (getBackground() != content) {
-            setBackground(content);
-        }
+        assert (getBackground() != content);
+        setBackground(content);
     }
 
     public PageContentProvider getPageContentProvider() {
@@ -83,18 +86,23 @@
     }
 
     public void init(PageContentProvider provider, MediaSize mediaSize, Margins minMargins) {
-        if (mProvider == null ? provider == null : mProvider.equals(provider)
-                && ((mAttributes.getMediaSize() == null)
-                        ? mediaSize == null : mAttributes.getMediaSize().equals(mediaSize))
-                && ((mAttributes.getMinMargins() == null)
-                        ? minMargins == null : mAttributes.getMinMargins().equals(minMargins))) {
+        final boolean providerChanged = (mProvider == null)
+                ? provider != null : !mProvider.equals(provider);
+        final boolean mediaSizeChanged = (mMediaSize == null)
+                ? mediaSize != null : !mMediaSize.equals(mediaSize);
+        final boolean marginsChanged = (mMinMargins == null)
+                ? minMargins != null : !mMinMargins.equals(minMargins);
+
+        if (!providerChanged && !mediaSizeChanged && !marginsChanged) {
             return;
         }
 
         mProvider = provider;
-        mAttributes.setMediaSize(mediaSize);
-        mAttributes.setMinMargins(minMargins);
+        mMediaSize = mediaSize;
+        mMinMargins = minMargins;
+
         mContentRequested = false;
+        mNeedsLayout = mNeedsLayout || mediaSizeChanged || marginsChanged;
 
         // If there is no provider we want immediately to switch to
         // the empty state, so pages with no content appear blank.
@@ -106,9 +114,11 @@
     }
 
     private void requestPageContentIfNeeded() {
-        if (getWidth() > 0 && getHeight() > 0 && !mContentRequested && mProvider != null) {
+        if (getWidth() > 0 && getHeight() > 0 && !mContentRequested
+                && mProvider != null && !mNeedsLayout) {
             mContentRequested = true;
-            mProvider.getPageContent(new RenderSpec(getWidth(), getHeight(), mAttributes), this);
+            mProvider.getPageContent(new RenderSpec(getWidth(), getHeight(),
+                    mMediaSize, mMinMargins), this);
         }
     }
 }
diff --git a/packages/SystemUI/res/drawable/ic_info.xml b/packages/SystemUI/res/drawable/ic_info.xml
new file mode 100644
index 0000000..65e7bf5
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_info.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:pathData="M12.000000,2.000000C6.500000,2.000000 2.000000,6.500000 2.000000,12.000000s4.500000,10.000000 10.000000,10.000000c5.500000,0.000000 10.000000,-4.500000 10.000000,-10.000000S17.500000,2.000000 12.000000,2.000000zM13.000000,17.000000l-2.000000,0.000000l0.000000,-6.000000l2.000000,0.000000L13.000000,17.000000zM13.000000,9.000000l-2.000000,0.000000L11.000000,7.000000l2.000000,0.000000L13.000000,9.000000z"
+        android:fillColor="#FFFFFF"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml
index ac8af1b..d52c274 100644
--- a/packages/SystemUI/res/layout/notification_guts.xml
+++ b/packages/SystemUI/res/layout/notification_guts.xml
@@ -77,13 +77,23 @@
         </LinearLayout>
 
         <ImageButton style="@android:style/Widget.Material.Light.Button.Borderless.Small"
+                 android:id="@+id/notification_inspect_app_provided_settings"
+                 android:layout_width="52dp"
+                 android:layout_height="match_parent"
+                 android:layout_weight="0"
+                 android:gravity="center"
+                 android:src="@drawable/ic_settings"
+                 android:visibility="gone"
+                />
+
+        <ImageButton style="@android:style/Widget.Material.Light.Button.Borderless.Small"
                 android:id="@+id/notification_inspect_item"
                 android:layout_width="52dp"
                 android:layout_height="match_parent"
                 android:layout_weight="0"
                 android:gravity="center"
                 android:contentDescription="@string/status_bar_notification_inspect_item_title"
-                android:src="@drawable/ic_settings"
+                android:src="@drawable/ic_info"
                 />
     </LinearLayout>
 </com.android.systemui.statusbar.NotificationGuts>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index df6e9fd..ee27bb2 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -355,13 +355,9 @@
     <string name="monitoring_description_vpn_device_and_profile_owned" msgid="9193588924767232909">"Това у-во се управлява от:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nПотр. ви профил се управлява от:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nАдминистр. ви може да наблюдава акт. ви в мрежата, вкл. имейлите, прилож. и защитените уебсайтове. За още информация се свържете с него.\n\nСъщо така дадохте на <xliff:g id="APPLICATION">%3$s</xliff:g> разрешение да настрои връзка с VPN. Приложението може да наблюдава и акт. в мрежата."</string>
     <string name="monitoring_description_legacy_vpn_device_and_profile_owned" msgid="6935475023447698473">"У-вото се управлява от:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nПотр. ви профил се управлява от:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nАдминистраторът ви може да наблюдава акт. ви в мрежата, вкл. имейлите, прилож. и защитените уебсайтове. За още информация се свържете с него.\n\nСъщо така сте свързани с VPN (<xliff:g id="APPLICATION">%3$s</xliff:g>). Доставчикът ви на услуги за VPN може да наблюдава и акт. ви в мрежата."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Устройството ще остане заключено, докато не го отключите ръчно"</string>
-    <!-- no translation found for hidden_notifications_title (7139628534207443290) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_text (2326409389088668981) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_cancel (3690709735122344913) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_setup (41079514801976810) -->
-    <skip />
+    <string name="hidden_notifications_title" msgid="7139628534207443290">"Получавайте известия по-бързо"</string>
+    <string name="hidden_notifications_text" msgid="2326409389088668981">"Вижте известията, преди да отключите"</string>
+    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"Няма нужда"</string>
+    <string name="hidden_notifications_setup" msgid="41079514801976810">"Настройване"</string>
     <string name="muted_by" msgid="6147073845094180001">"Заглушено от <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index 83a6ba9..812b19c 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -355,13 +355,9 @@
     <string name="monitoring_description_vpn_device_and_profile_owned" msgid="9193588924767232909">"এই ডিভাইসটি পরিচালনা করছে:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nআপনার প্রোফাইলটি পরিচালনা করছে:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nআপনার প্রশাসক ইমেল,অ্যাপ্লিকেশান ও নিরাপদ ওয়েবসাইটগুলি সহ আপনার নেটওয়ার্ক ক্রিয়াকলাপ নিরীক্ষণ করতে সক্ষম। আরো তথ্যের জন্য, আপনার প্রশাসকের সঙ্গে যোগাযোগ করুন।\n\nআপনি \"<xliff:g id="APPLICATION">%3$s</xliff:g>\"-কে একটি VPN সংযোগ সেট আপ করার অনুমতিও দিয়েছেন। এই অ্যাপ্লিকেশান নেটওয়ার্ক ক্রিয়াকলাপও নিরীক্ষণ করতে পারে।"</string>
     <string name="monitoring_description_legacy_vpn_device_and_profile_owned" msgid="6935475023447698473">"এই ডিভাইসটি পরিচালনা করছে:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nআপনার প্রোফাইলটি পরিচালনা করছে:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nআপনার প্রশাসক ইমেল,অ্যাপ্লিকেশান ও নিরাপদ ওয়েবসাইটগুলি সহ আপনার নেটওয়ার্ক ক্রিয়াকলাপ নিরীক্ষণ করতে সক্ষম। আরো তথ্যের জন্য, আপনার প্রশাসকের সঙ্গে যোগাযোগ করুন।\n\nএছাড়াও, আপনি একটি VPN (\"<xliff:g id="APPLICATION">%3$s</xliff:g>\") এ সংযুক্ত আছেন। আপনার VPN পরিষেবা প্রদানকারী নেটওয়ার্ক ক্রিয়াকলাপও নিরীক্ষণ করতে পারে।"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"আপনি নিজে আনলক না করা পর্যন্ত ডিভাইসটি লক হয়ে থাকবে"</string>
-    <!-- no translation found for hidden_notifications_title (7139628534207443290) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_text (2326409389088668981) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_cancel (3690709735122344913) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_setup (41079514801976810) -->
-    <skip />
+    <string name="hidden_notifications_title" msgid="7139628534207443290">"বিজ্ঞপ্তিগুলি আরো দ্রুত পান"</string>
+    <string name="hidden_notifications_text" msgid="2326409389088668981">"আপনি আনলক করার আগে ওগুলো দেখুন"</string>
+    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"না থাক"</string>
+    <string name="hidden_notifications_setup" msgid="41079514801976810">"সেট আপ"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> দ্বারা নিঃশব্দ করা হয়েছে"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 2197cbd3..89911ad 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -69,7 +69,7 @@
     <string name="screenshot_saving_ticker" msgid="7403652894056693515">"Ukládání snímku obrazovky..."</string>
     <string name="screenshot_saving_title" msgid="8242282144535555697">"Ukládání snímku obrazovky..."</string>
     <string name="screenshot_saving_text" msgid="2419718443411738818">"Probíhá ukládání snímku obrazovky."</string>
-    <string name="screenshot_saved_title" msgid="6461865960961414961">"Snímek obrazovky zachycen."</string>
+    <string name="screenshot_saved_title" msgid="6461865960961414961">"Snímek obrazovky Snímek obrazovky pořízen."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Snímek obrazovky zobrazíte dotykem."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Snímek obrazovky se nepodařilo zachytit."</string>
     <string name="screenshot_failed_text" msgid="1260203058661337274">"Snímek obrazovky nelze pořídit kvůli nedostatku místa, nebo to aplikace či vaše organizace zakazuje."</string>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index 126b3f6..5226b9c 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -348,20 +348,16 @@
     <string name="monitoring_description_legacy_vpn" msgid="4740349017929725435">"VPN sarera konektatuta zaude (\"<xliff:g id="APPLICATION">%1$s</xliff:g>\").\n\nVPN zerbitzu-hornitzaileak gailua eta sarean egiten dituzun jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webgune seguruak barne."</string>
     <string name="monitoring_description_vpn_device_owned" msgid="696121105616356493">"Honek kudeatzen du gailua:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nAdministratzaileak sarean egiten dituzun jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webgune seguruak barne.Informazio gehiago lortzeko, jarri administratzailearekin harremanetan.\n\nGainera, VPN konexio bat ezartzeko baimena eman diozu \"<xliff:g id="APPLICATION">%2$s</xliff:g>\" aplikazioari. Aplikazioak ere kontrola ditzake sarean egiten dituzun jarduerak."</string>
     <string name="monitoring_description_legacy_vpn_device_owned" msgid="649791650224064248">"Honek kudeatzen du gailua:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nAdministratzaileak sarean egiten dituzun jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webgune seguruak barne. Informazio gehiago lortzeko, jarri administratzailearekin harremanetan.\n\nGainera, VPN sare batera konektatuta zaude (\"<xliff:g id="APPLICATION">%2$s</xliff:g>\"). VPN hornitzaileak ere kontrola ditzake sarean egiten dituzun jarduerak."</string>
-    <string name="monitoring_description_profile_owned" msgid="2370062794285691713">"Honek kudeatzen du profila:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nAdministratzaileak gailua eta sarean egiten dituzun jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webgune seguruak barne.\n\nInformazio gehiago lortzeko, jarri administratzailearekin harremanetan."</string>
-    <string name="monitoring_description_device_and_profile_owned" msgid="8685301493845456293">"Honek kudeatzen du gailua:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nHonek kudeatzen du profila:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nAdministratzaileak gailua eta sarean egiten dituzun jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webgune segurak barne.\n\nInformazio gehiago lortzeko, jarri administratzailearekin harremanetan."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="847491346263295767">"Honek kudeatzen du profila:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nAdministratzaileak sarean egiten dituzun jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webgune seguruak barne. Informazio gehiago lortzeko, jarri administratzailearekin harremanetan.\n\nGainera, VPN konexioa konfiguratzeko \"<xliff:g id="APPLICATION">%2$s</xliff:g>\" baimena eman duzu. Aplikazio horrek ere kontrola ditzake sarean egiten dituzun jarduerak."</string>
-    <string name="monitoring_description_legacy_vpn_profile_owned" msgid="4095516964132237051">"Honek kudeatzen du profila:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nAdministratzaileak sarean egiten dituzun jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webgune seguruak barne. Informazio gehiago lortzeko, jarri administratzailearekin harremanetan.\n\nGainera, VPN sare batera konektatuta zaude (\"<xliff:g id="APPLICATION">%2$s</xliff:g>\"). VPN hornitzaileak ere kontrola ditzake sarean egiten dituzun jarduerak."</string>
-    <string name="monitoring_description_vpn_device_and_profile_owned" msgid="9193588924767232909">"Honek kudeatzen du gailua:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nHonek kudeatzen du profila:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nAdministratzaileak sarean egiten dituzun jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webgune seguruak barne. Informazio gehiago lortzeko, jarri administratzailearekin harremanetan.\n\nGainera, VPN konexioa konfiguratzeko \"<xliff:g id="APPLICATION">%3$s</xliff:g>\" baimena eman duzu. Aplikazio horrek ere kontrola ditzake sarean egiten dituzun jarduerak."</string>
-    <string name="monitoring_description_legacy_vpn_device_and_profile_owned" msgid="6935475023447698473">"Honek kudeatzen du gailua:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nHonek kudeatzen du profila:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nAdministratzaileak sarean egiten dituzun jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webgune seguruak barne. Informazio gehiago lortzeko, jarri administratzailearekin harremanetan.\n\nGainera, VPN sare batera konektatuta zaude (\"<xliff:g id="APPLICATION">%3$s</xliff:g>\"). VPN hornitzaileak ere kontrola ditzake sarean egiten dituzun jarduerak."</string>
+    <string name="monitoring_description_profile_owned" msgid="2370062794285691713">"Honek kudeatzen du profila:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nAdministratzaileak gailua eta sarean egiten dituzun jarduerak kontrola ditzake, mezuak, aplikazioak eta webgune seguruak barne.\n\nInformazio gehiago lortzeko, jo administratzailearengana."</string>
+    <string name="monitoring_description_device_and_profile_owned" msgid="8685301493845456293">"Honek kudeatzen du gailua:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nHonek kudeatzen du profila:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nAdministratzaileak gailua eta sarean egiten dituzun jarduerak kontrola ditzake, mezuak, aplikazioak eta webgune seguruak barne.\n\nInformazio gehiago lortzeko, jo administratzailearengana."</string>
+    <string name="monitoring_description_vpn_profile_owned" msgid="847491346263295767">"Honek kudeatzen du profila:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nAdministratzaileak sarean egiten dituzun jarduerak kontrola ditzake, mezuak, aplikazioak eta webgune seguruak barne. Info. gehiago lortzeko, jo administratzailearengana.\n\nGainera, VPN konexioa konfiguratzeko \"<xliff:g id="APPLICATION">%2$s</xliff:g>\" baimena eman duzu. Aplikazio horrek ere kontrola ditzake sarean egiten dituzun jarduerak."</string>
+    <string name="monitoring_description_legacy_vpn_profile_owned" msgid="4095516964132237051">"Honek kudeatzen du profila:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nAdministratzaileak sarean egiten dituzun jarduerak kontrola ditzake, mezuak, aplikazioak eta webgune seguruak barne. Info. gehiago lortzeko, jo administratzailearengana.\n\nGainera, VPN sare batera konektatuta zaude (\"<xliff:g id="APPLICATION">%2$s</xliff:g>\"). VPN hornitzaileak ere kontrola ditzake sarean egiten dituzun jarduerak."</string>
+    <string name="monitoring_description_vpn_device_and_profile_owned" msgid="9193588924767232909">"Honek kudeatzen du gailua:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nHonek kudeatzen du profila:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nAdministratzaileak sarean egiten dituzun jarduerak kontrola ditzake, mezuak, aplikazioak eta webgune seguruak barne. Info. gehiago lortzeko, jo administratzailearengana.\n\nGainera, VPN konexioa konfiguratzeko \"<xliff:g id="APPLICATION">%3$s</xliff:g>\" baimena eman duzu. Aplikazio horrek ere kontrola ditzake sarean egiten dituzun jarduerak."</string>
+    <string name="monitoring_description_legacy_vpn_device_and_profile_owned" msgid="6935475023447698473">"Honek kudeatzen du gailua:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nHonek kudeatzen du profila:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nAdministratzaileak sarean egiten dituzun jarduerak kontrola ditzake, mezuak, aplikazioak eta webgune seguruak barne. Info. gehiago lortzeko, jo administratzailearengana.\n\nGainera, VPN sare batera konektatuta zaude (\"<xliff:g id="APPLICATION">%3$s</xliff:g>\"). VPN hornitzaileak ere kontrola ditzake sarean egiten dituzun jarduerak."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Gailua blokeatuta egongo da eskuz desblokeatu arte"</string>
-    <!-- no translation found for hidden_notifications_title (7139628534207443290) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_text (2326409389088668981) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_cancel (3690709735122344913) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_setup (41079514801976810) -->
-    <skip />
+    <string name="hidden_notifications_title" msgid="7139628534207443290">"Eskuratu jakinarazpenak azkarrago"</string>
+    <string name="hidden_notifications_text" msgid="2326409389088668981">"Ikusi desblokeatu baino lehen"</string>
+    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"Ez, eskerrik asko"</string>
+    <string name="hidden_notifications_setup" msgid="41079514801976810">"Konfiguratu"</string>
     <string name="muted_by" msgid="6147073845094180001">"Audioa desaktibatu da (<xliff:g id="THIRD_PARTY">%1$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index f3479af..9f63781 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -355,13 +355,9 @@
     <string name="monitoring_description_vpn_device_and_profile_owned" msgid="9193588924767232909">"‏مدیریت این دستگاه توسط:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nمدیریت نمایه‌تان توسط:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nسرپرستتان می‌تواند فعالیت شبکه‌تان را کنترل کند از جمله ایمیل‌ها، برنامه‌ها و وب‌سایت‌های ایمن. برای کسب اطلاعات بیشتر، با سرپرستتان تماس بگیرید.\n\nهمچنین، به «<xliff:g id="APPLICATION">%3$s</xliff:g>» اجازه دادید اتصال VPN را تنظیم کند. این برنامه می‌تواند فعالیت شبکه‌ را نیز کنترل کند."</string>
     <string name="monitoring_description_legacy_vpn_device_and_profile_owned" msgid="6935475023447698473">"‏مدیریت این دستگاه توسط:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nمدیریت نمایه‌تان توسط:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nسرپرستتان می‌تواند فعالیت شبکه‌تان را کنترل کند از جمله ایمیل‌ها، برنامه‌ها و وب‌سایت‌های ایمن. برای کسب اطلاعات بیشتر، با سرپرستتان تماس بگیرید.\n\nهمچنین، به VPN ‏(«<xliff:g id="APPLICATION">%3$s</xliff:g>») وصل هستید. ارائه‌دهنده سرویس VPN شما می‌تواند فعالیت شبکه را نیز کنترل کند."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"دستگاه قفل باقی می‌ماند تا زمانی که قفل آن را به صورت دستی باز کنید"</string>
-    <!-- no translation found for hidden_notifications_title (7139628534207443290) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_text (2326409389088668981) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_cancel (3690709735122344913) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_setup (41079514801976810) -->
-    <skip />
+    <string name="hidden_notifications_title" msgid="7139628534207443290">"دریافت سریع‌تر اعلان‌ها"</string>
+    <string name="hidden_notifications_text" msgid="2326409389088668981">"قبل از باز کردن قفل آنها را مشاهده کنید"</string>
+    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"خیر، سپاسگزارم"</string>
+    <string name="hidden_notifications_setup" msgid="41079514801976810">"راه‌اندازی"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> آن را بی‌صدا کرد"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 4e595df..e2dd843b 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -357,13 +357,9 @@
     <string name="monitoring_description_vpn_device_and_profile_owned" msgid="9193588924767232909">"Laitteen hallinnoija: \n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nProfiilisi hallinnoija: \n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nJärjestelmänvalvoja voi valvoa toimiasi verkossa, esimerkiksi sähköpostin, sovellusten ja turvallisten verkkosivustojen käyttöä. Saat lisätietoja järjestelmänvalvojalta.\n\nAnnoit sovellukselle <xliff:g id="APPLICATION">%3$s</xliff:g> luvan VPN-yhteyden määrittämiseen. Myös se voi valvoa toimiasi."</string>
     <string name="monitoring_description_legacy_vpn_device_and_profile_owned" msgid="6935475023447698473">"Laitteen hallinnoija: \n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nProfiilisi hallinnoija: \n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nJärjestelmänvalvoja voi valvoa toimiasi verkossa, esimerkiksi sähköpostin, sovellusten ja turvallisten verkkosivustojen käyttöä. Saat lisätietoja järjestelmänvalvojalta.\n\nKäytät VPN-yhteyttä (<xliff:g id="APPLICATION">%3$s</xliff:g>). VPN-palveluntarjoaja voi myös valvoa toimiasi."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Laite pysyy lukittuna, kunnes se avataan käsin"</string>
-    <!-- no translation found for hidden_notifications_title (7139628534207443290) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_text (2326409389088668981) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_cancel (3690709735122344913) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_setup (41079514801976810) -->
-    <skip />
+    <string name="hidden_notifications_title" msgid="7139628534207443290">"Näe ilmoitukset nopeammin"</string>
+    <string name="hidden_notifications_text" msgid="2326409389088668981">"Näytä ennen lukituksen avaamista"</string>
+    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"Ei kiitos"</string>
+    <string name="hidden_notifications_setup" msgid="41079514801976810">"Määritä asetukset"</string>
     <string name="muted_by" msgid="6147073845094180001">"Mykistänyt <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 0282d02..71f042d 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -338,7 +338,7 @@
     <string name="media_projection_action_text" msgid="8470872969457985954">"Commencer maintenant"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Aucune notification"</string>
     <string name="device_owned_footer" msgid="3802752663326030053">"Il est possible que cet appareil soit surveillé."</string>
-    <string name="profile_owned_footer" msgid="8021888108553696069">"Ce profil peut être contrôlé"</string>
+    <string name="profile_owned_footer" msgid="8021888108553696069">"le profil peut être contrôlé"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Le réseau peut être surveillé"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Surveillance d\'appareils"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Contrôle de profil"</string>
@@ -357,13 +357,9 @@
     <string name="monitoring_description_vpn_device_and_profile_owned" msgid="9193588924767232909">"Appareil géré par : \n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nProfil géré par : \n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nVotre administrateur peut surveiller votre activité réseau (courriels, applications et sites sécurisés). Communiquez avec votre administrateur.\n\nEn outre, vous avez autorisé <xliff:g id="APPLICATION">%3$s</xliff:g> à créer une connexion RPV. Cette application peut aussi surveiller l\'activité réseau."</string>
     <string name="monitoring_description_legacy_vpn_device_and_profile_owned" msgid="6935475023447698473">"Appareil géré par : \n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nProfil géré par : \n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nVotre administrateur peut surveiller l\'act. de votre appareil et votre act. réseau (courriels, applications et sites sécurisés). Communiquez avec votre administrateur.\n\nVous êtes aussi connecté à un RPV (<xliff:g id="APPLICATION">%3$s</xliff:g>). Votre admin RPV peut lui aussi surveiller votre act. réseau."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"L\'appareil restera verrouillé jusqu\'à ce que vous le déverrouilliez manuellement"</string>
-    <!-- no translation found for hidden_notifications_title (7139628534207443290) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_text (2326409389088668981) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_cancel (3690709735122344913) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_setup (41079514801976810) -->
-    <skip />
+    <string name="hidden_notifications_title" msgid="7139628534207443290">"Voir les notifications plus rapidement"</string>
+    <string name="hidden_notifications_text" msgid="2326409389088668981">"Afficher les notifications avant de déverrouiller l\'appareil"</string>
+    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"Non, merci"</string>
+    <string name="hidden_notifications_setup" msgid="41079514801976810">"Configurer"</string>
     <string name="muted_by" msgid="6147073845094180001">"Mis en sourdine par <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index daaace4..a85b209 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -357,13 +357,9 @@
     <string name="monitoring_description_vpn_device_and_profile_owned" msgid="9193588924767232909">"Appareil géré par :\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nProfil géré par :\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nVotre administrateur peut contrôler votre activité réseau (e-mails, applications et sites sécurisés). Pour en savoir plus, contactez votre admin.\n\nVous avez donné à l\'appli \"<xliff:g id="APPLICATION">%3$s</xliff:g>\" l\'autorisation de configurer une connexion VPN. Cette appli peut contrôler votre activité réseau."</string>
     <string name="monitoring_description_legacy_vpn_device_and_profile_owned" msgid="6935475023447698473">"Appareil géré par :\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nProfil géré par :\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nVotre administrateur peut contrôler votre activité réseau (e-mails, applications et sites sécurisés). Pour en savoir plus, contactez votre administrateur.\n\nVous êtes aussi connecté à un VPN (\"<xliff:g id="APPLICATION">%3$s</xliff:g>\"). Votre fournisseur de services VPN peut également contrôler l\'activité réseau."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"L\'appareil restera verrouillé jusqu\'à ce que vous le déverrouilliez manuellement."</string>
-    <!-- no translation found for hidden_notifications_title (7139628534207443290) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_text (2326409389088668981) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_cancel (3690709735122344913) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_setup (41079514801976810) -->
-    <skip />
+    <string name="hidden_notifications_title" msgid="7139628534207443290">"Recevoir les notifications plus vite"</string>
+    <string name="hidden_notifications_text" msgid="2326409389088668981">"Afficher les notifications avant de déverrouiller l\'appareil"</string>
+    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"Non, merci"</string>
+    <string name="hidden_notifications_setup" msgid="41079514801976810">"Configurer"</string>
     <string name="muted_by" msgid="6147073845094180001">"Son coupé par : <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index 11f3aa8..af20b98 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -355,13 +355,9 @@
     <string name="monitoring_description_vpn_device_and_profile_owned" msgid="9193588924767232909">"Սարքի կառավարիչն է՝\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nՊրոֆիլի կառավարիչն է՝\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nԱդմինիստրատորը կարող է վերահսկել ձեր ցանցային գործունեությունը՝ նամակները, ծրագրերը և վստահելի կայքերը: Լրացուցիչ տեղեկությունների համար դիմեք ադմինիստրատորին:\n\nԴուք նաև «<xliff:g id="APPLICATION">%3$s</xliff:g>»-ին թույլատրել եք ստեղծել VPN: Այն նույնպես կարող է վերահսկել ցանցային գործունեությունը:"</string>
     <string name="monitoring_description_legacy_vpn_device_and_profile_owned" msgid="6935475023447698473">"Սարքի կառավարիչն է՝\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nՊրոֆիլի կառավարիչն է՝\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nԱդմինիստրատորը կարող է վերահսկել ձեր ցանցային գործունեությունը՝ նամակները, ծրագրերը և վստահելի կայքերը: Այլ տեղեկությունների համար դիմեք ադմինիստրատորին:\n\nԴուք նաև միացած եք VPN-ին («<xliff:g id="APPLICATION">%3$s</xliff:g>»): VPN ծառայություն մատուցողը նույնպես կարող է վերահսկել ցանցային գործունեությունը:"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Սարքը կմնա արգելափակված՝ մինչև ձեռքով չբացեք"</string>
-    <!-- no translation found for hidden_notifications_title (7139628534207443290) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_text (2326409389088668981) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_cancel (3690709735122344913) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_setup (41079514801976810) -->
-    <skip />
+    <string name="hidden_notifications_title" msgid="7139628534207443290">"Ստանալ ծանուցումներն ավելի արագ"</string>
+    <string name="hidden_notifications_text" msgid="2326409389088668981">"Տեսեք դրանք՝ մինչև ապակողպելը"</string>
+    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"Ոչ, շնորհակալություն"</string>
+    <string name="hidden_notifications_setup" msgid="41079514801976810">"Կարգավորել"</string>
     <string name="muted_by" msgid="6147073845094180001">"Համրեցվել է <xliff:g id="THIRD_PARTY">%1$s</xliff:g>-ի կողմից"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 0404ce5..f1aa72c 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -355,15 +355,11 @@
     <string name="monitoring_description_vpn_profile_owned" msgid="847491346263295767">"このプロフィールは次の組織によって管理されています。\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\n管理者はあなたのネットワークアクティビティ(メール、アプリ、保護されたウェブサイトなど)を監視できます。詳しくは管理者にお問い合わせください。\n\nまた、VPN接続を設定する権限を「<xliff:g id="APPLICATION">%2$s</xliff:g>」に付与しているため、このアプリもネットワークアクティビティを監視できます。"</string>
     <string name="monitoring_description_legacy_vpn_profile_owned" msgid="4095516964132237051">"このプロフィールは次の組織によって管理されています。\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\n管理者はあなたのネットワークアクティビティ(メール、アプリ、保護されたウェブサイトなど)を監視できます。詳しくは管理者にお問い合わせください。\n\nまた、VPN(「<xliff:g id="APPLICATION">%2$s</xliff:g>」)に接続しているため、VPNサービスプロバイダもネットワークアクティビティを監視できます。"</string>
     <string name="monitoring_description_vpn_device_and_profile_owned" msgid="9193588924767232909">"この端末は次の組織によって管理されています。\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nあなたのプロフィールは次の組織によって管理されています。\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\n管理者はあなたのネットワークアクティビティ(メール、アプリ、保護されたウェブサイトなど)を監視できます。詳しくは管理者にお問い合わせください。\n\nまた、VPN接続を設定する権限を「<xliff:g id="APPLICATION">%3$s</xliff:g>」に付与しているため、このアプリもネットワークアクティビティを監視できます。"</string>
-    <string name="monitoring_description_legacy_vpn_device_and_profile_owned" msgid="6935475023447698473">"この端末は次の組織によって管理されています。\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nあなたのプロフィールは次の組織によって管理されています。\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\n管理者はあなたのネットワークアクティビティ(メール、アプリ、保護されたウェブサイトなど)を監視できます。詳しくは管理者にお問い合わせください。\n\nまた、VPN(「<xliff:g id="APPLICATION">%3$s</xliff:g>」)に接続しているため、VPNサービスプロバイダもあなたのネットワークアクティビティを監視できます。"</string>
+    <string name="monitoring_description_legacy_vpn_device_and_profile_owned" msgid="6935475023447698473">"この端末は次の組織によって管理されています。\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nあなたのプロフィールは次の組織によって管理されています。\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\n管理者はあなたのネットワークアクティビティ(メール、アプリ、保護されたウェブサイトなど)を監視できます。詳しくは管理者にお問い合わせください。\n\nまた、VPN(「<xliff:g id="APPLICATION">%3$s</xliff:g>」)に接続しているため、VPNサービスプロバイダもネットワークアクティビティを監視できます。"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"手動でロックを解除するまでロックされたままとなります"</string>
-    <!-- no translation found for hidden_notifications_title (7139628534207443290) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_text (2326409389088668981) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_cancel (3690709735122344913) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_setup (41079514801976810) -->
-    <skip />
+    <string name="hidden_notifications_title" msgid="7139628534207443290">"通知をすばやく確認できます"</string>
+    <string name="hidden_notifications_text" msgid="2326409389088668981">"ロックを解除する前にご確認ください"</string>
+    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"キャンセル"</string>
+    <string name="hidden_notifications_setup" msgid="41079514801976810">"設定"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g>によりミュートになっています"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index 30b6d67..e7b272b 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -355,13 +355,9 @@
     <string name="monitoring_description_vpn_device_and_profile_owned" msgid="9193588924767232909">"ამ მოწყობილობის მმართველია:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nთქვენი პროფილის მმართველია:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nთქვენს ადმინისტრატორს შეუძლია თქვენი მოწყობილობისა და ქსელის აქტივობის მონიტორინგი, მათ შორის ელფოსტის, აპების და უსაფრთხო საიტების. დამატებითი ინფორმაციისათვის, დაუკავშირდით ადმინისტრატორს.\n\nასევე, თქვენ მიანიჭეთ „<xliff:g id="APPLICATION">%3$s</xliff:g>“-ს VPN კავშირის დაყენება. ამ აპს ასევე შეუძლია ქსელის მონიტორინგი."</string>
     <string name="monitoring_description_legacy_vpn_device_and_profile_owned" msgid="6935475023447698473">"ამ მოწყობილობის მმართველია:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nთქვენი პროფილის მმართველია:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nთქვენს ადმინისტრატორს შეუძლია თქვენი მოწყობილობისა და ქსელის აქტივობის მონიტორინგი, მათ შორის ელფოსტის, აპების და უსაფრთხო საიტების. დამატებითი ინფორმაციისათვის, დაუკავშირდით ადმინისტრატორს.\n\nასევე, თქვენ დაკავშირებული ხართ VPN-თან („<xliff:g id="APPLICATION">%3$s</xliff:g>“). თქვენს VPN სერვისის მომწოდებელს ასევე შეუძლია თქვენი ქსელის აქტივობის მონიტორინგი."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"მოწყობილობის დარჩება ჩაკეტილი, სანამ ხელით არ გახსნით"</string>
-    <!-- no translation found for hidden_notifications_title (7139628534207443290) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_text (2326409389088668981) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_cancel (3690709735122344913) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_setup (41079514801976810) -->
-    <skip />
+    <string name="hidden_notifications_title" msgid="7139628534207443290">"შეტყობინებების უფრო სწრაფად მიღება"</string>
+    <string name="hidden_notifications_text" msgid="2326409389088668981">"იხილეთ განბლოკვამდე"</string>
+    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"არა, გმადლობთ"</string>
+    <string name="hidden_notifications_setup" msgid="41079514801976810">"დაყენება"</string>
     <string name="muted_by" msgid="6147073845094180001">"დადუმებულია <xliff:g id="THIRD_PARTY">%1$s</xliff:g>-ის მიერ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index 055bee6..e7e7119 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -355,13 +355,9 @@
     <string name="monitoring_description_vpn_device_and_profile_owned" msgid="9193588924767232909">"Бұл құрылғыны басқаратын:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nПрофиліңізді басқаратын:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nӘкімші желілік белс-ті, соның ішінде, эл. хаб-ды, қол-ды және қорғалған веб-сайттарды бақылай алады. Қосымша ақпар. алу үшін әкімшіге хаб-з.\n\nСондай-ақ, сіз «<xliff:g id="APPLICATION">%3$s</xliff:g>» VPN байланысын орнату рұқсатын бердіңіз. Бұл қолданба да желілік белсенділікті бақылай алады."</string>
     <string name="monitoring_description_legacy_vpn_device_and_profile_owned" msgid="6935475023447698473">"Бұл құр. басқаратын:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nПрофиліңізді басқаратын:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nӘкімші желілік белсенділікті, соның ішінде, эл. хаб-ды, қолд-ды және қорғалған веб-сайттарды бақылай алады. Қосымша ақпарат алу үшін әкімшіге хаб-ңыз.\n\nСондай-ақ, VPN (\"<xliff:g id="APPLICATION">%3$s</xliff:g>\") қызметіне қосылғансыз. VPN қызметін жеткізуші де желілік белсенділікті бақылай алады."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Қолмен бекітпесін ашқанша құрылғы бекітілген күйде қалады"</string>
-    <!-- no translation found for hidden_notifications_title (7139628534207443290) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_text (2326409389088668981) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_cancel (3690709735122344913) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_setup (41079514801976810) -->
-    <skip />
+    <string name="hidden_notifications_title" msgid="7139628534207443290">"Хабарландыруларды тезірек алу"</string>
+    <string name="hidden_notifications_text" msgid="2326409389088668981">"Бекітпесін ашу алдында оларды көру"</string>
+    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"Жоқ, рақмет"</string>
+    <string name="hidden_notifications_setup" msgid="41079514801976810">"Реттеу"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> үнін өшірген"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index 252f356..61d4289 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -355,13 +355,9 @@
     <string name="monitoring_description_vpn_device_and_profile_owned" msgid="9193588924767232909">"ឧបករណ៍នេះត្រូវបានគ្រប់គ្រងដោយ៖\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nប្រវត្តិរូបរបស់អ្នកត្រូវបានគ្រប់គ្រង៖\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nអ្នកគ្រប់គ្រងរបស់អ្នកអាចតាមដានសកម្មភាពបណ្ដាញ រួមមានអ៊ីមែល កម្មវិធី និងតំបន់បណ្ដាញមានសុវត្ថិភាព។ ចំពោះព័ត៌មានបន្ថែម ទាក់ទងអ្នកគ្រប់គ្រងរបស់អ្នក។\n\nអ្នកបានផ្ដល់សិទ្ធិ \"<xliff:g id="APPLICATION">%3$s</xliff:g>\" ឲ្យកំណត់ការភ្ជាប់ VPN ។ កម្មវិធីនេះអាចតាមដានសកម្មភាពបណ្ដាញផងដែរ។"</string>
     <string name="monitoring_description_legacy_vpn_device_and_profile_owned" msgid="6935475023447698473">"ឧបករណ៍នេះត្រូវបា​នគ្រប់គ្រងដោយ៖\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nប្រវត្តិរូបរបស់អ្នកត្រូវបានគ្រប់គ្រង​ដោយ៖\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nអ្នកគ្រប់គ្រងរបស់អ្នកអាចតាមដានសកម្មភាពបណ្ដាញរបស់អ្នក  រួមមានអ៊ីមែល, កម្មវិធី និងតំបន់បណ្ដាញមានសុវត្ថិភាព​​​។ ចំពោះព័ត៌មានបន្ថែម ទាក់ទង​អ្នកគ្រប់គ្រងរបស់​អ្នក។\n\nអ្នកក៏បានភ្ជាប់ទៅ​ VPN (\"<xliff:g id="APPLICATION">%3$s</xliff:g>\") ។ ក្រុមហ៊ុនផ្ដល់សេវាកម្ម VPN របស់អ្នកអាចតាមដានសកម្មភាពបណ្ដាញបានផងដែរ។"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"ឧបករណ៍​នឹង​ចាក់​សោ​រហូត​ដល់​អ្នក​ដោះ​សោ​ដោយ​ដៃ"</string>
-    <!-- no translation found for hidden_notifications_title (7139628534207443290) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_text (2326409389088668981) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_cancel (3690709735122344913) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_setup (41079514801976810) -->
-    <skip />
+    <string name="hidden_notifications_title" msgid="7139628534207443290">"ទទួល​បាន​ការ​ជូន​ដំណឹង​កាន់តែ​លឿន"</string>
+    <string name="hidden_notifications_text" msgid="2326409389088668981">"ឃើញ​ពួកវា​មុន​ពេល​ដោះ​សោ"</string>
+    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"ទេ អរគុណ!"</string>
+    <string name="hidden_notifications_setup" msgid="41079514801976810">"រៀបចំ"</string>
     <string name="muted_by" msgid="6147073845094180001">"បាន​បិទ​សំឡេង​ដោយ <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 9d424ae..e73cbde 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -357,13 +357,9 @@
     <string name="monitoring_description_vpn_device_and_profile_owned" msgid="9193588924767232909">"기기 관리자:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\n프로필 관리자:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\n관리자는 이메일, 앱, 보안 웹사이트를 비롯한 내 네트워크 활동을 모니터링할 수 있습니다. 자세한 정보는 관리자에게 문의하세요.\n\n또한 \'<xliff:g id="APPLICATION">%3$s</xliff:g>\'에 VPN 연결을 설정할 수 있는 권한을 부여했습니다. 이 앱에서도 네트워크 활동을 모니터링할 수 있습니다."</string>
     <string name="monitoring_description_legacy_vpn_device_and_profile_owned" msgid="6935475023447698473">"기기 관리자:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\n프로필 관리자:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\n관리자는 이메일, 앱, 보안 웹사이트를 비롯한 내 네트워크 활동을 모니터링할 수 있습니다. 자세한 정보는 관리자에게 문의하세요.\n\n또한 현재 VPN(\'<xliff:g id="APPLICATION">%3$s</xliff:g>\')에 연결되어 있습니다. VPN 서비스 제공업체에서도 네트워크 활동을 모니터링할 수 있습니다."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"수동으로 잠금 해제할 때까지 기기가 잠금 상태로 유지됩니다."</string>
-    <!-- no translation found for hidden_notifications_title (7139628534207443290) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_text (2326409389088668981) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_cancel (3690709735122344913) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_setup (41079514801976810) -->
-    <skip />
+    <string name="hidden_notifications_title" msgid="7139628534207443290">"알림을 더욱 빠르게 받기"</string>
+    <string name="hidden_notifications_text" msgid="2326409389088668981">"잠금 해제하기 전에 알림을 봅니다."</string>
+    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"사용 안함"</string>
+    <string name="hidden_notifications_setup" msgid="41079514801976810">"설정"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g>에서 알림음 음소거"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index 1827c13..a96c88a 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -381,13 +381,9 @@
     <string name="monitoring_description_vpn_device_and_profile_owned" msgid="9193588924767232909">"Бул түзмөктү төмөнкү башк-т:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nПрофилиңизди төмөнкү башк-т:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nАдмин-ңуздун тармак ар-ңизди, анын ичинде email-дер, колд-лор жана коопсуз вебс-ды, көз-дөө мүмк-гү бар. Дагы маалымат үчүн, админ-ңузга кайр-з.\n\n\"<xliff:g id="APPLICATION">%3$s</xliff:g>\" VPN туташуусун орнотуусуна да уруксат бердиңиз. Бул колдонмо тармак аракетин да көзөмөлдөй алат."</string>
     <string name="monitoring_description_legacy_vpn_device_and_profile_owned" msgid="6935475023447698473">"Түзмөктү тө-кү башк-т:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nПрофилди тө-кү башк-т:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nАдмин-ңуздун тармак ар-ңизди, анын ичинде email-дер, колд-лор жана коопсуз вебс-ды, көзөмөлдөө мүмкүнчүлүгү бар. Дагы маалымат үчүн, админ-ңузга кайрылыңыз.\n\nСиз VPN-ге (\"<xliff:g id="APPLICATION">%3$s</xliff:g>\") да туташкансыз. VPN тейлөөчүңүз да тармак аракетин көзөмөлдөй алат."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Түзмөктүн кулпусу кол менен ачылмайынча кулпуланган бойдон алат"</string>
-    <!-- no translation found for hidden_notifications_title (7139628534207443290) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_text (2326409389088668981) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_cancel (3690709735122344913) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_setup (41079514801976810) -->
-    <skip />
+    <string name="hidden_notifications_title" msgid="7139628534207443290">"Эскертмелерди тезирээк алуу"</string>
+    <string name="hidden_notifications_text" msgid="2326409389088668981">"Аларды кулпудан чыгараардан мурун көрүңүз"</string>
+    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"Жок, рахмат"</string>
+    <string name="hidden_notifications_setup" msgid="41079514801976810">"Орнотуу"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> тарабынан үнсүздөлдү"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 6f41766..468f717 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -355,13 +355,9 @@
     <string name="monitoring_description_vpn_device_and_profile_owned" msgid="9193588924767232909">"ອຸ​ປະ​ກອນ​ນີ້​ແມ່ນ​ຈັດ​ການ​ໂດຍ:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nໂປຣ​ໄຟລ໌​ຂອງ​ທ່ານ​ແມ່ນ​ຖືກ​ຈັດ​ການ​ໂດຍ:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nຜູ່​ເບິ່ງ​ແຍງ​ຂອງ​ທ່ານ​ມີ​ຄວາມ​ສາ​ມາດ​ໃນ​ການ​ຕິດ​ຕາມ​ການ​ເຄື່ອນ​ໄຫວ​ໃນ​ເຄືອ​ຂ່າຍ​ຂອງ​ທ່ານ​ໄດ້ ຮວມ​ເຖິງ: ​ອີ​ເມວ, ແອັບຯ ແລະ​ເວັບ​ໄຊ​​ທີ່​ເຂົ້າ​ລະ​ຫັດ. ສຳ​ລັບ​ຂໍ້​ມູນ​ເພີ່ມ​ເຕີມ, ໃຫ້​ຕິດ​ຕໍ່​ຜູ່​ເບິ່ງ​ແຍງ​ລະ​ບົບ​ຂອງ​ທ່ານ.\n\nນອກ​ຈາກ​ນັ້ນ, ທ່ານ​ໄດ້​ອະ​ນຸ​ຍາດ​ໃຫ້ \"<xliff:g id="APPLICATION">%3$s</xliff:g>\" ​ສາ​ມາດ​ຕັ້ງ​ຄ່າ​ການ​ເຊື່ອມ​ຕໍ່ VPN ໄດ້. ແອັບຯ​ນີ້​​ສາ​ມາດ​ຕິດ​ຕາມ​ການ​ເຄື່ອນ​ໄຫວ​ເຄືອ​ຂ່າຍ​ຂອງ​ທ່ານ​ໄດ້​ເຊັ່ນ​ກັນ."</string>
     <string name="monitoring_description_legacy_vpn_device_and_profile_owned" msgid="6935475023447698473">"ອຸ​ປະ​ກອນ​ນີ້​ແມ່ນ​ຈັດ​ການ​ໂດຍ:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nໂປຣ​ໄຟລ໌​ຂອງ​ທ່ານ​ແມ່ນ​ຖືກ​ຈັດ​ການ​ໂດຍ:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nຜູ່​ເບິ່ງ​ແຍງ​ຂອງ​ທ່ານ​ມີ​ຄວາມ​ສາ​ມາດ​ໃນ​ການ​ຕິດ​ຕາມ​ການ​ເຄື່ອນ​ໄຫວ​ໃນ​ເຄືອ​ຂ່າຍ​ຂອງ​ທ່ານ​ໄດ້ ຮວມ​ເຖິງ: ​ອີ​ເມວ, ແອັບຯ ແລະ​ເວັບ​ໄຊ​​ທີ່​ເຂົ້າ​ລະ​ຫັດ. ສຳ​ລັບ​ຂໍ້​ມູນ​ເພີ່ມ​ເຕີມ, ໃຫ້​ຕິດ​ຕໍ່​ຜູ່​ເບິ່ງ​ແຍງ​ລະ​ບົບ​ຂອງ​ທ່ານ.\n\nນອກ​ຈາກ​ນັ້ນ, ທ່ານ​ໄ​ດ້​ເຊື່ອມ​ຕໍ່​ຫາ VPN (\"<xliff:g id="APPLICATION">%3$s</xliff:g>\"). ຜູ່​ໃຫ້​ບໍ​ລິ​ການ VPN ​ຂອງ​ທ່ານ​ສາ​ມາດ​ຕິດ​ຕາມ​ການ​ເຄື່ອນ​ໄຫວ​ເຄືອ​ຂ່າຍ​ໄດ້​ເຊັ່ນ​ກັນ."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Device will stay locked until you manually unlock"</string>
-    <!-- no translation found for hidden_notifications_title (7139628534207443290) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_text (2326409389088668981) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_cancel (3690709735122344913) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_setup (41079514801976810) -->
-    <skip />
+    <string name="hidden_notifications_title" msgid="7139628534207443290">"ຮັບເອົາການ​ແຈ້ງເຕືອນ​ໄວຂຶ້ນ"</string>
+    <string name="hidden_notifications_text" msgid="2326409389088668981">"ເບິ່ງພວກ​ມັນກ່ອນ​ທ່ານຈະ​ປົດລັອກ"</string>
+    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"ບໍ່, ຂອບໃຈ"</string>
+    <string name="hidden_notifications_setup" msgid="41079514801976810">"ຕັ້ງຄ່າ"</string>
     <string name="muted_by" msgid="6147073845094180001">"ຖືກ​ປິດ​ສຽງ​ໂດຍ <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index 12ab9e8..293b028 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -266,7 +266,7 @@
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"ടെതറിംഗ്"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"ഹോട്ട്‌സ്‌പോട്ട്"</string>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"അറിയിപ്പുകൾ"</string>
-    <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"ഫ്‌ലാഷ്‌ലൈറ്റ്"</string>
+    <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"ഫ്ലാഷ്‌ലൈറ്റ്"</string>
     <string name="quick_settings_cellular_detail_title" msgid="8575062783675171695">"സെല്ലുലാർ ഡാറ്റ"</string>
     <string name="quick_settings_cellular_detail_data_usage" msgid="1964260360259312002">"ഡാറ്റ ഉപയോഗം"</string>
     <string name="quick_settings_cellular_detail_remaining_data" msgid="722715415543541249">"ശേഷിക്കുന്ന ഡാറ്റ"</string>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index 1d8e11e..f6c6f8a 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -350,10 +350,10 @@
     <string name="monitoring_description_legacy_vpn_device_owned" msgid="649791650224064248">"हे डिव्हाइस याद्वारे व्यवस्थापित केले जाते:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nआपला प्रशासक ईमेल, अॅप्स आणि सुरक्षित वेबसाइट यासह आपल्या नेटवर्क क्रियाकलापाचे परीक्षण करण्यास सक्षम आहे. अधिक माहितीसाठी, आपल्या प्रशासकाशी संपर्क साधा.\n\nतसेच, आपण एका VPN शी कनेक्ट केले आहे (\"<xliff:g id="APPLICATION">%2$s</xliff:g>\"). आपला VPN सेवा प्रदाता नेटवर्क क्रियाकलापाचे देखील परीक्षण करू शकतो."</string>
     <string name="monitoring_description_profile_owned" msgid="2370062794285691713">"हे प्रोफाईल याद्वारे व्यवस्थापित केले आहे:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nआपला प्रशासक ईमेल, अॅप्स आणि सुरक्षित वेबसाइटसह, आपल्या डिव्हाइसचे आणि नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो.\n\nअधिक माहितीसाठी, आपल्या प्रशासकाशी संपर्क साधा."</string>
     <string name="monitoring_description_device_and_profile_owned" msgid="8685301493845456293">"हे डिव्हाइस याद्वारे व्यवस्थापित केले आहे:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nआपले प्रोफाईल याद्वारे व्यवस्थापित केले आहे:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nआपला प्रशासक ईमेल, अॅप्स आणि सुरक्षित वेबसाइटसह, आपल्या डिव्हाइसचे आणि नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो.\n\nअधिक माहितीसाठी, आपल्या प्रशासकाशी संपर्क साधा."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="847491346263295767">"हे प्रोफाईल याद्वारे व्यवस्थापित केले आहे:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nआपला प्रशासक ईमेल, अॅप्स आणि सुरक्षित वेबसाइटसह, आपल्या नेटवर्क क्रियाकलापाचे परीक्षण करण्यास सक्षम आहे. अधिक माहितीसाठी, आपल्या प्रशासकाशी संपर्क साधा.\n\nतथापि, VPN कनेक्शन सेट करण्यासाठी आपण \"<xliff:g id="APPLICATION">%2$s</xliff:g>\" ला परवानगी दिली आहे. हा अॅप नेटवर्क क्रियाकलापाचे देखील परीक्षण करू शकतो."</string>
-    <string name="monitoring_description_legacy_vpn_profile_owned" msgid="4095516964132237051">"हे प्रोफाईल याद्वारे व्यवस्थापित केले आहे:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nआपला प्रशासक ईमेल, अॅप्स आणि सुरक्षित वेबसाइटसह, आपल्या नेटवर्क क्रियाकलापाचे परीक्षण करण्यास सक्षम आहे. अधिक माहितीसाठी, आपल्या प्रशासकाशी संपर्क साधा.\n\nतथापि, आपण एका VPN (\"<xliff:g id="APPLICATION">%2$s</xliff:g>\") शी कनेक्ट केलेले आहे. आपला VPN सेवा प्रदाता नेटवर्क क्रियाकलापाचे देखील परीक्षण करू शकतो."</string>
-    <string name="monitoring_description_vpn_device_and_profile_owned" msgid="9193588924767232909">"हे डिव्हाइस याद्वारे व्यवस्थापित केले आहे:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nआपले प्रोफाईल याद्वारे व्यवस्थापित केले आहे:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nआपला प्रशासक ईमेल, अॅप्स आणि सुरक्षित वेबसाइटसह, आपल्या नेटवर्क क्रियाकलापाचे परीक्षण करण्यास सक्षम आहे. अधिक माहितीसाठी, आपल्या प्रशासकाशी संपर्क साधा.\n\nतथापि, VPN कनेक्शन सेट करण्यासाठी आपण \"<xliff:g id="APPLICATION">%3$s</xliff:g>\" ला परवानगी दिली आहे. हा अॅप नेटवर्क क्रियाकलापाचे परीक्षण देखील करू शकतो."</string>
-    <string name="monitoring_description_legacy_vpn_device_and_profile_owned" msgid="6935475023447698473">"हे डिव्हाइस याद्वारे व्यवस्थापित केले आहे:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nआपले प्रोफाईल याद्वारे व्यवस्थापित केले आहे:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nआपला प्रशासक ईमेल, अॅप्स आणि सुरक्षित वेबसाइटसह, आपल्या नेटवर्क क्रियाकलापाचे परीक्षण करण्यास सक्षम आहे. अधिक माहितीसाठी, आपल्या प्रशासकाशी संपर्क साधा.\n\nतथापि, आपण एका VPN (\"<xliff:g id="APPLICATION">%3$s</xliff:g>\") शी कनेक्ट केलेले आहे. आपला VPN सेवा प्रदाता नेटवर्क क्रियाकलापाचे देखील परीक्षण करू शकतो."</string>
+    <string name="monitoring_description_vpn_profile_owned" msgid="847491346263295767">"हे प्रोफाईल याद्वारे व्यवस्थापित केले आहे:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nआपला प्रशासक ईमेल, अॅप्स आणि सुरक्षित वेबसाइटसह, आपल्या नेटवर्क क्रियाकलापाचे परीक्षण करण्यास सक्षम आहे. अधिक माहितीसाठी, आपल्या प्रशासकाशी संपर्क साधा.\n\nतसेच, VPN कनेक्शन सेट करण्यासाठी आपण \"<xliff:g id="APPLICATION">%2$s</xliff:g>\" ला परवानगी दिली आहे. हा अॅप नेटवर्क क्रियाकलापाचे देखील परीक्षण करू शकतो."</string>
+    <string name="monitoring_description_legacy_vpn_profile_owned" msgid="4095516964132237051">"हे प्रोफाईल याद्वारे व्यवस्थापित केले आहे:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nआपला प्रशासक ईमेल, अॅप्स आणि सुरक्षित वेबसाइटसह, आपल्या नेटवर्क क्रियाकलापाचे परीक्षण करण्यास सक्षम आहे. अधिक माहितीसाठी, आपल्या प्रशासकाशी संपर्क साधा.\n\nतसेच, आपण एका VPN (\"<xliff:g id="APPLICATION">%2$s</xliff:g>\") शी कनेक्ट केलेले आहे. आपला VPN सेवा प्रदाता नेटवर्क क्रियाकलापाचे देखील परीक्षण करू शकतो."</string>
+    <string name="monitoring_description_vpn_device_and_profile_owned" msgid="9193588924767232909">"हे डिव्हाइस याद्वारे व्यवस्थापित केले आहे:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nआपले प्रोफाईल याद्वारे व्यवस्थापित केले आहे:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nआपला प्रशासक ईमेल, अॅप्स आणि सुरक्षित वेबसाइटसह, आपल्या नेटवर्क क्रियाकलापाचे परीक्षण करण्यास सक्षम आहे. अधिक माहितीसाठी, आपल्या प्रशासकाशी संपर्क साधा.\n\nतसेच, VPN कनेक्शन सेट करण्यासाठी आपण \"<xliff:g id="APPLICATION">%3$s</xliff:g>\" ला परवानगी दिली आहे. हा अॅप नेटवर्क क्रियाकलापाचे परीक्षण देखील करू शकतो."</string>
+    <string name="monitoring_description_legacy_vpn_device_and_profile_owned" msgid="6935475023447698473">"हे डिव्हाइस याद्वारे व्यवस्थापित केले आहे:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nआपले प्रोफाईल याद्वारे व्यवस्थापित केले आहे:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nआपला प्रशासक ईमेल, अॅप्स आणि सुरक्षित वेबसाइटसह, आपल्या नेटवर्क क्रियाकलापाचे परीक्षण करण्यास सक्षम आहे. अधिक माहितीसाठी, आपल्या प्रशासकाशी संपर्क साधा.\n\nतसेच, आपण एका VPN (\"<xliff:g id="APPLICATION">%3$s</xliff:g>\") शी कनेक्ट केलेले आहे. आपला VPN सेवा प्रदाता नेटवर्क क्रियाकलापाचे देखील परीक्षण करू शकतो."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"आपण व्यक्तिचलितपणे अनलॉक करेपर्यंत डिव्हाइस लॉक केलेले राहील"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"सूचना अधिक जलद मिळवा"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"आपण अनलॉक करण्‍यापूर्वी त्यांना पहा"</string>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index df99613..0c0efb3 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -355,13 +355,9 @@
     <string name="monitoring_description_vpn_device_and_profile_owned" msgid="9193588924767232909">"Peranti ini diurus olh:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nProfil anda diurus olh:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nPentadbir anda bkemampuan mmantau aktiviti rgkaian anda tmasuk e-mel, apl dan tapak web yg slmt. Untuk mdptkn maklumat lanjut, hubungi pentadbir anda.\n\nAnda jg mberi \"<xliff:g id="APPLICATION">%3$s</xliff:g>\" kebenaran utk menyediakan smbungn VPN. Apl ini jg blh mmantau aktiviti rngkaian."</string>
     <string name="monitoring_description_legacy_vpn_device_and_profile_owned" msgid="6935475023447698473">"Peranti ini diurus olh:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nProfil anda diurus olh:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nPentadbir anda blh mmantau pranti dn aktiviti rgkaian anda, tmasuk e-mel, apl dan tapak web yg slmt. Utk mdapatkan mklumat lanjut, hubungi pentadbir anda.\n\nAnda juga disambungkn ke VPN (\"<xliff:g id="APPLICATION">%3$s</xliff:g>\"). Pmbekal perkhidmatan VPN anda jg blh memantau rangkaian aktiviti."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Peranti akan kekal terkunci sehingga anda membuka kunci secara manual"</string>
-    <!-- no translation found for hidden_notifications_title (7139628534207443290) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_text (2326409389088668981) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_cancel (3690709735122344913) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_setup (41079514801976810) -->
-    <skip />
+    <string name="hidden_notifications_title" msgid="7139628534207443290">"Dapatkan pemberitahuan lebih cepat"</string>
+    <string name="hidden_notifications_text" msgid="2326409389088668981">"Lihat sebelum anda membuka kunci"</string>
+    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"Tidak, terima kasih"</string>
+    <string name="hidden_notifications_setup" msgid="41079514801976810">"Sediakan"</string>
     <string name="muted_by" msgid="6147073845094180001">"Diredam oleh <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index 8c866a9..df555a6 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -355,13 +355,9 @@
     <string name="monitoring_description_vpn_device_and_profile_owned" msgid="9193588924767232909">"यस उपकरण र तपाईँको प्रोफाइल \n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\n र \n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\n ले व्यवस्थित गरिएको छ। तपाईँको प्रशासकले सञ्जाल गतिविधि निगरानी गर्न सक्षम छन् जस्तै इमेल, अनुप्रयोग र सुरक्षित वेबसाइट। थप जान्न प्रशासकलाई सम्पर्क गर्नुहोला।\n\nसाथै, तपाईँले VPN जडान स्थापित गर्न \"<xliff:g id="APPLICATION">%3$s</xliff:g>\" अनुमति दिनुभयो। यो अनुप्रयोगले संजालको निगरानी पनि गर्न सक्छ।"</string>
     <string name="monitoring_description_legacy_vpn_device_and_profile_owned" msgid="6935475023447698473">"यो उपकरणको व्यवस्थित \n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\n ले गरेको छ। तपाईँको प्रोफाइल \n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\n ले व्यवस्थित गरिएको छ। तपाईँको प्रशासकले सञ्जाल गतिविधि निगरानी गर्न सक्षम छन् जसमा इमेल, अनुप्रयोग र सुरक्षित वेबसाइट छ। थप जान्न प्रशासकलाई सम्पर्क गर्नुहोला।\n\nसाथै, तपाईँ VPN (\"<xliff:g id="APPLICATION">%3$s</xliff:g>\") मा जडित हुनुहुन्छ। जुन सेवा प्रदायकले निगरानी गर्न सक्ने छन्।"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"तपाईँले नखोले सम्म उपकरण बन्द रहनेछ"</string>
-    <!-- no translation found for hidden_notifications_title (7139628534207443290) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_text (2326409389088668981) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_cancel (3690709735122344913) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_setup (41079514801976810) -->
-    <skip />
+    <string name="hidden_notifications_title" msgid="7139628534207443290">"छिटो सूचनाहरू प्राप्त गर्नुहोस्"</string>
+    <string name="hidden_notifications_text" msgid="2326409389088668981">"तपाईँले अनलक गर्नअघि तिनीहरूलाई हेर्नुहोस्"</string>
+    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"धन्यवाद पर्दैन"</string>
+    <string name="hidden_notifications_setup" msgid="41079514801976810">"सेटअप गर्नुहोस्"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> द्वारा मौन गरिएको"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 181f361..4180640 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -357,13 +357,9 @@
     <string name="monitoring_description_vpn_device_and_profile_owned" msgid="9193588924767232909">"Este dispositivo é gerenciado por:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nSeu perfil é gerenciado por:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nO administrador pode monitorar sua atividade na rede, como e-mails, apps e sites seguros. Para mais informações, contate o administrador.\n\nVocê autorizou \"<xliff:g id="APPLICATION">%3$s</xliff:g>\" a fazer conexões VPN e o provedor de serviços de VPN também pode monitorar atividades de rede."</string>
     <string name="monitoring_description_legacy_vpn_device_and_profile_owned" msgid="6935475023447698473">"Este dispositivo é gerenciado por:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nSeu perfil é gerenciado por:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nO administrador pode monitorar sua atividade na rede, como e-mails, apps e sites seguros. Para mais informações, contate o administrador.\n\nVocê está conectado a uma VPN (\"<xliff:g id="APPLICATION">%3$s</xliff:g>\") e o provedor de serviços de VPN também pode monitorar atividades de rede."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"O dispositivo permanecerá bloqueado até que você o desbloqueie manualmente"</string>
-    <!-- no translation found for hidden_notifications_title (7139628534207443290) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_text (2326409389088668981) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_cancel (3690709735122344913) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_setup (41079514801976810) -->
-    <skip />
+    <string name="hidden_notifications_title" msgid="7139628534207443290">"Receba notificações mais rápido"</string>
+    <string name="hidden_notifications_text" msgid="2326409389088668981">"Veja-as antes de desbloquear"</string>
+    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"Não, obrigado"</string>
+    <string name="hidden_notifications_setup" msgid="41079514801976810">"Configurar"</string>
     <string name="muted_by" msgid="6147073845094180001">"Som desativado por <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 9a41430..84cfff4 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -357,13 +357,9 @@
     <string name="monitoring_description_vpn_device_and_profile_owned" msgid="9193588924767232909">"Устройством управляет организация:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nВашим профилем управляет организация:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nАдминистратор может отслеживать вашу работу с эл. почтой, приложениями и защищенными веб-сайтами. Обратитесь к нему за дополнительной информацией.\n\nВы разрешили приложению \"<xliff:g id="APPLICATION">%3$s</xliff:g>\" подключаться к VPN, и ему также доступны эти сведения."</string>
     <string name="monitoring_description_legacy_vpn_device_and_profile_owned" msgid="6935475023447698473">"Устройством управляет организация:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nВашим профилем управляет организация:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nАдминистратор может отслеживать вашу работу с почтой, приложениями и защищенными веб-сайтами. Обратитесь к нему за дополнительной информацией.\n\nУстройство подключено к сети VPN (<xliff:g id="APPLICATION">%3$s</xliff:g>). Поставщику услуг VPN видны ваши действия в Сети."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Устройство необходимо будет разблокировать вручную"</string>
-    <!-- no translation found for hidden_notifications_title (7139628534207443290) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_text (2326409389088668981) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_cancel (3690709735122344913) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_setup (41079514801976810) -->
-    <skip />
+    <string name="hidden_notifications_title" msgid="7139628534207443290">"Быстрый доступ к уведомлениям"</string>
+    <string name="hidden_notifications_text" msgid="2326409389088668981">"Просматривайте уведомления на заблокированном экране."</string>
+    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"Закрыть"</string>
+    <string name="hidden_notifications_setup" msgid="41079514801976810">"Настроить"</string>
     <string name="muted_by" msgid="6147073845094180001">"Звук отключен приложением \"<xliff:g id="THIRD_PARTY">%1$s</xliff:g>\""</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index bd667cf..c0b1b12 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -337,7 +337,7 @@
     <string name="profile_owned_footer" msgid="8021888108553696069">"Huenda wasifu ukafuatiliwa"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Huenda mtandao unafuatiliwa"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Ufuatiliaji wa kifaa"</string>
-    <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Ufuatiliaji wa wasifu"</string>
+    <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Ufuatiliaji wasifu"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Ufuatiliaji wa mtandao"</string>
     <string name="disable_vpn" msgid="4435534311510272506">"Zima VPN"</string>
     <string name="disconnect_vpn" msgid="1324915059568548655">"Ondoa VPN"</string>
@@ -346,20 +346,16 @@
     <string name="monitoring_description_legacy_vpn" msgid="4740349017929725435">"Umeunganishwa kwenye VPN (\"<xliff:g id="APPLICATION">%1$s</xliff:g>\").\n\nMtoa huduma wako wa VPN anaweza kufuatilia kifaa na shughuli za kifaa na mtandao wako, ikiwa ni pamoja na barua pepe, programu na tovuti salama."</string>
     <string name="monitoring_description_vpn_device_owned" msgid="696121105616356493">"Kifaa hiki kinasimamiwa na:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nMsimamizi anaweza kufuatilia shughuli za mtandao wako ikiwa ni pamoja na barua pepe, programu na tovuti salama. Kwa maelezo zaidi, wasiliana na msimamizi wako.\n\nPia, umeruhusu \"<xliff:g id="APPLICATION">%2$s</xliff:g>\" isanidi muunganisho wa VPN. Programu hii pia inaweza kufuatilia shughuli za mtandao wako."</string>
     <string name="monitoring_description_legacy_vpn_device_owned" msgid="649791650224064248">"Kifaa hiki kinasimamiwa na:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nMsimamizi anaweza kufuatilia shughuli za mtandao wako ikiwa ni pamoja na barua pepe, programu na tovuti salama. Kwa maelezo zaidi, wasiliana na msimamizi wako.\n\nPia, umeunganishwa kwenye VPN (\"<xliff:g id="APPLICATION">%2$s</xliff:g>\"). Mtoa huduma wako wa VPN pia anaweza kufuatilia shughuli za mtandao."</string>
-    <string name="monitoring_description_profile_owned" msgid="2370062794285691713">"Wasifu huu unasimamiwa na:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nMsimamizi wako anaweza kufuatilia kifaa chako na shughuli za mtandao, ikiwa ni pamoja na barua pepe na tovuti salama.\n\nKwa maelezo zaidi, wasiliana na msimamizi wako."</string>
-    <string name="monitoring_description_device_and_profile_owned" msgid="8685301493845456293">"Kifaa hiki kinasimamiwa na:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nWasifu wako unasimamiwa na:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nMsimamizi wako anaweza kufuatilia kifaa chako na shughuli za mtandao, ikiwa ni pamoja na barua pepe na tovuti salama.\n\nKwa maelezo zaidi, wasiliana na msimamizi wako."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="847491346263295767">"Wasifu huu unasimamiwa na:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nMsimamizi wako anaweza kufuatilia shughuli za mtandao, ikiwa ni pamoja na barua pepe, programu na na tovuti salama. Kwa maelezo zaidi, wasiliana na msimamizi wako.\n\nPia, uliruhusu \"<xliff:g id="APPLICATION">%2$s</xliff:g>\" isanidi muunganisho wa VPN. Programu hii pia inaweza kufuatilia shughuli za mtandao."</string>
-    <string name="monitoring_description_legacy_vpn_profile_owned" msgid="4095516964132237051">"Kifaa hiki kinasimamiwa na:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nMsimamizi wako anaweza kufuatilia shughuli za mtandao wako ikiwa ni pamoja na barua pepe, programu na tovuti salama. Kwa maelezo zaidi, wasiliana na msimamizi wako.\n\nPia, umeunganishwa kwenye VPN (\"<xliff:g id="APPLICATION">%2$s</xliff:g>\"). Mtoa huduma wako wa VPN pia anaweza kufuatilia shughuli za mtandao."</string>
-    <string name="monitoring_description_vpn_device_and_profile_owned" msgid="9193588924767232909">"Kifaa hiki kinasimamiwa na:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nWasifu wako unasimamiwa na:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nMsimamizi wako anaweza kufuatilia shughuli za mtandao, ikiwa ni pamoja na barua pepe, programu na na tovuti salama\n\nPia, uliruhusu \"<xliff:g id="APPLICATION">%3$s</xliff:g>\" isanidi muunganisho wa VPN. Programu hii pia inaweza kufuatilia shughuli za mtandao."</string>
-    <string name="monitoring_description_legacy_vpn_device_and_profile_owned" msgid="6935475023447698473">"Kifaa hiki kinasimamiwa na:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nWasifu wako unasimamiwa na:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nMsimamizi wako anaweza kufuatilia shughuli za mtandao wako, ikiwa ni pamoja na barua pepe, programu na tovuti salama. Kwa maelezo zaidi, wasiliana na msimamizi wako.\n\nPia, umeunganishwa kwenye VPN (\"<xliff:g id="APPLICATION">%3$s</xliff:g>\"). Mtoa huduma wako wa VPN pia anaweza kufuatilia shughuli za mtandao."</string>
+    <string name="monitoring_description_profile_owned" msgid="2370062794285691713">"Wasifu huu unasimamiwa na:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nMsimamizi wako anaweza kufuatilia kifaa chako na shughuli kwenye mtandao, ikiwa ni pamoja na barua pepe na tovuti salama.\n\nKwa maelezo zaidi, wasiliana na msimamizi wako."</string>
+    <string name="monitoring_description_device_and_profile_owned" msgid="8685301493845456293">"Kifaa hiki kinasimamiwa na:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nWasifu wako unasimamiwa na:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nMsimamizi wako anaweza kufuatilia kifaa chako na shughuli kwenye mtandao, ikiwa ni pamoja na barua pepe na tovuti salama.\n\nKwa maelezo zaidi, wasiliana na msimamizi wako."</string>
+    <string name="monitoring_description_vpn_profile_owned" msgid="847491346263295767">"Wasifu huu unasimamiwa na:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nMsimamizi wako anaweza kufuatilia shughuli zako kwenye mtandao, ikiwa ni pamoja na barua pepe, programu na na tovuti salama. Kwa maelezo zaidi, wasiliana na msimamizi wako.\n\nPia, uliruhusu \"<xliff:g id="APPLICATION">%2$s</xliff:g>\" isanidi muunganisho wa VPN. Programu hii pia inaweza kufuatilia shughuli kwenye mtandao."</string>
+    <string name="monitoring_description_legacy_vpn_profile_owned" msgid="4095516964132237051">"Kifaa hiki kinasimamiwa na:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nMsimamizi wako anaweza kufuatilia shughuli zako kwenye mtandao ikiwa ni pamoja na barua pepe, programu na tovuti salama. Kwa maelezo zaidi, wasiliana na msimamizi wako.\n\nPia, umeunganishwa kwenye VPN (\"<xliff:g id="APPLICATION">%2$s</xliff:g>\"). Mtoa huduma wako wa VPN pia anaweza kufuatilia shughuli kwenye mtandao."</string>
+    <string name="monitoring_description_vpn_device_and_profile_owned" msgid="9193588924767232909">"Kifaa hiki kinasimamiwa na:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nWasifu wako unasimamiwa na:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nMsimamizi wako anaweza kufuatilia shughuli zako kwenye mtandao, ikiwa ni pamoja na barua pepe, programu na na tovuti salama\n\nPia, uliruhusu \"<xliff:g id="APPLICATION">%3$s</xliff:g>\" isanidi muunganisho wa VPN. Programu hii pia inaweza kufuatilia shughuli kwenye mtandao."</string>
+    <string name="monitoring_description_legacy_vpn_device_and_profile_owned" msgid="6935475023447698473">"Kifaa hiki kinasimamiwa na:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nWasifu wako unasimamiwa na:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nMsimamizi wako anaweza kufuatilia shughuli zako kwenye mtandao, ikiwa ni pamoja na barua pepe, programu na tovuti salama. Kwa maelezo zaidi, wasiliana na msimamizi wako.\n\nPia, umeunganishwa kwenye VPN (\"<xliff:g id="APPLICATION">%3$s</xliff:g>\"). Mtoa huduma wako wa VPN pia anaweza kufuatilia shughuli kwenye mtandao."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Kifaa kitaendelea kuwa katika hali ya kufungwa hadi utakapokifungua mwenyewe"</string>
-    <!-- no translation found for hidden_notifications_title (7139628534207443290) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_text (2326409389088668981) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_cancel (3690709735122344913) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_setup (41079514801976810) -->
-    <skip />
+    <string name="hidden_notifications_title" msgid="7139628534207443290">"Pata arifa kwa haraka"</string>
+    <string name="hidden_notifications_text" msgid="2326409389088668981">"Zitazame kabla hujafungua"</string>
+    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"La, asante"</string>
+    <string name="hidden_notifications_setup" msgid="41079514801976810">"Sanidi"</string>
     <string name="muted_by" msgid="6147073845094180001">"Sauti imezimwa na <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index 1c343a9..52700cc 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -83,7 +83,7 @@
     <string name="accessibility_recent" msgid="1606470783629913980">"சமீபத்திய திரைகள்"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"தேடு"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"கேமரா"</string>
-    <string name="accessibility_phone_button" msgid="6738112589538563574">"மொபைல்"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"ஃபோன்"</string>
     <string name="accessibility_unlock_button" msgid="128158454631118828">"திற"</string>
     <string name="unlock_label" msgid="8779712358041029439">"திற"</string>
     <string name="phone_label" msgid="2320074140205331708">"ஃபோனைத் திற"</string>
@@ -143,7 +143,7 @@
     <string name="accessibility_data_connection_roaming" msgid="5977362333466556094">"ரோமிங்"</string>
     <string name="accessibility_data_connection_edge" msgid="4477457051631979278">"Edge"</string>
     <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"வைஃபை"</string>
-    <string name="accessibility_no_sim" msgid="8274017118472455155">"SIM இல்லை."</string>
+    <string name="accessibility_no_sim" msgid="8274017118472455155">"சிம் இல்லை."</string>
     <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"புளூடூத் இணைப்பு முறை."</string>
     <string name="accessibility_airplane_mode" msgid="834748999790763092">"விமானப் பயன்முறை."</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"பேட்டரி சக்தி <xliff:g id="NUMBER">%d</xliff:g> சதவிகிதம் உள்ளது."</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 2aa8f05..0c0149c 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -355,13 +355,9 @@
     <string name="monitoring_description_vpn_device_and_profile_owned" msgid="9193588924767232909">"Bu cihazı yöneten kuruluş:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nProfilinizi yöneten kuruluş:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nYöneticiniz; e-postalar, uygulamalar ve güvenli web siteleri de dahil olmak üzere ağ etkinliğinizi izleyebilir. Daha fazla bilgi için yöneticinize başvurun.\n\nAyrıca \"<xliff:g id="APPLICATION">%3$s</xliff:g>\" uygulamasına VPN kurma izni verdiniz. Bu uygulama da ağ etkinliğini izleyebilir."</string>
     <string name="monitoring_description_legacy_vpn_device_and_profile_owned" msgid="6935475023447698473">"Bu cihazı yöneten kuruluş:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nProfilinizi yöneten kuruluş:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nYöneticiniz; e-postalar, uygulamalar ve güvenli web siteleri de dahil olmak üzere ağ etkinliğinizi izleyebilir. Daha fazla bilgi için yöneticinize başvurun.\n\nAyrıca, bir VPN\'ye (\"<xliff:g id="APPLICATION">%3$s</xliff:g>\") bağlısınız. VPN hizmet sağlayıcınız da ağ etkinliğini izleyebilir."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Cihazınızın kilidini manuel olarak açmadıkça cihaz kilitli kalacak"</string>
-    <!-- no translation found for hidden_notifications_title (7139628534207443290) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_text (2326409389088668981) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_cancel (3690709735122344913) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_setup (41079514801976810) -->
-    <skip />
+    <string name="hidden_notifications_title" msgid="7139628534207443290">"Bildirimleri daha hızlı alın"</string>
+    <string name="hidden_notifications_text" msgid="2326409389088668981">"Kilidi açmadan bildirimleri görün"</string>
+    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"Hayır, teşekkürler"</string>
+    <string name="hidden_notifications_setup" msgid="41079514801976810">"Kur"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> tarafından kapatıldı"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 4ab3171..162a280 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -286,7 +286,7 @@
     <string name="description_target_search" msgid="3091587249776033139">"Пошук"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Проведіть пальцем угору, щоб <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"Проведіть пальцем ліворуч, щоб <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Без сповіщень. Навіть без сигналів будильника."</string>
+    <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Без сповіщень і сигналів будильника."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Без сповіщень"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Лише пріоритетні сповіщення"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Наступний сигнал: <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index 5bfac40..708607c 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -355,13 +355,9 @@
     <string name="monitoring_description_vpn_device_and_profile_owned" msgid="9193588924767232909">"‏اس آلہ کا نظم کیا جاتا ہے بذریعہ:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nآپ کے پروفائل کا نظم کیا جاتا ہے بذریعہ:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nآپ کا منتظم آپ کے نیٹ ورک کی سرگرمی بشمول، ای میلز، ایپس اور محفوظ ویب سائٹس کو مانیٹر کر سکتا ہے۔ مزید معلومات کیلئے، اپنے منتظم سے رابطہ کریں۔\n\nنیز، آپ نے \"<xliff:g id="APPLICATION">%3$s</xliff:g>\" کو ایک VPN کنکشن ترتیب دینے کی اجازت دی ہے۔ یہ ایپ نیٹ ورک کی سرگرمی بھی مانیٹر کر سکتی ہے۔"</string>
     <string name="monitoring_description_legacy_vpn_device_and_profile_owned" msgid="6935475023447698473">"‏اس آلہ کا نظم کیا جاتا ہے بذریعہ:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nآپ کے پروفائل کا نظم کیا جاتا ہے بذریعہ:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nآپ کا منتظم آپ کے نیٹ ورک کی سرگرمی، بشمول ای میلز، ایپس اور محفوظ ویب سائٹس کو مانیٹر کر سکتا ہے۔ مزید معلومات کیلئے، اپنے منتظم سے رابطہ کریں۔\n\nنیز، آپ ایک VPN (\"<xliff:g id="APPLICATION">%3$s</xliff:g>\") سے منسلک ہیں۔ آپ کا VPN سروس فراہم کنندہ نیٹ ورک کی سرگرمی کو بھی مانیٹر کر سکتا ہے۔"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"آلہ اس وقت تک مقفل رہے گا جب تک آپ دستی طور پر اسے غیر مقفل نہ کریں"</string>
-    <!-- no translation found for hidden_notifications_title (7139628534207443290) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_text (2326409389088668981) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_cancel (3690709735122344913) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_setup (41079514801976810) -->
-    <skip />
+    <string name="hidden_notifications_title" msgid="7139628534207443290">"تیزی سے اطلاعات حاصل کریں"</string>
+    <string name="hidden_notifications_text" msgid="2326409389088668981">"غیر مقفل کرنے سے پہلے انہیں دیکھیں"</string>
+    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"نہیں شکریہ"</string>
+    <string name="hidden_notifications_setup" msgid="41079514801976810">"ترتیب دیں"</string>
     <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> کے ذریعے خاموش کردہ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index 8868213..7776269 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -355,13 +355,9 @@
     <string name="monitoring_description_vpn_device_and_profile_owned" msgid="9193588924767232909">"Bu qurilma boshqaruvchisi:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nProfil boshqaruvchisi:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nAdmin-ngiz tarmoqdagi faollik – e-pochta, ilova va xavfsiz veb-saytlardagi har-ni kuzatishi m-n. Qo‘sh. ma’l. olish u-n admin-ga murojaat qiling.\n\nSiz “<xliff:g id="APPLICATION">%3$s</xliff:g>” ilovasiga VPN ulanishini sozlash u-n ruxsat bergansiz. U ham tarmoqdagi faollikni kuzatishi m-n."</string>
     <string name="monitoring_description_legacy_vpn_device_and_profile_owned" msgid="6935475023447698473">"Bu qurilma boshqaruvchisi:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\nProfil boshqaruvchisi:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\nAdmin-ngiz tarmoqdagi faollik – e-pochta, ilova va xavfsiz veb-saytlardagi har-ni kuzatishi m-n.\n\nQo‘sh. ma’l. olish u-n admin-ga murojaat qiling. Siz VPN tarmog‘iga (“<xliff:g id="APPLICATION">%3$s</xliff:g>”) ulangansiz. VPN xizmati ta’minotchingiz ham tarmoqdagi faollikni kuzatishi m-n."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Qurilma qo‘lda qulfdan chiqarilmaguncha qulflangan holatda qoladi"</string>
-    <!-- no translation found for hidden_notifications_title (7139628534207443290) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_text (2326409389088668981) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_cancel (3690709735122344913) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_setup (41079514801976810) -->
-    <skip />
+    <string name="hidden_notifications_title" msgid="7139628534207443290">"Bildirishnomalarni tezroq oling"</string>
+    <string name="hidden_notifications_text" msgid="2326409389088668981">"Ularni qulfdan chiqarishdan oldin ko‘ring"</string>
+    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"Yo‘q, kerak emas"</string>
+    <string name="hidden_notifications_setup" msgid="41079514801976810">"Sozlash"</string>
     <string name="muted_by" msgid="6147073845094180001">"“<xliff:g id="THIRD_PARTY">%1$s</xliff:g>” tomonidan ovozsiz qilingan"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 7d6dc64..06cebb3 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -357,13 +357,9 @@
     <string name="monitoring_description_vpn_device_and_profile_owned" msgid="9193588924767232909">"此设备由以下单位管理:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\n您的资料由以下单位管理:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\n您的管理员可以监控您的网络活动,包括收发电子邮件、使用应用和浏览安全网站。若要了解详情,请与您的管理员联系。\n\n此外,您已授权“<xliff:g id="APPLICATION">%3$s</xliff:g>”设置VPN连接。此应用也可以监控网络活动。"</string>
     <string name="monitoring_description_legacy_vpn_device_and_profile_owned" msgid="6935475023447698473">"此设备由以下单位管理:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\n您的资料由以下单位管理:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\n您的管理员可以监控您的网络活动,包括收发电子邮件、使用应用和浏览安全网站。若要了解详情,请与您的管理员联系。\n\n此外,您已连接到VPN(“<xliff:g id="APPLICATION">%3$s</xliff:g>”)。您的VPN服务提供商也可以监控您的网络活动。"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"在您手动解锁之前,设备会保持锁定状态"</string>
-    <!-- no translation found for hidden_notifications_title (7139628534207443290) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_text (2326409389088668981) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_cancel (3690709735122344913) -->
-    <skip />
-    <!-- no translation found for hidden_notifications_setup (41079514801976810) -->
-    <skip />
+    <string name="hidden_notifications_title" msgid="7139628534207443290">"更快捷地查看通知"</string>
+    <string name="hidden_notifications_text" msgid="2326409389088668981">"无需解锁即可查看通知"</string>
+    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"不用了"</string>
+    <string name="hidden_notifications_setup" msgid="41079514801976810">"设置"</string>
     <string name="muted_by" msgid="6147073845094180001">"已被<xliff:g id="THIRD_PARTY">%1$s</xliff:g>设为静音"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 2df414c..9b0bde1 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -338,7 +338,7 @@
     <string name="media_projection_action_text" msgid="8470872969457985954">"立即開始"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"沒有通知"</string>
     <string name="device_owned_footer" msgid="3802752663326030053">"裝置可能會受到監控"</string>
-    <string name="profile_owned_footer" msgid="8021888108553696069">"個人檔案可能會受到監控"</string>
+    <string name="profile_owned_footer" msgid="8021888108553696069">"個人檔案可能受到監控"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"網絡可能會受到監控"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"裝置監控"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"個人檔案監控"</string>
@@ -357,7 +357,7 @@
     <string name="monitoring_description_vpn_device_and_profile_owned" msgid="9193588924767232909">"這部裝置的管理機構:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\n您的個人檔案的管理機構:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\n您的管理員可以監控您的網絡活動,包括電郵、應用程式及安全網站。如需瞭解詳情,請聯絡您的管理員。\n\n同時,由於您已授權「<xliff:g id="APPLICATION">%3$s</xliff:g>」設定 VPN 連線,因此這個應用程式也能監控您的網絡活動。"</string>
     <string name="monitoring_description_legacy_vpn_device_and_profile_owned" msgid="6935475023447698473">"這部裝置的管理機構:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>\n您的個人檔案的管理機構:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>\n\n您的管理員可以監控您的網絡活動,包括電郵、應用程式及安全網站。如需瞭解詳情,請聯絡您的管理員。\n\n同時,由於您的裝置已與 VPN (「<xliff:g id="APPLICATION">%3$s</xliff:g>」) 連線,因此您的 VPN 服務供應商也能監控您的網絡活動。"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"裝置將保持上鎖,直到您手動解鎖"</string>
-    <string name="hidden_notifications_title" msgid="7139628534207443290">"更快取得通知"</string>
+    <string name="hidden_notifications_title" msgid="7139628534207443290">"快速取得通知"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"解鎖前顯示"</string>
     <string name="hidden_notifications_cancel" msgid="3690709735122344913">"不用了,謝謝"</string>
     <string name="hidden_notifications_setup" msgid="41079514801976810">"設定"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 0e18979..5399a39 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -137,7 +137,7 @@
     <!-- The min animation duration for animating the task in when transitioning from home. -->
     <integer name="recents_animate_task_enter_from_home_duration">275</integer>
     <!-- The animation stagger to apply to each task animation when transitioning from home. -->
-    <integer name="recents_animate_task_enter_from_home_delay">10</integer>
+    <integer name="recents_animate_task_enter_from_home_delay">150</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. -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 946914b..8cd4ce6 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -289,13 +289,13 @@
     <dimen name="speed_bump_height">16dp</dimen>
 
     <!-- Lockscreen unlocking falsing threshold. -->
-    <dimen name="unlock_falsing_threshold">100dp</dimen>
+    <dimen name="unlock_falsing_threshold">80dp</dimen>
 
     <!-- Lockscreen falsing threshold for quick settings. -->
-    <dimen name="qs_falsing_threshold">60dp</dimen>
+    <dimen name="qs_falsing_threshold">80dp</dimen>
 
     <!-- Falsing threshold used when dismissing notifications from the lockscreen. -->
-    <dimen name="swipe_helper_falsing_threshold">100dp</dimen>
+    <dimen name="swipe_helper_falsing_threshold">70dp</dimen>
 
     <dimen name="notifications_top_padding">8dp</dimen>
     
@@ -315,7 +315,7 @@
     <dimen name="heads_up_window_height">250dp</dimen>
 
     <!-- The minimum amount the user needs to swipe to go to the camera / phone. -->
-    <dimen name="keyguard_min_swipe_amount">85dp</dimen>
+    <dimen name="keyguard_min_swipe_amount">90dp</dimen>
 
     <!-- The minimum background radius when swiping to a side for the camera / phone affordances. -->
     <dimen name="keyguard_affordance_min_background_radius">30dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index b488c56..c7a91af 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -522,9 +522,13 @@
     <!-- Content description of the clear button in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_clear_all">Clear all notifications.</string>
 
-    <!-- Title shown in notification popup for inspecting the responsible
-         application [CHAR LIMIT=30] -->
-    <string name="status_bar_notification_inspect_item_title">Settings</string>
+    <!-- Content description of button in notification inspector for system settings relating to
+         notifications from this application [CHAR LIMIT=NONE] -->
+    <string name="status_bar_notification_inspect_item_title">Notification settings</string>
+
+    <!-- Content description of button in notification inspetor for application-provided settings
+         for its own notifications [CHAR LIMIT=NONE] -->
+    <string name="status_bar_notification_app_settings_title"><xliff:g id="app_name" example="Calendar">%s</xliff:g> settings</string>
 
     <!-- Description of the button in the phone-style notification panel that controls auto-rotation, when auto-rotation is on. [CHAR LIMIT=NONE] -->
     <string name="accessibility_rotation_lock_off">Screen will rotate automatically.</string>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index ce29407..2c1d70d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -34,13 +34,11 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.database.ContentObserver;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Color;
 import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
 import android.os.Build;
@@ -96,6 +94,7 @@
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 
 import java.util.ArrayList;
+import java.util.List;
 import java.util.Locale;
 
 import static com.android.keyguard.KeyguardHostView.OnDismissAction;
@@ -177,7 +176,7 @@
     // public mode, private notifications, etc
     private boolean mLockscreenPublicMode = false;
     private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
-    private NotificationColorUtil mNotificationColorUtil = NotificationColorUtil.getInstance();
+    private NotificationColorUtil mNotificationColorUtil;
 
     private UserManager mUserManager;
 
@@ -435,6 +434,8 @@
         mDevicePolicyManager = (DevicePolicyManager)mContext.getSystemService(
                 Context.DEVICE_POLICY_SERVICE);
 
+        mNotificationColorUtil = NotificationColorUtil.getInstance(mContext);
+
         mNotificationData = new NotificationData(this);
 
         mDreamManager = IDreamManager.Stub.asInterface(
@@ -717,11 +718,23 @@
                entry.expandedBig.findViewById(com.android.internal.R.id.media_actions) != null;
     }
 
+    // The gear button in the guts that links to the app's own notification settings
+    private void startAppOwnNotificationSettingsActivity(Intent intent,
+            final int notificationId, final String notificationTag, final int appUid) {
+        intent.putExtra("notification_id", notificationId);
+        intent.putExtra("notification_tag", notificationTag);
+        startNotificationGutsIntent(intent, appUid);
+    }
+
+    // The (i) button in the guts that links to the system notification settings for that app
     private void startAppNotificationSettingsActivity(String packageName, final int appUid) {
         final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
         intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName);
         intent.putExtra(Settings.EXTRA_APP_UID, appUid);
+        startNotificationGutsIntent(intent, appUid);
+    }
 
+    private void startNotificationGutsIntent(final Intent intent, final int appUid) {
         final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
         dismissKeyguardThenExecute(new OnDismissAction() {
             @Override
@@ -1128,7 +1141,7 @@
                 entry.notification.getUser().getIdentifier());
 
         int maxHeight = mRowMaxHeight;
-        StatusBarNotification sbn = entry.notification;
+        final StatusBarNotification sbn = entry.notification;
         RemoteViews contentView = sbn.getNotification().contentView;
         RemoteViews bigContentView = sbn.getNotification().bigContentView;
 
@@ -1197,6 +1210,8 @@
         ((DateTimeView) row.findViewById(R.id.timestamp)).setTime(entry.notification.getPostTime());
         ((TextView) row.findViewById(R.id.pkgname)).setText(appname);
         final View settingsButton = guts.findViewById(R.id.notification_inspect_item);
+        final View appSettingsButton
+                = guts.findViewById(R.id.notification_inspect_app_provided_settings);
         if (appUid >= 0) {
             final int appUidF = appUid;
             settingsButton.setOnClickListener(new View.OnClickListener() {
@@ -1204,8 +1219,33 @@
                     startAppNotificationSettingsActivity(pkg, appUidF);
                 }
             });
+
+            final Intent appSettingsQueryIntent
+                    = new Intent(Intent.ACTION_MAIN)
+                        .addCategory(Notification.INTENT_CATEGORY_NOTIFICATION_PREFERENCES)
+                        .setPackage(pkg);
+            List<ResolveInfo> infos = pmUser.queryIntentActivities(appSettingsQueryIntent, 0);
+            if (infos.size() > 0) {
+                appSettingsButton.setVisibility(View.VISIBLE);
+                appSettingsButton.setContentDescription(
+                        mContext.getResources().getString(
+                                R.string.status_bar_notification_app_settings_title,
+                                appname
+                        ));
+                final Intent appSettingsLaunchIntent = new Intent(appSettingsQueryIntent)
+                        .setClassName(pkg, infos.get(0).activityInfo.name);
+                appSettingsButton.setOnClickListener(new View.OnClickListener() {
+                    public void onClick(View v) {
+                        startAppOwnNotificationSettingsActivity(appSettingsLaunchIntent,
+                                sbn.getId(),
+                                sbn.getTag(),
+                                appUidF);
+                    }
+                });
+            }
         } else {
             settingsButton.setVisibility(View.GONE);
+            appSettingsButton.setVisibility(View.GONE);
         }
 
         workAroundBadLayerDrawableOpacity(row);
@@ -1281,7 +1321,9 @@
             // Add a basic notification template
             publicViewLocal = LayoutInflater.from(mContext).inflate(
                     com.android.internal.R.layout.notification_template_material_base,
-                    expandedPublic, true);
+                    expandedPublic, false);
+            publicViewLocal.setIsRootNamespace(true);
+            expandedPublic.setContractedChild(publicViewLocal);
 
             final TextView title = (TextView) publicViewLocal.findViewById(com.android.internal.R.id.title);
             try {
@@ -1305,7 +1347,7 @@
 
             Drawable iconDrawable = StatusBarIconView.getIcon(mContext, ic);
             icon.setImageDrawable(iconDrawable);
-            if (mNotificationColorUtil.isGrayscale(iconDrawable)) {
+            if (mNotificationColorUtil.isGrayscaleIcon(iconDrawable)) {
                 icon.setBackgroundResource(
                         com.android.internal.R.drawable.notification_icon_legacy_bg);
                 int padding = mContext.getResources().getDimensionPixelSize(
@@ -1902,6 +1944,13 @@
     }
 
     protected boolean shouldInterrupt(StatusBarNotification sbn) {
+        if (mNotificationData.shouldFilterOut(sbn)) {
+            if (DEBUG) {
+                Log.d(TAG, "Skipping HUN check for " + sbn.getKey() + " since it's filtered out.");
+            }
+            return false;
+        }
+
         Notification notification = sbn.getNotification();
         // some predicates to make the boolean logic legible
         boolean isNoisy = (notification.defaults & Notification.DEFAULT_SOUND) != 0
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index dfcc408..e3a0b18 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -17,10 +17,15 @@
 package com.android.systemui.statusbar;
 
 import android.content.Context;
+import android.graphics.drawable.AnimatedVectorDrawable;
+import android.graphics.drawable.AnimationDrawable;
+import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 
+import android.widget.ImageView;
 import com.android.systemui.R;
 
 public class ExpandableNotificationRow extends ActivatableNotificationView {
@@ -62,6 +67,51 @@
     private boolean mWasReset;
     private NotificationGuts mGuts;
 
+    public void setIconAnimationRunning(boolean running) {
+        setIconAnimationRunning(running, mPublicLayout);
+        setIconAnimationRunning(running, mPrivateLayout);
+    }
+
+    private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
+        if (layout != null) {
+            View contractedChild = layout.getContractedChild();
+            View expandedChild = layout.getExpandedChild();
+            setIconAnimationRunningForChild(running, contractedChild);
+            setIconAnimationRunningForChild(running, expandedChild);
+        }
+    }
+
+    private void setIconAnimationRunningForChild(boolean running, View child) {
+        if (child != null) {
+            ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
+            setIconRunning(icon, running);
+            ImageView rightIcon = (ImageView) child.findViewById(
+                    com.android.internal.R.id.right_icon);
+            setIconRunning(rightIcon, running);
+        }
+    }
+
+    private void setIconRunning(ImageView imageView, boolean running) {
+        if (imageView != null) {
+            Drawable drawable = imageView.getDrawable();
+            if (drawable instanceof AnimationDrawable) {
+                AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
+                if (running) {
+                    animationDrawable.start();
+                } else {
+                    animationDrawable.stop();
+                }
+            } else if (drawable instanceof AnimatedVectorDrawable) {
+                AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
+                if (running) {
+                    animationDrawable.start();
+                } else {
+                    animationDrawable.stop();
+                }
+            }
+        }
+    }
+
     public interface ExpansionLogger {
         public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
index 5878ae1..a4161f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
@@ -251,15 +251,19 @@
     }
 
     public void setCircleRadius(float circleRadius) {
-        setCircleRadius(circleRadius, false);
+        setCircleRadius(circleRadius, false, false);
+    }
+
+    public void setCircleRadius(float circleRadius, boolean slowAnimation) {
+        setCircleRadius(circleRadius, slowAnimation, false);
     }
 
     public void setCircleRadiusWithoutAnimation(float circleRadius) {
         cancelAnimator(mCircleAnimator);
-        setCircleRadius(circleRadius, true);
+        setCircleRadius(circleRadius, false ,true);
     }
 
-    private void setCircleRadius(float circleRadius, boolean noAnimation) {
+    private void setCircleRadius(float circleRadius, boolean slowAnimation, boolean noAnimation) {
 
         // Check if we need a new animation
         boolean radiusHidden = (mCircleAnimator != null && mCircleWillBeHidden)
@@ -292,10 +296,13 @@
                     ? mDisappearInterpolator
                     : mAppearInterpolator;
             animator.setInterpolator(interpolator);
-            float durationFactor = Math.abs(mCircleRadius - circleRadius)
-                    / (float) mMinBackgroundRadius;
-            long duration = (long) (CIRCLE_APPEAR_DURATION * durationFactor);
-            duration = Math.min(duration, CIRCLE_DISAPPEAR_MAX_DURATION);
+            long duration = 250;
+            if (!slowAnimation) {
+                float durationFactor = Math.abs(mCircleRadius - circleRadius)
+                        / (float) mMinBackgroundRadius;
+                duration = (long) (CIRCLE_APPEAR_DURATION * durationFactor);
+                duration = Math.min(duration, CIRCLE_DISAPPEAR_MAX_DURATION);
+            }
             animator.setDuration(duration);
             animator.start();
             if (mPreviewView != null && mPreviewView.getVisibility() == View.VISIBLE) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 8b4c2c4..e31eb7c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -88,6 +88,14 @@
         mContractedVisible = true;
     }
 
+    public View getContractedChild() {
+        return mContractedChild;
+    }
+
+    public View getExpandedChild() {
+        return mExpandedChild;
+    }
+
     public void setContractedChild(View child) {
         if (mContractedChild != null) {
             mContractedChild.animate().cancel();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 454041c..0905fe7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar;
 
 import android.app.Notification;
+import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationListenerService.Ranking;
 import android.service.notification.NotificationListenerService.RankingMap;
 import android.service.notification.StatusBarNotification;
@@ -173,6 +174,14 @@
         return false;
     }
 
+    public int getVisibilityOverride(String key) {
+        if (mRankingMap != null) {
+            mRankingMap.getRanking(key, mTmpRanking);
+            return mTmpRanking.getVisibilityOverride();
+        }
+        return NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE;
+    }
+
     private void updateRankingAndSort(RankingMap ranking) {
         if (ranking != null) {
             mRankingMap = ranking;
@@ -221,7 +230,7 @@
         return mGroupsWithSummaries.contains(groupKey);
     }
 
-    private boolean shouldFilterOut(StatusBarNotification sbn) {
+    boolean shouldFilterOut(StatusBarNotification sbn) {
         if (!(mEnvironment.isDeviceProvisioned() ||
                 showNotificationEvenIfUnprovisioned(sbn))) {
             return true;
@@ -300,7 +309,7 @@
      * Provides access to keyguard state and user settings dependent data.
      */
     public interface Environment {
-        public boolean shouldHideSensitiveContents(int userId);
+        public boolean shouldHideSensitiveContents(int userid);
         public boolean isDeviceProvisioned();
         public boolean isNotificationForCurrentProfiles(StatusBarNotification sbn);
         public String getCurrentMediaNotificationKey();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java
index c75bd28..c4c9dac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java
@@ -36,7 +36,7 @@
     private TextView mMoreText;
     private int mTintColor;
     private int mIconSize;
-    private NotificationColorUtil mNotificationColorUtil = new NotificationColorUtil();
+    private NotificationColorUtil mNotificationColorUtil;
 
     public NotificationOverflowIconsView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -45,6 +45,7 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
+        mNotificationColorUtil = NotificationColorUtil.getInstance(getContext());
         mTintColor = getResources().getColor(R.color.keyguard_overflow_content_color);
         mIconSize = getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.status_bar_icon_size);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
index eca8e6a..a9c701a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
@@ -20,8 +20,6 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
 import android.content.Context;
-import android.os.PowerManager;
-import android.os.SystemClock;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
@@ -85,9 +83,9 @@
         mContext = context;
         mCallback = callback;
         initIcons();
-        updateIcon(mLeftIcon, 0.0f, SWIPE_RESTING_ALPHA_AMOUNT, false);
-        updateIcon(mCenterIcon, 0.0f, SWIPE_RESTING_ALPHA_AMOUNT, false);
-        updateIcon(mRightIcon, 0.0f, SWIPE_RESTING_ALPHA_AMOUNT, false);
+        updateIcon(mLeftIcon, 0.0f, SWIPE_RESTING_ALPHA_AMOUNT, false, false);
+        updateIcon(mCenterIcon, 0.0f, SWIPE_RESTING_ALPHA_AMOUNT, false, false);
+        updateIcon(mRightIcon, 0.0f, SWIPE_RESTING_ALPHA_AMOUNT, false, false);
         initDimens();
     }
 
@@ -295,8 +293,7 @@
         float vel = getCurrentVelocity();
 
         // We snap back if the current translation is not far enough
-        boolean snapBack = Math.abs(mTranslation) < Math.abs(mTranslationOnDown)
-                + mMinTranslationAmount;
+        boolean snapBack = isBelowFalsingThreshold();
 
         // or if the velocity is in the opposite direction.
         boolean velIsInWrongDirection = vel * mTranslation < 0;
@@ -305,6 +302,11 @@
         fling(vel, snapBack || forceSnapBack);
     }
 
+    private boolean isBelowFalsingThreshold() {
+        return Math.abs(mTranslation) < Math.abs(mTranslationOnDown)
+                + mMinTranslationAmount;
+    }
+
     private void fling(float vel, final boolean snapBack) {
         float target = mTranslation < 0 ? -mCallback.getPageWidth() : mCallback.getPageWidth();
         target = snapBack ? 0 : target;
@@ -355,13 +357,14 @@
 
             boolean animateIcons = isReset && animateReset;
             float radius = getRadiusFromTranslation(absTranslation);
+            boolean slowAnimation = isReset && isBelowFalsingThreshold();
             if (!isReset) {
-                updateIcon(targetView, radius, alpha, false);
+                updateIcon(targetView, radius, alpha, false, false);
             } else {
-                updateIcon(targetView, 0.0f, fadeOutAlpha, animateIcons);
+                updateIcon(targetView, 0.0f, fadeOutAlpha, animateIcons, slowAnimation);
             }
-            updateIcon(otherView, 0.0f, fadeOutAlpha, animateIcons);
-            updateIcon(mCenterIcon, 0.0f, fadeOutAlpha, animateIcons);
+            updateIcon(otherView, 0.0f, fadeOutAlpha, animateIcons, slowAnimation);
+            updateIcon(mCenterIcon, 0.0f, fadeOutAlpha, animateIcons, slowAnimation);
 
             mTranslation = translation;
         }
@@ -392,16 +395,16 @@
     }
 
     public void animateHideLeftRightIcon() {
-        updateIcon(mRightIcon, 0f, 0f, true);
-        updateIcon(mLeftIcon, 0f, 0f, true);
+        updateIcon(mRightIcon, 0f, 0f, true, false);
+        updateIcon(mLeftIcon, 0f, 0f, true, false);
     }
 
     private void updateIcon(KeyguardAffordanceView view, float circleRadius, float alpha,
-            boolean animate) {
+            boolean animate, boolean slowRadiusAnimation) {
         if (view.getVisibility() != View.VISIBLE) {
             return;
         }
-        view.setCircleRadius(circleRadius);
+        view.setCircleRadius(circleRadius, slowRadiusAnimation);
         updateIconAlpha(view, alpha, animate);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 91a8b22..bae1864 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -548,7 +548,7 @@
     }
 
     private boolean flingExpandsQs(float vel) {
-        if (!mQsTouchAboveFalsingThreshold && mStatusBarState == StatusBarState.KEYGUARD) {
+        if (isBelowFalsingThreshold()) {
             return false;
         }
         if (Math.abs(vel) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
@@ -558,6 +558,10 @@
         }
     }
 
+    private boolean isBelowFalsingThreshold() {
+        return !mQsTouchAboveFalsingThreshold && mStatusBar.isFalsingThresholdNeeded();
+    }
+
     private float getQsExpansionFraction() {
         return Math.min(1f, (mQsExpansionHeight - mQsMinExpansionHeight)
                 / (getTempQsMaxExpansion() - mQsMinExpansionHeight));
@@ -1122,9 +1126,16 @@
             }
             return;
         }
+        boolean belowFalsingThreshold = isBelowFalsingThreshold();
+        if (belowFalsingThreshold) {
+            vel = 0;
+        }
         mScrollView.setBlockFlinging(true);
         ValueAnimator animator = ValueAnimator.ofFloat(mQsExpansionHeight, target);
         mFlingAnimationUtils.apply(animator, mQsExpansionHeight, target, vel);
+        if (belowFalsingThreshold) {
+            animator.setDuration(350);
+        }
         animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
             @Override
             public void onAnimationUpdate(ValueAnimator animation) {
@@ -1692,9 +1703,9 @@
     }
 
     public void setEmptyDragAmount(float amount) {
-        float factor = 1f;
+        float factor = 0.8f;
         if (mNotificationStackScroller.getNotGoneChildCount() > 0) {
-            factor = 0.6f;
+            factor = 0.4f;
         } else if (!mStatusBar.hasActiveNotifications()) {
             factor = 0.4f;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 6127811..7261ea1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -479,7 +479,7 @@
      * @return whether a fling should expands the panel; contracts otherwise
      */
     protected boolean flingExpands(float vel, float vectorVel) {
-        if (!mTouchAboveFalsingThreshold && mStatusBar.isFalsingThresholdNeeded()) {
+        if (isBelowFalsingThreshold()) {
             return true;
         }
         if (Math.abs(vectorVel) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
@@ -489,6 +489,10 @@
         }
     }
 
+    private boolean isBelowFalsingThreshold() {
+        return !mTouchAboveFalsingThreshold && mStatusBar.isFalsingThresholdNeeded();
+    }
+
     protected void fling(float vel, boolean expand) {
         cancelPeek();
         float target = expand ? getMaxPanelHeight() : 0.0f;
@@ -509,7 +513,14 @@
         mOverExpandedBeforeFling = getOverExpansionAmount() > 0f;
         ValueAnimator animator = createHeightAnimator(target);
         if (expand) {
+            boolean belowFalsingThreshold = isBelowFalsingThreshold();
+            if (belowFalsingThreshold) {
+                vel = 0;
+            }
             mFlingAnimationUtils.apply(animator, mExpandedHeight, target, vel, getHeight());
+            if (belowFalsingThreshold) {
+                animator.setDuration(350);
+            }
         } else {
             mFlingAnimationUtils.applyDismissing(animator, mExpandedHeight, target, vel,
                     getHeight());
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 00e9790..ddd03d6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -71,6 +71,7 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationListenerService.RankingMap;
 import android.service.notification.StatusBarNotification;
 import android.util.ArraySet;
@@ -1414,11 +1415,12 @@
             // Display public version of the notification if we need to redact.
             final boolean hideSensitive =
                     !userAllowsPrivateNotificationsInPublic(ent.notification.getUserId());
-            boolean sensitive = vis == Notification.VISIBILITY_PRIVATE;
-            boolean showingPublic = sensitive && hideSensitive && isLockscreenPublicMode();
-            ent.row.setSensitive(sensitive && hideSensitive);
+            boolean sensitiveNote = vis == Notification.VISIBILITY_PRIVATE;
+            boolean sensitivePackage = packageHasVisibilityOverride(ent.notification.getKey());
+            boolean sensitive = (sensitiveNote && hideSensitive) || sensitivePackage;
+            boolean showingPublic = sensitive && isLockscreenPublicMode();
+            ent.row.setSensitive(sensitive);
             if (ent.autoRedacted && ent.legacy) {
-
                 // TODO: Also fade this? Or, maybe easier (and better), provide a dark redacted form
                 // for legacy auto redacted notifications.
                 if (showingPublic) {
@@ -1479,6 +1481,11 @@
         mShadeUpdates.check();
     }
 
+    private boolean packageHasVisibilityOverride(String key) {
+        return mNotificationData.getVisibilityOverride(key)
+                != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE;
+    }
+
     private void updateClearAll() {
         boolean showDismissView =
                 mState != StatusBarState.KEYGUARD &&
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 148b00c..fed579c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -1467,6 +1467,7 @@
             // drawn when removed
             getOverlay().add(child);
         }
+        updateAnimationState(false, child);
 
         // Make sure the clipRect we might have set is removed
         child.setClipBounds(null);
@@ -1545,10 +1546,28 @@
         mStackScrollAlgorithm.notifyChildrenChanged(this);
         ((ExpandableView) child).setOnHeightChangedListener(this);
         generateAddAnimation(child, false /* fromMoreCard */);
+        updateAnimationState(mAnimationsEnabled && mIsExpanded, child);
     }
 
     public void setAnimationsEnabled(boolean animationsEnabled) {
         mAnimationsEnabled = animationsEnabled;
+        updateNotificationAnimationStates();
+    }
+
+    private void updateNotificationAnimationStates() {
+        boolean running = mIsExpanded && mAnimationsEnabled;
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View child = getChildAt(i);
+            updateAnimationState(running, child);
+        }
+    }
+
+    private void updateAnimationState(boolean running, View child) {
+        if (child instanceof ExpandableNotificationRow) {
+            ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+            row.setIconAnimationRunning(running);
+        }
     }
 
     public boolean isAddOrRemoveAnimationPending() {
@@ -1918,8 +1937,12 @@
     }
 
     private void setIsExpanded(boolean isExpanded) {
+        boolean changed = isExpanded != mIsExpanded;
         mIsExpanded = isExpanded;
         mStackScrollAlgorithm.setIsExpanded(isExpanded);
+        if (changed) {
+            updateNotificationAnimationStates();
+        }
     }
 
     @Override
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 5d13fed..a43a2a6 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -3484,11 +3484,16 @@
         }
 
         private void notifyWindowsChanged() {
-            // Let the client know the windows changed.
-            AccessibilityEvent event = AccessibilityEvent.obtain(
-                    AccessibilityEvent.TYPE_WINDOWS_CHANGED);
-            event.setEventTime(SystemClock.uptimeMillis());
-            sendAccessibilityEvent(event, mCurrentUserId);
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                // Let the client know the windows changed.
+                AccessibilityEvent event = AccessibilityEvent.obtain(
+                        AccessibilityEvent.TYPE_WINDOWS_CHANGED);
+                event.setEventTime(SystemClock.uptimeMillis());
+                sendAccessibilityEvent(event, mCurrentUserId);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
         }
 
         public boolean canGetAccessibilityNodeInfoLocked(Service service, int windowId) {
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 3e7a7e4..083aa9b 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -8395,10 +8395,15 @@
 
         Slog.i(TAG, "Auto restore => " + doAutoRestore);
 
-        synchronized (this) {
-            Settings.Secure.putInt(mContext.getContentResolver(),
-                    Settings.Secure.BACKUP_AUTO_RESTORE, doAutoRestore ? 1 : 0);
-            mAutoRestore = doAutoRestore;
+        final long oldId = Binder.clearCallingIdentity();
+        try {
+            synchronized (this) {
+                Settings.Secure.putInt(mContext.getContentResolver(),
+                        Settings.Secure.BACKUP_AUTO_RESTORE, doAutoRestore ? 1 : 0);
+                mAutoRestore = doAutoRestore;
+            }
+        } finally {
+            Binder.restoreCallingIdentity(oldId);
         }
     }
 
@@ -8467,10 +8472,15 @@
         synchronized (mTransports) {
             String prevTransport = null;
             if (mTransports.get(transport) != null) {
-                prevTransport = mCurrentTransport;
-                mCurrentTransport = transport;
-                Settings.Secure.putString(mContext.getContentResolver(),
-                        Settings.Secure.BACKUP_TRANSPORT, transport);
+                final long oldId = Binder.clearCallingIdentity();
+                try {
+                    prevTransport = mCurrentTransport;
+                    mCurrentTransport = transport;
+                    Settings.Secure.putString(mContext.getContentResolver(),
+                            Settings.Secure.BACKUP_TRANSPORT, transport);
+                } finally {
+                    Binder.restoreCallingIdentity(oldId);
+                }
                 Slog.v(TAG, "selectBackupTransport() set " + mCurrentTransport
                         + " returning " + prevTransport);
             } else {
diff --git a/services/core/java/com/android/server/MmsServiceBroker.java b/services/core/java/com/android/server/MmsServiceBroker.java
index 2830b5e..65ad1ce 100644
--- a/services/core/java/com/android/server/MmsServiceBroker.java
+++ b/services/core/java/com/android/server/MmsServiceBroker.java
@@ -192,29 +192,30 @@
     // Service API calls implementation, proxied to the real MmsService in "com.android.mms.service"
     private final class BinderService extends IMms.Stub {
         @Override
-        public void sendMessage(long subId, String callingPkg, byte[] pdu, String locationUrl,
-                ContentValues configOverrides, PendingIntent sentIntent) throws RemoteException {
+        public void sendMessage(long subId, String callingPkg, Uri contentUri,
+                String locationUrl, ContentValues configOverrides, PendingIntent sentIntent)
+                        throws RemoteException {
             mContext.enforceCallingPermission(Manifest.permission.SEND_SMS, "Send MMS message");
             if (getAppOpsManager().noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(),
                     callingPkg) != AppOpsManager.MODE_ALLOWED) {
                 return;
             }
-            getServiceGuarded().sendMessage(subId, callingPkg, pdu, locationUrl, configOverrides,
-                    sentIntent);
+            getServiceGuarded().sendMessage(subId, callingPkg, contentUri, locationUrl,
+                    configOverrides, sentIntent);
         }
 
         @Override
         public void downloadMessage(long subId, String callingPkg, String locationUrl,
-                ContentValues configOverrides, PendingIntent downloadedIntent)
-                throws RemoteException {
+                Uri contentUri, ContentValues configOverrides,
+                PendingIntent downloadedIntent) throws RemoteException {
             mContext.enforceCallingPermission(Manifest.permission.RECEIVE_MMS,
                     "Download MMS message");
             if (getAppOpsManager().noteOp(AppOpsManager.OP_RECEIVE_MMS, Binder.getCallingUid(),
                     callingPkg) != AppOpsManager.MODE_ALLOWED) {
                 return;
             }
-            getServiceGuarded().downloadMessage(subId, callingPkg, locationUrl, configOverrides,
-                    downloadedIntent);
+            getServiceGuarded().downloadMessage(subId, callingPkg, locationUrl, contentUri,
+                    configOverrides, downloadedIntent);
         }
 
         @Override
@@ -249,8 +250,9 @@
         }
 
         @Override
-        public Uri importMultimediaMessage(String callingPkg, byte[] pdu, String messageId,
-                long timestampSecs, boolean seen, boolean read) throws RemoteException {
+        public Uri importMultimediaMessage(String callingPkg, Uri contentUri,
+                String messageId, long timestampSecs, boolean seen, boolean read)
+                        throws RemoteException {
             mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS, "Import MMS message");
             if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
                     callingPkg) != AppOpsManager.MODE_ALLOWED) {
@@ -259,7 +261,7 @@
                 return FAKE_MMS_SENT_URI;
             }
             return getServiceGuarded().importMultimediaMessage(
-                    callingPkg, pdu, messageId, timestampSecs, seen, read);
+                    callingPkg, contentUri, messageId, timestampSecs, seen, read);
         }
 
         @Override
@@ -317,7 +319,8 @@
         }
 
         @Override
-        public Uri addMultimediaMessageDraft(String callingPkg, byte[] pdu) throws RemoteException {
+        public Uri addMultimediaMessageDraft(String callingPkg, Uri contentUri)
+                throws RemoteException {
             mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS, "Add MMS draft");
             if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
                     callingPkg) != AppOpsManager.MODE_ALLOWED) {
@@ -325,7 +328,7 @@
                 // while writing the TelephonyProvider
                 return FAKE_MMS_DRAFT_URI;
             }
-            return getServiceGuarded().addMultimediaMessageDraft(callingPkg, pdu);
+            return getServiceGuarded().addMultimediaMessageDraft(callingPkg, contentUri);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 94d979e..c469b42 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -1700,9 +1700,10 @@
             subtitle = titleAndSubtitle.substring(index + 1);
         }
         UserHandle user = new UserHandle(userId);
-        n.color = mContext.getResources().getColor(
+        Context contextForUser = getContextForUser(user);
+        n.color = contextForUser.getResources().getColor(
                 com.android.internal.R.color.system_notification_accent_color);
-        n.setLatestEventInfo(mContext, title, subtitle,
+        n.setLatestEventInfo(contextForUser, title, subtitle,
                 PendingIntent.getActivityAsUser(mContext, 0, intent,
                         PendingIntent.FLAG_CANCEL_CURRENT, null, user));
         installNotification(getCredentialPermissionNotificationId(
@@ -2968,11 +2969,12 @@
                 Notification n = new Notification(android.R.drawable.stat_sys_warning, null,
                         0 /* when */);
                 UserHandle user = new UserHandle(userId);
+                Context contextForUser = getContextForUser(user);
                 final String notificationTitleFormat =
-                        mContext.getText(R.string.notification_title).toString();
-                n.color = mContext.getResources().getColor(
+                        contextForUser.getText(R.string.notification_title).toString();
+                n.color = contextForUser.getResources().getColor(
                         com.android.internal.R.color.system_notification_accent_color);
-                n.setLatestEventInfo(mContext,
+                n.setLatestEventInfo(contextForUser,
                         String.format(notificationTitleFormat, account.name),
                         message, PendingIntent.getActivityAsUser(
                         mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT,
@@ -3478,4 +3480,13 @@
         }
         return authTokensForAccount;
     }
+
+    private Context getContextForUser(UserHandle user) {
+        try {
+            return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
+        } catch (NameNotFoundException e) {
+            // Default to mContext, not finding the package system is running as is unlikely.
+            return mContext;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 008ec99..2e9df8a 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -8408,6 +8408,10 @@
         synchronized(this) {
             TaskRecord tr = recentTaskForIdLocked(taskId);
             if (tr != null) {
+                if (tr == mStackSupervisor.mLockTaskModeTask) {
+                    mStackSupervisor.showLockTaskToast();
+                    return;
+                }
                 if (DEBUG_STACK) Slog.d(TAG, "moveTaskToBack: moving task=" + tr);
                 ActivityStack stack = tr.stack;
                 if (stack.mResumedActivity != null && stack.mResumedActivity.task == tr) {
@@ -8440,11 +8444,19 @@
         enforceNotIsolatedCaller("moveActivityTaskToBack");
         synchronized(this) {
             final long origId = Binder.clearCallingIdentity();
-            int taskId = ActivityRecord.getTaskForActivityLocked(token, !nonRoot);
-            if (taskId >= 0) {
-                return ActivityRecord.getStackLocked(token).moveTaskToBackLocked(taskId, null);
+            try {
+                int taskId = ActivityRecord.getTaskForActivityLocked(token, !nonRoot);
+                if (taskId >= 0) {
+                    if ((mStackSupervisor.mLockTaskModeTask != null)
+                            && (mStackSupervisor.mLockTaskModeTask.taskId == taskId)) {
+                        mStackSupervisor.showLockTaskToast();
+                        return false;
+                    }
+                    return ActivityRecord.getStackLocked(token).moveTaskToBackLocked(taskId, null);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(origId);
             }
-            Binder.restoreCallingIdentity(origId);
         }
         return false;
     }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 6bc1c9c..780efa1 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1262,7 +1262,7 @@
         if (err == ActivityManager.START_SUCCESS) {
             final int userId = aInfo != null ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
             Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false)
-                    + "} from pid " + (callerApp != null ? callerApp.pid : callingPid)
+                    + "} from uid " + callingUid
                     + " on display " + (container == null ? (mFocusedStack == null ?
                             Display.DEFAULT_DISPLAY : mFocusedStack.mDisplayId) :
                             (container.mActivityDisplay == null ? Display.DEFAULT_DISPLAY :
@@ -2075,6 +2075,7 @@
             }
             targetStack = inTask.stack;
             targetStack.moveTaskToFrontLocked(inTask, r, options);
+            targetStack.moveToFront();
             mWindowManager.moveTaskToTop(inTask.taskId);
 
             // Check whether we should actually launch the new activity in to the task,
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index cedf573..ff319d3 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -16,6 +16,7 @@
 
 package com.android.server.connectivity;
 
+import android.app.AlarmManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -213,6 +214,7 @@
     private final NetworkAgentInfo mNetworkAgentInfo;
     private final TelephonyManager mTelephonyManager;
     private final WifiManager mWifiManager;
+    private final AlarmManager mAlarmManager;
 
     private String mServer;
     private boolean mIsCaptivePortalCheckEnabled = false;
@@ -236,6 +238,7 @@
         mNetworkAgentInfo = networkAgentInfo;
         mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
         mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+        mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
 
         addState(mDefaultState);
         addState(mOfflineState, mDefaultState);
@@ -500,10 +503,38 @@
     }
 
     private class LingeringState extends State {
+        private static final String ACTION_LINGER_EXPIRED = "android.net.netmon.lingerExpired";
+        private static final String EXTRA_NETID = "lingerExpiredNetId";
+        private static final String EXTRA_TOKEN = "lingerExpiredToken";
+
+        private class LingerExpiredBroadcastReceiver extends BroadcastReceiver {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (intent.getAction().equals(ACTION_LINGER_EXPIRED) &&
+                        Integer.parseInt(intent.getStringExtra(EXTRA_NETID)) ==
+                        mNetworkAgentInfo.network.netId) {
+                    sendMessage(CMD_LINGER_EXPIRED,
+                            Integer.parseInt(intent.getStringExtra(EXTRA_TOKEN)));
+                }
+            }
+        }
+
+        private BroadcastReceiver mBroadcastReceiver;
+        private PendingIntent mIntent;
+
         @Override
         public void enter() {
-            Message message = obtainMessage(CMD_LINGER_EXPIRED, ++mLingerToken, 0);
-            sendMessageDelayed(message, mLingerDelayMs);
+            mBroadcastReceiver = new LingerExpiredBroadcastReceiver();
+            mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(ACTION_LINGER_EXPIRED));
+
+            Intent intent = new Intent(ACTION_LINGER_EXPIRED, null);
+            intent.putExtra(EXTRA_NETID, String.valueOf(mNetworkAgentInfo.network.netId));
+            intent.putExtra(EXTRA_TOKEN, String.valueOf(++mLingerToken));
+            mIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+            long wakeupTime = SystemClock.elapsedRealtime() + mLingerDelayMs;
+            mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP, wakeupTime,
+                    // Give a specific window so we aren't subject to unknown inexactitude.
+                    mLingerDelayMs / 6, mIntent);
         }
 
         @Override
@@ -524,6 +555,12 @@
                     return NOT_HANDLED;
             }
         }
+
+        @Override
+        public void exit() {
+            mAlarmManager.cancel(mIntent);
+            mContext.unregisterReceiver(mBroadcastReceiver);
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 9e169d9..f6beb9a 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -46,6 +46,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ProviderInfo;
 import android.content.pm.RegisteredServicesCache;
 import android.content.pm.RegisteredServicesCacheListener;
@@ -3098,26 +3099,28 @@
                 return;
             }
 
+            UserHandle user = new UserHandle(userId);
             final PendingIntent pendingIntent = PendingIntent
                     .getActivityAsUser(mContext, 0, clickIntent,
-                            PendingIntent.FLAG_CANCEL_CURRENT, null, new UserHandle(userId));
+                            PendingIntent.FLAG_CANCEL_CURRENT, null, user);
 
             CharSequence tooManyDeletesDescFormat = mContext.getResources().getText(
                     R.string.contentServiceTooManyDeletesNotificationDesc);
 
+            Context contextForUser = getContextForUser(user);
             Notification notification =
                 new Notification(R.drawable.stat_notify_sync_error,
                         mContext.getString(R.string.contentServiceSync),
                         System.currentTimeMillis());
-            notification.color = mContext.getResources().getColor(
+            notification.color = contextForUser.getResources().getColor(
                     com.android.internal.R.color.system_notification_accent_color);
-            notification.setLatestEventInfo(mContext,
-                    mContext.getString(R.string.contentServiceSyncNotificationTitle),
+            notification.setLatestEventInfo(contextForUser,
+                    contextForUser.getString(R.string.contentServiceSyncNotificationTitle),
                     String.format(tooManyDeletesDescFormat.toString(), authorityName),
                     pendingIntent);
             notification.flags |= Notification.FLAG_ONGOING_EVENT;
             mNotificationMgr.notifyAsUser(null, account.hashCode() ^ authority.hashCode(),
-                    notification, new UserHandle(userId));
+                    notification, user);
         }
 
         /**
@@ -3305,4 +3308,13 @@
             return mTable.size();
         }
     }
+
+    private Context getContextForUser(UserHandle user) {
+        try {
+            return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
+        } catch (NameNotFoundException e) {
+            // Default to mContext, not finding the package system is running as is unlikely.
+            return mContext;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 93c0f07..9314cf8 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -856,8 +856,11 @@
                 device.onDeviceRemoved();
                 // There is no explicit event for device removal unlike capability register event
                 // used for device addition . Hence we remove the device on hotplug event.
-                invokeDeviceEventListeners(device.getInfo(), DEVICE_EVENT_REMOVE_DEVICE);
-                updateSafeMhlInput();
+                HdmiDeviceInfo deviceInfo = device.getInfo();
+                if (deviceInfo != null) {
+                    invokeDeviceEventListeners(deviceInfo, DEVICE_EVENT_REMOVE_DEVICE);
+                    updateSafeMhlInput();
+                }
             } else {
                 Slog.w(TAG, "No device to remove:[portId=" + portId);
             }
@@ -1082,7 +1085,7 @@
                         // the connected mobile device, start routing control to switch ports.
                         // callback is handled by MHL action.
                         device.turnOn(callback);
-                        tv.doManualPortSwitching(device.getInfo().getPortId(), null);
+                        tv.doManualPortSwitching(device.getPortId(), null);
                         return;
                     }
                     tv.deviceSelect(deviceId, callback);
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index c3bc306..30154d7 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -199,9 +199,6 @@
             List<JobStatus> jobsForUser = mJobs.getJobsByUser(userHandle);
             for (int i=0; i<jobsForUser.size(); i++) {
                 JobStatus toRemove = jobsForUser.get(i);
-                if (DEBUG) {
-                    Slog.d(TAG, "Cancelling: " + toRemove);
-                }
                 cancelJobLocked(toRemove);
             }
         }
@@ -219,9 +216,6 @@
             List<JobStatus> jobsForUid = mJobs.getJobsByUid(uid);
             for (int i=0; i<jobsForUid.size(); i++) {
                 JobStatus toRemove = jobsForUid.get(i);
-                if (DEBUG) {
-                    Slog.d(TAG, "Cancelling: " + toRemove);
-                }
                 cancelJobLocked(toRemove);
             }
         }
@@ -547,14 +541,28 @@
         private void queueReadyJobsForExecutionH() {
             synchronized (mJobs) {
                 ArraySet<JobStatus> jobs = mJobs.getJobs();
+                if (DEBUG) {
+                    Slog.d(TAG, "queuing all ready jobs for execution:");
+                }
                 for (int i=0; i<jobs.size(); i++) {
                     JobStatus job = jobs.valueAt(i);
                     if (isReadyToBeExecutedLocked(job)) {
+                        if (DEBUG) {
+                            Slog.d(TAG, "    queued " + job.toShortString());
+                        }
                         mPendingJobs.add(job);
                     } else if (isReadyToBeCancelledLocked(job)) {
                         stopJobOnServiceContextLocked(job);
                     }
                 }
+                if (DEBUG) {
+                    final int queuedJobs = mPendingJobs.size();
+                    if (queuedJobs == 0) {
+                        Slog.d(TAG, "No jobs pending.");
+                    } else {
+                        Slog.d(TAG, queuedJobs + " jobs queued.");
+                    }
+                }
             }
         }
 
@@ -657,6 +665,9 @@
         private void maybeRunPendingJobsH() {
             synchronized (mJobs) {
                 Iterator<JobStatus> it = mPendingJobs.iterator();
+                if (DEBUG) {
+                    Slog.d(TAG, "pending queue: " + mPendingJobs.size() + " jobs.");
+                }
                 while (it.hasNext()) {
                     JobStatus nextPending = it.next();
                     JobServiceContext availableContext = null;
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 5297911..344c57b 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -157,6 +157,7 @@
             mExecutionStartTimeElapsed = SystemClock.elapsedRealtime();
 
             mVerb = VERB_BINDING;
+            scheduleOpTimeOut();
             final Intent intent = new Intent().setComponent(job.getServiceComponent());
             boolean binding = mContext.bindServiceAsUser(intent, this,
                     Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND,
@@ -253,8 +254,6 @@
             return;
         }
         this.service = IJobService.Stub.asInterface(service);
-        // Remove all timeouts.
-        mCallbackHandler.removeMessages(MSG_TIMEOUT);
         final PowerManager pm =
                 (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mRunningJob.getTag());
@@ -299,6 +298,7 @@
         public void handleMessage(Message message) {
             switch (message.what) {
                 case MSG_SERVICE_BOUND:
+                    removeMessages(MSG_TIMEOUT);
                     handleServiceBoundH();
                     break;
                 case MSG_CALLBACK:
@@ -337,6 +337,9 @@
 
         /** Start the job on the service. */
         private void handleServiceBoundH() {
+            if (DEBUG) {
+                Slog.d(TAG, "MSG_SERVICE_BOUND for " + mRunningJob.toShortString());
+            }
             if (mVerb != VERB_BINDING) {
                 Slog.e(TAG, "Sending onStartJob for a job that isn't pending. "
                         + VERB_STRINGS[mVerb]);
@@ -456,42 +459,36 @@
 
         /** Process MSG_TIMEOUT here. */
         private void handleOpTimeoutH() {
-            if (JobSchedulerService.DEBUG) {
-                Slog.d(TAG, "MSG_TIMEOUT of " +
-                        mRunningJob.getServiceComponent().getShortClassName() + " : "
-                        + mParams.getJobId());
-            }
-
-            final int jobId = mParams.getJobId();
             switch (mVerb) {
+                case VERB_BINDING:
+                    Slog.e(TAG, "Time-out while trying to bind " + mRunningJob.toShortString() +
+                            ", dropping.");
+                    closeAndCleanupJobH(false /* needsReschedule */);
+                    break;
                 case VERB_STARTING:
                     // Client unresponsive - wedged or failed to respond in time. We don't really
                     // know what happened so let's log it and notify the JobScheduler
                     // FINISHED/NO-RETRY.
                     Slog.e(TAG, "No response from client for onStartJob '" +
-                            mRunningJob.getServiceComponent().getShortClassName() + "' jId: "
-                            + jobId);
+                            mRunningJob.toShortString());
                     closeAndCleanupJobH(false /* needsReschedule */);
                     break;
                 case VERB_STOPPING:
                     // At least we got somewhere, so fail but ask the JobScheduler to reschedule.
                     Slog.e(TAG, "No response from client for onStopJob, '" +
-                            mRunningJob.getServiceComponent().getShortClassName() + "' jId: "
-                            + jobId);
+                            mRunningJob.toShortString());
                     closeAndCleanupJobH(true /* needsReschedule */);
                     break;
                 case VERB_EXECUTING:
                     // Not an error - client ran out of time.
                     Slog.i(TAG, "Client timed out while executing (no jobFinished received)." +
-                            " sending onStop. "  +
-                            mRunningJob.getServiceComponent().getShortClassName() + "' jId: "
-                            + jobId);
+                            " sending onStop. "  + mRunningJob.toShortString());
                     sendStopMessageH();
                     break;
                 default:
-                    Slog.e(TAG, "Handling timeout for an unknown active job state: "
-                            + mRunningJob);
-                    return;
+                    Slog.e(TAG, "Handling timeout for an invalid job state: " +
+                            mRunningJob.toShortString() + ", dropping.");
+                    closeAndCleanupJobH(false /* needsReschedule */);
             }
         }
 
@@ -530,7 +527,9 @@
                 } catch (RemoteException e) {
                     // Whatever.
                 }
-                mWakeLock.release();
+                if (mWakeLock != null) {
+                    mWakeLock.release();
+                }
                 mContext.unbindService(JobServiceContext.this);
                 mWakeLock = null;
                 mRunningJob = null;
@@ -547,25 +546,25 @@
             removeMessages(MSG_SHUTDOWN_EXECUTION);
             mCompletedListener.onJobCompleted(completedJob, reschedule);
         }
+    }
 
-        /**
-         * Called when sending a message to the client, over whose execution we have no control. If
-         * we haven't received a response in a certain amount of time, we want to give up and carry
-         * on with life.
-         */
-        private void scheduleOpTimeOut() {
-            mCallbackHandler.removeMessages(MSG_TIMEOUT);
+    /**
+     * Called when sending a message to the client, over whose execution we have no control. If
+     * we haven't received a response in a certain amount of time, we want to give up and carry
+     * on with life.
+     */
+    private void scheduleOpTimeOut() {
+        mCallbackHandler.removeMessages(MSG_TIMEOUT);
 
-            final long timeoutMillis = (mVerb == VERB_EXECUTING) ?
-                    EXECUTING_TIMESLICE_MILLIS : OP_TIMEOUT_MILLIS;
-            if (DEBUG) {
-                Slog.d(TAG, "Scheduling time out for '" +
-                        mRunningJob.getServiceComponent().getShortClassName() + "' jId: " +
-                        mParams.getJobId() + ", in " + (timeoutMillis / 1000) + " s");
-            }
-            Message m = mCallbackHandler.obtainMessage(MSG_TIMEOUT);
-            mCallbackHandler.sendMessageDelayed(m, timeoutMillis);
-            mTimeoutElapsed = SystemClock.elapsedRealtime() + timeoutMillis;
+        final long timeoutMillis = (mVerb == VERB_EXECUTING) ?
+                EXECUTING_TIMESLICE_MILLIS : OP_TIMEOUT_MILLIS;
+        if (DEBUG) {
+            Slog.d(TAG, "Scheduling time out for '" +
+                    mRunningJob.getServiceComponent().getShortClassName() + "' jId: " +
+                    mParams.getJobId() + ", in " + (timeoutMillis / 1000) + " s");
         }
+        Message m = mCallbackHandler.obtainMessage(MSG_TIMEOUT);
+        mCallbackHandler.sendMessageDelayed(m, timeoutMillis);
+        mTimeoutElapsed = SystemClock.elapsedRealtime() + timeoutMillis;
     }
 }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d0f4054..0794edf 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1126,6 +1126,19 @@
             return mRankingHelper.getPackagePriority(pkg, uid);
         }
 
+        @Override
+        public void setPackageVisibilityOverride(String pkg, int uid, int visibility) {
+            checkCallerIsSystem();
+            mRankingHelper.setPackageVisibilityOverride(pkg, uid, visibility);
+            savePolicyFile();
+        }
+
+        @Override
+        public int getPackageVisibilityOverride(String pkg, int uid) {
+            checkCallerIsSystem();
+            return mRankingHelper.getPackageVisibilityOverride(pkg, uid);
+        }
+
         /**
          * System-only API for getting a list of current (i.e. not cleared) notifications.
          *
@@ -2045,12 +2058,15 @@
             }
             int indexBefore = findNotificationRecordIndexLocked(record);
             boolean interceptBefore = record.isIntercepted();
+            int visibilityBefore = record.getPackageVisibilityOverride();
             recon.applyChangesLocked(record);
             applyZenModeLocked(record);
             mRankingHelper.sort(mNotificationList);
             int indexAfter = findNotificationRecordIndexLocked(record);
             boolean interceptAfter = record.isIntercepted();
-            changed = indexBefore != indexAfter || interceptBefore != interceptAfter;
+            int visibilityAfter = record.getPackageVisibilityOverride();
+            changed = indexBefore != indexAfter || interceptBefore != interceptAfter
+                    || visibilityBefore != visibilityAfter;
             if (interceptBefore && !interceptAfter) {
                 buzzBeepBlinkLocked(record);
             }
@@ -2064,14 +2080,18 @@
         synchronized (mNotificationList) {
             final int N = mNotificationList.size();
             ArrayList<String> orderBefore = new ArrayList<String>(N);
+            int[] visibilities = new int[N];
             for (int i = 0; i < N; i++) {
                 final NotificationRecord r = mNotificationList.get(i);
                 orderBefore.add(r.getKey());
+                visibilities[i] = r.getPackageVisibilityOverride();
                 mRankingHelper.extractSignals(r);
             }
-            mRankingHelper.sort(mNotificationList);
             for (int i = 0; i < N; i++) {
-                if (!orderBefore.get(i).equals(mNotificationList.get(i).getKey())) {
+                mRankingHelper.sort(mNotificationList);
+                final NotificationRecord r = mNotificationList.get(i);
+                if (!orderBefore.get(i).equals(r.getKey())
+                        || visibilities[i] != r.getPackageVisibilityOverride()) {
                     scheduleSendRankingUpdate();
                     return;
                 }
@@ -2601,6 +2621,7 @@
         final int N = mNotificationList.size();
         ArrayList<String> keys = new ArrayList<String>(N);
         ArrayList<String> interceptedKeys = new ArrayList<String>(N);
+        Bundle visibilityOverrides = new Bundle();
         for (int i = 0; i < N; i++) {
             NotificationRecord record = mNotificationList.get(i);
             if (!isVisibleToListener(record.sbn, info)) {
@@ -2610,6 +2631,11 @@
             if (record.isIntercepted()) {
                 interceptedKeys.add(record.sbn.getKey());
             }
+            if (record.getPackageVisibilityOverride()
+                    != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
+                visibilityOverrides.putInt(record.sbn.getKey(),
+                        record.getPackageVisibilityOverride());
+            }
             if (speedBumpIndex == -1 &&
                     record.sbn.getNotification().priority == Notification.PRIORITY_MIN) {
                 speedBumpIndex = keys.size() - 1;
@@ -2617,7 +2643,8 @@
         }
         String[] keysAr = keys.toArray(new String[keys.size()]);
         String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
-        return new NotificationRankingUpdate(keysAr, interceptedKeysAr, speedBumpIndex);
+        return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
+                speedBumpIndex);
     }
 
     private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index f2bd676..84b4d97 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -65,6 +65,7 @@
 
     private int mAuthoritativeRank;
     private String mGlobalSortKey;
+    private int mPackageVisibility;
 
     @VisibleForTesting
     public NotificationRecord(StatusBarNotification sbn, int score)
@@ -79,6 +80,7 @@
         mContactAffinity = previous.mContactAffinity;
         mRecentlyIntrusive = previous.mRecentlyIntrusive;
         mPackagePriority = previous.mPackagePriority;
+        mPackageVisibility = previous.mPackageVisibility;
         mIntercept = previous.mIntercept;
         mRankingTimeMs = calculateRankingTimeMs(previous.getRankingTimeMs());
         // Don't copy mGlobalSortKey, recompute it.
@@ -155,6 +157,7 @@
         pw.println(prefix + "  mContactAffinity=" + mContactAffinity);
         pw.println(prefix + "  mRecentlyIntrusive=" + mRecentlyIntrusive);
         pw.println(prefix + "  mPackagePriority=" + mPackagePriority);
+        pw.println(prefix + "  mPackageVisibility=" + mPackageVisibility);
         pw.println(prefix + "  mIntercept=" + mIntercept);
         pw.println(prefix + "  mGlobalSortKey=" + mGlobalSortKey);
         pw.println(prefix + "  mRankingTimeMs=" + mRankingTimeMs);
@@ -216,6 +219,14 @@
         return mPackagePriority;
     }
 
+    public void setPackageVisibilityOverride(int packageVisibility) {
+        mPackageVisibility = packageVisibility;
+    }
+
+    public int getPackageVisibilityOverride() {
+        return mPackageVisibility;
+    }
+
     public boolean setIntercepted(boolean intercept) {
         mIntercept = intercept;
         return mIntercept;
diff --git a/services/core/java/com/android/server/notification/PackageVisibilityExtractor.java b/services/core/java/com/android/server/notification/PackageVisibilityExtractor.java
new file mode 100644
index 0000000..f720f9f
--- /dev/null
+++ b/services/core/java/com/android/server/notification/PackageVisibilityExtractor.java
@@ -0,0 +1,53 @@
+/*
+* Copyright (C) 2014 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package com.android.server.notification;
+
+import android.content.Context;
+import android.util.Slog;
+
+public class PackageVisibilityExtractor implements NotificationSignalExtractor {
+    private static final String TAG = "PackageVisibilityExtractor";
+    private static final boolean DBG = false;
+
+    private RankingConfig mConfig;
+
+    public void initialize(Context ctx) {
+        if (DBG) Slog.d(TAG, "Initializing  " + getClass().getSimpleName() + ".");
+    }
+
+    public RankingReconsideration process(NotificationRecord record) {
+        if (record == null || record.getNotification() == null) {
+            if (DBG) Slog.d(TAG, "skipping empty notification");
+            return null;
+        }
+
+        if (mConfig == null) {
+            if (DBG) Slog.d(TAG, "missing config");
+            return null;
+        }
+
+        final int packageVisibility = mConfig.getPackageVisibilityOverride(
+                record.sbn.getPackageName(), record.sbn.getUid());
+        record.setPackageVisibilityOverride(packageVisibility);
+
+        return null;
+    }
+
+    @Override
+    public void setConfig(RankingConfig config) {
+        mConfig = config;
+    }
+}
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index 7d0bd59..aea137b 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -19,4 +19,8 @@
     int getPackagePriority(String packageName, int uid);
 
     void setPackagePriority(String packageName, int uid, int priority);
+
+    int getPackageVisibilityOverride(String packageName, int uid);
+
+    void setPackageVisibilityOverride(String packageName, int uid, int visibility);
 }
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 435177b..aeddecb 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -20,8 +20,10 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.UserHandle;
+import android.service.notification.NotificationListenerService;
 import android.text.TextUtils;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseIntArray;
@@ -33,7 +35,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Comparator;
+import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 public class RankingHelper implements RankingConfig {
@@ -49,6 +51,7 @@
     private static final String ATT_NAME = "name";
     private static final String ATT_UID = "uid";
     private static final String ATT_PRIORITY = "priority";
+    private static final String ATT_VISIBILITY = "visibility";
 
     private final NotificationSignalExtractor[] mSignalExtractors;
     private final NotificationComparator mPreliminaryComparator = new NotificationComparator();
@@ -56,6 +59,7 @@
 
     // Package name to uid, to priority. Would be better as Table<String, Int, Int>
     private final ArrayMap<String, SparseIntArray> mPackagePriorities;
+    private final ArrayMap<String, SparseIntArray> mPackageVisibilities;
     private final ArrayMap<String, NotificationRecord> mProxyByGroupTmp;
 
     private final Context mContext;
@@ -65,6 +69,7 @@
         mContext = context;
         mRankingHandler = rankingHandler;
         mPackagePriorities = new ArrayMap<String, SparseIntArray>();
+        mPackageVisibilities = new ArrayMap<String, SparseIntArray>();
 
         final int N = extractorNames.length;
         mSignalExtractors = new NotificationSignalExtractor[N];
@@ -132,15 +137,27 @@
                 if (TAG_PACKAGE.equals(tag)) {
                     int uid = safeInt(parser, ATT_UID, UserHandle.USER_ALL);
                     int priority = safeInt(parser, ATT_PRIORITY, Notification.PRIORITY_DEFAULT);
+                    int vis = safeInt(parser, ATT_VISIBILITY,
+                            NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE);
                     String name = parser.getAttributeValue(null, ATT_NAME);
 
-                    if (!TextUtils.isEmpty(name) && priority != Notification.PRIORITY_DEFAULT) {
-                        SparseIntArray priorityByUid = mPackagePriorities.get(name);
-                        if (priorityByUid == null) {
-                            priorityByUid = new SparseIntArray();
-                            mPackagePriorities.put(name, priorityByUid);
+                    if (!TextUtils.isEmpty(name)) {
+                        if (priority != Notification.PRIORITY_DEFAULT) {
+                            SparseIntArray priorityByUid = mPackagePriorities.get(name);
+                            if (priorityByUid == null) {
+                                priorityByUid = new SparseIntArray();
+                                mPackagePriorities.put(name, priorityByUid);
+                            }
+                            priorityByUid.put(uid, priority);
                         }
-                        priorityByUid.put(uid, priority);
+                        if (vis != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
+                            SparseIntArray visibilityByUid = mPackageVisibilities.get(name);
+                            if (visibilityByUid == null) {
+                                visibilityByUid = new SparseIntArray();
+                                mPackageVisibilities.put(name, visibilityByUid);
+                            }
+                            visibilityByUid.put(uid, vis);
+                        }
                     }
                 }
             }
@@ -152,18 +169,43 @@
         out.startTag(null, TAG_RANKING);
         out.attribute(null, ATT_VERSION, Integer.toString(XML_VERSION));
 
-        final int N = mPackagePriorities.size();
-        for (int i = 0; i < N; i ++) {
-            String name = mPackagePriorities.keyAt(i);
-            SparseIntArray priorityByUid = mPackagePriorities.get(name);
-            final int M = priorityByUid.size();
-            for (int j = 0; j < M; j++) {
-                int uid = priorityByUid.keyAt(j);
-                int priority = priorityByUid.get(uid);
+        final Set<String> packageNames = new ArraySet<>(mPackagePriorities.size()
+                + mPackageVisibilities.size());
+        packageNames.addAll(mPackagePriorities.keySet());
+        packageNames.addAll(mPackageVisibilities.keySet());
+        final Set<Integer> packageUids = new ArraySet<>();
+        for (String packageName : packageNames) {
+            packageUids.clear();
+            SparseIntArray priorityByUid = mPackagePriorities.get(packageName);
+            SparseIntArray visibilityByUid = mPackageVisibilities.get(packageName);
+            if (priorityByUid != null) {
+                final int M = priorityByUid.size();
+                for (int j = 0; j < M; j++) {
+                    packageUids.add(priorityByUid.keyAt(j));
+                }
+            }
+            if (visibilityByUid != null) {
+                final int M = visibilityByUid.size();
+                for (int j = 0; j < M; j++) {
+                    packageUids.add(visibilityByUid.keyAt(j));
+                }
+            }
+            for (Integer uid : packageUids) {
                 out.startTag(null, TAG_PACKAGE);
-                out.attribute(null, ATT_NAME, name);
+                out.attribute(null, ATT_NAME, packageName);
+                if (priorityByUid != null) {
+                    final int priority = priorityByUid.get(uid);
+                    if (priority != Notification.PRIORITY_DEFAULT) {
+                        out.attribute(null, ATT_PRIORITY, Integer.toString(priority));
+                    }
+                }
+                if (visibilityByUid != null) {
+                    final int visibility = visibilityByUid.get(uid);
+                    if (visibility != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
+                        out.attribute(null, ATT_VISIBILITY, Integer.toString(visibility));
+                    }
+                }
                 out.attribute(null, ATT_UID, Integer.toString(uid));
-                out.attribute(null, ATT_PRIORITY, Integer.toString(priority));
                 out.endTag(null, TAG_PACKAGE);
             }
         }
@@ -293,6 +335,31 @@
         updateConfig();
     }
 
+    @Override
+    public int getPackageVisibilityOverride(String packageName, int uid) {
+        int visibility = NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE;
+        SparseIntArray visibilityByUid = mPackageVisibilities.get(packageName);
+        if (visibilityByUid != null) {
+            visibility = visibilityByUid.get(uid,
+                    NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE);
+        }
+        return visibility;
+    }
+
+    @Override
+    public void setPackageVisibilityOverride(String packageName, int uid, int visibility) {
+        if (visibility == getPackageVisibilityOverride(packageName, uid)) {
+            return;
+        }
+        SparseIntArray visibilityByUid = mPackageVisibilities.get(packageName);
+        if (visibilityByUid == null) {
+            visibilityByUid = new SparseIntArray();
+            mPackageVisibilities.put(packageName, visibilityByUid);
+        }
+        visibilityByUid.put(uid, visibility);
+        updateConfig();
+    }
+
     public void dump(PrintWriter pw, String prefix, NotificationManagerService.DumpFilter filter) {
         if (filter == null) {
             final int N = mSignalExtractors.length;
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index 37bedf3..4a8e318 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -538,14 +538,17 @@
                     pw.println("");
                 }
                 printedLabel = false;
-                for (long keySetId : pkg.keySetData.getSigningKeySets()) {
-                    if (!printedLabel) {
-                        pw.print("      Signing KeySets: ");
-                        printedLabel = true;
-                    } else {
-                        pw.print(", ");
+                final long[] signingKeySets = pkg.keySetData.getSigningKeySets();
+                if (signingKeySets != null) {
+                    for (long keySetId : signingKeySets) {
+                        if (!printedLabel) {
+                            pw.print("      Signing KeySets: ");
+                            printedLabel = true;
+                        } else {
+                            pw.print(", ");
+                        }
+                        pw.print(Long.toString(keySetId));
                     }
-                    pw.print(Long.toString(keySetId));
                 }
                 if (printedLabel) {
                     pw.println("");
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9554afa..228c120 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -317,6 +317,7 @@
     final Context mContext;
     final boolean mFactoryTest;
     final boolean mOnlyCore;
+    final boolean mLazyDexOpt;
     final DisplayMetrics mMetrics;
     final int mDefParseFlags;
     final String[] mSeparateProcesses;
@@ -1266,6 +1267,7 @@
         mContext = context;
         mFactoryTest = factoryTest;
         mOnlyCore = onlyCore;
+        mLazyDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
         mMetrics = new DisplayMetrics();
         mSettings = new Settings(context);
         mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
@@ -4451,13 +4453,12 @@
         if (pkgs != null) {
             // Filter out packages that aren't recently used.
             //
-            // The exception is first boot of a non-eng device, which
+            // The exception is first boot of a non-eng device (aka !mLazyDexOpt), which
             // should do a full dexopt.
-            boolean eng = "eng".equals(SystemProperties.get("ro.build.type"));
-            if (eng || (!isFirstBoot() && mPackageUsage.isHistoricalPackageUsageAvailable())) {
+            if (mLazyDexOpt || (!isFirstBoot() && mPackageUsage.isHistoricalPackageUsageAvailable())) {
                 // TODO: add a property to control this?
                 long dexOptLRUThresholdInMinutes;
-                if (eng) {
+                if (mLazyDexOpt) {
                     dexOptLRUThresholdInMinutes = 30; // only last 30 minutes of apps for eng builds.
                 } else {
                     dexOptLRUThresholdInMinutes = 7 * 24 * 60; // apps used in the 7 days for users.
@@ -4522,7 +4523,13 @@
         return VMRuntime.getInstructionSet(info.primaryCpuAbi);
     }
 
-    public boolean performDexOpt(String packageName, String instructionSet, boolean updateUsage) {
+    public boolean performDexOpt(String packageName, String instructionSet, boolean backgroundDexopt) {
+        boolean dexopt = mLazyDexOpt || backgroundDexopt;
+        boolean updateUsage = !backgroundDexopt;  // Don't update usage if this is just a backgroundDexopt
+        if (!dexopt && !updateUsage) {
+            // We aren't going to dexopt or update usage, so bail early.
+            return false;
+        }
         PackageParser.Package p;
         final String targetInstructionSet;
         synchronized (mPackages) {
@@ -4534,6 +4541,10 @@
                 p.mLastPackageUsageTimeInMills = System.currentTimeMillis();
             }
             mPackageUsage.write(false);
+            if (!dexopt) {
+                // We aren't going to dexopt, so bail early.
+                return false;
+            }
 
             targetInstructionSet = instructionSet != null ? instructionSet :
                     getPrimaryInstructionSet(p.applicationInfo);
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index c346f71..c1caeac 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -602,11 +602,8 @@
                             // original default value is true), or we are being
                             // asked to install for all users, or this is the
                             // user we are installing for.
-                            // In this context all users (USER_ALL) implies an adb install,
-                            // so we additionally check whether that is allowed for this user.
                             final boolean installed = installUser == null
-                                    || (installUser.getIdentifier() == UserHandle.USER_ALL
-                                            && (!isUnknownSourcesDisallowed(user.id)))
+                                    || installUser.getIdentifier() == UserHandle.USER_ALL
                                     || installUser.getIdentifier() == user.id;
                             p.setUserState(user.id, COMPONENT_ENABLED_STATE_DEFAULT,
                                     installed,
@@ -673,10 +670,7 @@
                 List<UserInfo> users = getAllUsers();
                 if (users != null) {
                     for (UserInfo user : users) {
-                        // Installing for USER_ALL implies an adb install, so we
-                        // additionally check whether that is allowed for this user.
-                        if ((installUser.getIdentifier() == UserHandle.USER_ALL
-                                        && (!isUnknownSourcesDisallowed(user.id)))
+                        if (installUser.getIdentifier() == UserHandle.USER_ALL
                                 || installUser.getIdentifier() == user.id) {
                             boolean installed = p.getInstalled(user.id);
                             if (!installed) {
@@ -691,12 +685,6 @@
         return p;
     }
 
-    boolean isUnknownSourcesDisallowed(int userId) {
-        UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        return um.getUserRestrictions(new UserHandle(userId)).getBoolean(
-                UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, false);
-    }
-
     void insertPackageSettingLPw(PackageSetting p, PackageParser.Package pkg) {
         p.pkg = pkg;
         // pkg.mSetEnabled = p.getEnabled(userId);
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 7e0215c..c8b5b3e 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -116,7 +116,7 @@
         if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY && !isSafeMode()) {
             mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
             mReceiver.register(mContext);
-            refreshAgentList();
+            refreshAgentList(UserHandle.USER_ALL);
         }
     }
 
@@ -157,11 +157,17 @@
         dispatchOnTrustChanged(aggregateIsTrusted(userId), userId, initiatedByUser);
     }
 
-    void refreshAgentList() {
+    void refreshAgentList(int userId) {
         if (DEBUG) Slog.d(TAG, "refreshAgentList()");
         PackageManager pm = mContext.getPackageManager();
 
-        List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */);
+        List<UserInfo> userInfos;
+        if (userId == UserHandle.USER_ALL) {
+            userInfos = mUserManager.getUsers(true /* excludeDying */);
+        } else {
+            userInfos = new ArrayList<>();
+            userInfos.add(mUserManager.getUserInfo(userId));
+        }
         LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
 
         ArraySet<AgentInfo> obsoleteAgents = new ArraySet<>();
@@ -170,6 +176,7 @@
         for (UserInfo userInfo : userInfos) {
             if (lockPatternUtils.getKeyguardStoredPasswordQuality(userInfo.id)
                     == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) continue;
+            if (!mUserHasAuthenticatedSinceBoot.get(userInfo.id)) continue;
             DevicePolicyManager dpm = lockPatternUtils.getDevicePolicyManager();
             int disabledFeatures = dpm.getKeyguardDisabledFeatures(null, userInfo.id);
             final boolean disableTrustAgents =
@@ -233,7 +240,7 @@
         }
     }
 
-    void updateDevicePolicyFeatures(int userId) {
+    void updateDevicePolicyFeatures() {
         for (int i = 0; i < mActiveAgents.size(); i++) {
             AgentInfo info = mActiveAgents.valueAt(i);
             if (info.agent.isConnected()) {
@@ -276,7 +283,7 @@
         if (trustMayHaveChanged) {
             updateTrust(userId, false);
         }
-        refreshAgentList();
+        refreshAgentList(userId);
     }
 
     private ComponentName getSettingsComponentName(PackageManager pm, ResolveInfo resolveInfo) {
@@ -383,7 +390,7 @@
     private void updateUserHasAuthenticated(int userId) {
         if (!mUserHasAuthenticatedSinceBoot.get(userId)) {
             mUserHasAuthenticatedSinceBoot.put(userId, true);
-            updateTrust(userId, false);
+            refreshAgentList(userId);
         }
     }
 
@@ -391,10 +398,10 @@
     private void requireCredentialEntry(int userId) {
         if (userId == UserHandle.USER_ALL) {
             mUserHasAuthenticatedSinceBoot.clear();
-            updateTrustAll();
+            refreshAgentList(UserHandle.USER_ALL);
         } else {
             mUserHasAuthenticatedSinceBoot.put(userId, false);
-            updateTrust(userId, false);
+            refreshAgentList(userId);
         }
     }
 
@@ -578,7 +585,7 @@
                     dispatchUnlockAttempt(msg.arg1 != 0, msg.arg2);
                     break;
                 case MSG_ENABLED_AGENTS_CHANGED:
-                    refreshAgentList();
+                    refreshAgentList(UserHandle.USER_ALL);
                     break;
                 case MSG_REQUIRE_CREDENTIAL_ENTRY:
                     requireCredentialEntry(msg.arg1);
@@ -590,7 +597,7 @@
     private final PackageMonitor mPackageMonitor = new PackageMonitor() {
         @Override
         public void onSomePackagesChanged() {
-            refreshAgentList();
+            refreshAgentList(UserHandle.USER_ALL);
         }
 
         @Override
@@ -611,8 +618,8 @@
         public void onReceive(Context context, Intent intent) {
             if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(
                     intent.getAction())) {
-                refreshAgentList();
-                updateDevicePolicyFeatures(getSendingUserId());
+                refreshAgentList(getSendingUserId());
+                updateDevicePolicyFeatures();
             } else if (Intent.ACTION_USER_PRESENT.equals(intent.getAction())) {
                 updateUserHasAuthenticated(getSendingUserId());
             }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 564a3df..cad2772 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -40,7 +40,6 @@
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
-import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
@@ -70,7 +69,6 @@
 import android.os.UserManager;
 import android.provider.Settings;
 import android.security.Credentials;
-import android.security.IKeyChainService;
 import android.security.KeyChain;
 import android.security.KeyChain.KeyChainConnection;
 import android.util.Log;
@@ -2749,7 +2747,8 @@
         return !"".equals(state);
     }
 
-    public boolean installCaCert(ComponentName who, byte[] certBuffer) throws RemoteException {
+    @Override
+    public void enforceCanManageCaCerts(ComponentName who) {
         if (who == null) {
             mContext.enforceCallingOrSelfPermission(MANAGE_CA_CERTIFICATES, null);
         } else {
@@ -2757,6 +2756,11 @@
                 getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             }
         }
+    }
+
+    @Override
+    public boolean installCaCert(ComponentName admin, byte[] certBuffer) throws RemoteException {
+        enforceCanManageCaCerts(admin);
 
         byte[] pemCert;
         try {
@@ -2791,21 +2795,15 @@
         return false;
     }
 
-    private static X509Certificate parseCert(byte[] certBuffer)
-            throws CertificateException, IOException {
+    private static X509Certificate parseCert(byte[] certBuffer) throws CertificateException {
         CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
         return (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(
                 certBuffer));
     }
 
-    public void uninstallCaCert(ComponentName who, String alias) {
-        if (who == null) {
-            mContext.enforceCallingOrSelfPermission(MANAGE_CA_CERTIFICATES, null);
-        } else {
-            synchronized (this) {
-                getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
-            }
-        }
+    @Override
+    public void uninstallCaCert(ComponentName admin, String alias) {
+        enforceCanManageCaCerts(admin);
 
         final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
         final long id = Binder.clearCallingIdentity();
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index ce91f3d..64242ba 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -26,6 +26,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.pm.UserInfo;
@@ -730,7 +731,14 @@
                     PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT, null,
                     userHandle);
 
-            Notification.Builder builder = new Notification.Builder(mContext)
+            Context builderContext = mContext;
+            try {
+                builderContext = mContext.createPackageContextAsUser(mContext.getPackageName(), 0,
+                        userHandle);
+            } catch (NameNotFoundException e) {
+                // Ignore can't find the package the system is running as.
+            }
+            Notification.Builder builder = new Notification.Builder(builderContext)
                     .setSmallIcon(R.drawable.ic_print)
                     .setContentTitle(mContext.getString(R.string.print_service_installed_title,
                             label))
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 6e13732..a0b8c94 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -125,7 +125,8 @@
                 UserInfo.FLAG_MANAGED_PROFILE, UserHandle.USER_OWNER);
         assertNotNull(userInfo1);
         assertNull(userInfo2);
-
+        // Verify that current user is not a managed profile
+        assertFalse(mUserManager.isManagedProfile());
         // Cleanup
         removeUser(userInfo1.id);
     }
diff --git a/telecomm/java/android/telecomm/Call.java b/telecomm/java/android/telecomm/Call.java
index 7c596c1..5bf0855 100644
--- a/telecomm/java/android/telecomm/Call.java
+++ b/telecomm/java/android/telecomm/Call.java
@@ -347,14 +347,6 @@
         public void onVideoCallChanged(Call call, InCallService.VideoCall videoCall) {}
 
         /**
-         * Launches an activity for this connection on top of the in-call UI.
-         *
-         * @param call The {@code Call} invoking this method.
-         * @param intent The intent to use to start the activity.
-         */
-        public void onStartActivity(Call call, PendingIntent intent) {}
-
-        /**
          * Invoked when the {@code Call} is destroyed. Clients should refrain from cleaning
          * up their UI for the {@code Call} in response to state transitions. Specifically,
          * clients should not assume that a {@link #onStateChanged(Call, int)} with a state of
@@ -753,11 +745,6 @@
     }
 
     /** {@hide} */
-    final void internalStartActivity(PendingIntent intent) {
-        fireStartActivity(intent);
-    }
-
-    /** {@hide} */
     final void internalSetDisconnected() {
         if (mState != Call.STATE_DISCONNECTED) {
             mState = Call.STATE_DISCONNECTED;
@@ -809,12 +796,6 @@
         }
     }
 
-    private void fireStartActivity(PendingIntent intent) {
-        for (Listener listener : mListeners) {
-            listener.onStartActivity(this, intent);
-        }
-    }
-
     private void fireCallDestroyed() {
         for (Listener listener : mListeners) {
             listener.onCallDestroyed(this);
diff --git a/telecomm/java/android/telecomm/Connection.java b/telecomm/java/android/telecomm/Connection.java
index f349659..4d6e267 100644
--- a/telecomm/java/android/telecomm/Connection.java
+++ b/telecomm/java/android/telecomm/Connection.java
@@ -81,7 +81,6 @@
                 Connection c, VideoProvider videoProvider) {}
         public void onAudioModeIsVoipChanged(Connection c, boolean isVoip) {}
         public void onStatusHintsChanged(Connection c, StatusHints statusHints) {}
-        public void onStartActivityFromInCall(Connection c, PendingIntent intent) {}
         public void onConferenceableConnectionsChanged(
                 Connection c, List<Connection> conferenceableConnections) {}
         public void onConferenceChanged(Connection c, Conference conference) {}
@@ -942,20 +941,6 @@
     }
 
     /**
-     * Launches an activity for this connection on top of the in-call UI.
-     *
-     * @param intent The intent to use to start the activity.
-     */
-    public final void startActivityFromInCall(PendingIntent intent) {
-        if (!intent.isActivity()) {
-            throw new IllegalArgumentException("Activity intent required.");
-        }
-        for (Listener l : mListeners) {
-            l.onStartActivityFromInCall(this, intent);
-        }
-    }
-
-    /**
      * Notifies this Connection that the {@link #getAudioState()} property has a new value.
      *
      * @param state The new call audio state.
diff --git a/telecomm/java/android/telecomm/ConnectionService.java b/telecomm/java/android/telecomm/ConnectionService.java
index 19cf622..2dc6910 100644
--- a/telecomm/java/android/telecomm/ConnectionService.java
+++ b/telecomm/java/android/telecomm/ConnectionService.java
@@ -463,12 +463,6 @@
         }
 
         @Override
-        public void onStartActivityFromInCall(Connection c, PendingIntent intent) {
-            String id = mIdByConnection.get(c);
-            mAdapter.startActivityFromInCall(id, intent);
-        }
-
-        @Override
         public void onConferenceableConnectionsChanged(
                 Connection connection, List<Connection> conferenceableConnections) {
             mAdapter.setConferenceableConnections(
@@ -834,24 +828,6 @@
      */
     public void onConference(Connection connection1, Connection connection2) {}
 
-    /**
-     * Notifies that a connection has been added to this connection service and sent to Telecomm.
-     *
-     * @param connection The connection which was added.
-     */
-    public void onConnectionAdded(Connection connection) {}
-
-    /**
-     * Notified that a connection has been removed from this connection service.
-     * <p>
-     * TODO: Deprecate this since we can listen to the Connection onDestroyed() to determine when
-     * it is destroyed. This then percolates down to the RemoteConference stuff, where we can also
-     * have a callback for one being added, but we don't need one for being destroyed.
-     *
-     * @param connection The connection which was removed.
-     */
-    public void onConnectionRemoved(Connection connection) {}
-
     public void onRemoteConferenceAdded(RemoteConference conference) {}
 
     /**
@@ -879,7 +855,6 @@
         mIdByConnection.put(connection, callId);
         connection.addConnectionListener(mConnectionListener);
         connection.setConnectionService(this);
-        onConnectionAdded(connection);
     }
 
     private void removeConnection(Connection connection) {
@@ -888,7 +863,6 @@
         connection.removeConnectionListener(mConnectionListener);
         mConnectionById.remove(mIdByConnection.get(connection));
         mIdByConnection.remove(connection);
-        onConnectionRemoved(connection);
         mAdapter.removeCall(id);
     }
 
diff --git a/telecomm/java/android/telecomm/ConnectionServiceAdapter.java b/telecomm/java/android/telecomm/ConnectionServiceAdapter.java
index cb63646..e3dc713 100644
--- a/telecomm/java/android/telecomm/ConnectionServiceAdapter.java
+++ b/telecomm/java/android/telecomm/ConnectionServiceAdapter.java
@@ -346,13 +346,4 @@
             }
         }
     }
-
-    void startActivityFromInCall(String callId, PendingIntent intent) {
-        for (IConnectionServiceAdapter adapter : mAdapters) {
-            try {
-                adapter.startActivityFromInCall(callId, intent);
-            } catch (RemoteException e) {
-            }
-        }
-    }
 }
diff --git a/telecomm/java/android/telecomm/ConnectionServiceAdapterServant.java b/telecomm/java/android/telecomm/ConnectionServiceAdapterServant.java
index 0e1c516..21e99db 100644
--- a/telecomm/java/android/telecomm/ConnectionServiceAdapterServant.java
+++ b/telecomm/java/android/telecomm/ConnectionServiceAdapterServant.java
@@ -57,8 +57,7 @@
     private static final int MSG_SET_STATUS_HINTS = 17;
     private static final int MSG_SET_HANDLE = 18;
     private static final int MSG_SET_CALLER_DISPLAY_NAME = 19;
-    private static final int MSG_START_ACTIVITY_FROM_IN_CALL = 20;
-    private static final int MSG_SET_CONFERENCEABLE_CONNECTIONS = 21;
+    private static final int MSG_SET_CONFERENCEABLE_CONNECTIONS = 20;
 
     private final IConnectionServiceAdapter mDelegate;
 
@@ -192,16 +191,6 @@
                     }
                     break;
                 }
-                case MSG_START_ACTIVITY_FROM_IN_CALL: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    try {
-                        mDelegate.startActivityFromInCall(
-                                (String) args.arg1, (PendingIntent) args.arg2);
-                    } finally {
-                        args.recycle();
-                    }
-                    break;
-                }
                 case MSG_SET_CONFERENCEABLE_CONNECTIONS: {
                     SomeArgs args = (SomeArgs) msg.obj;
                     try {
@@ -352,14 +341,6 @@
         }
 
         @Override
-        public final void startActivityFromInCall(String connectionId, PendingIntent intent) {
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = connectionId;
-            args.arg2 = intent;
-            mHandler.obtainMessage(MSG_START_ACTIVITY_FROM_IN_CALL, args).sendToTarget();
-        }
-
-        @Override
         public final void setConferenceableConnections(
                 String connectionId, List<String> conferenceableConnectionIds) {
             SomeArgs args = SomeArgs.obtain();
diff --git a/telecomm/java/android/telecomm/InCallService.java b/telecomm/java/android/telecomm/InCallService.java
index 62a90bc..51cd537 100644
--- a/telecomm/java/android/telecomm/InCallService.java
+++ b/telecomm/java/android/telecomm/InCallService.java
@@ -55,7 +55,6 @@
     private static final int MSG_SET_POST_DIAL_WAIT = 4;
     private static final int MSG_ON_AUDIO_STATE_CHANGED = 5;
     private static final int MSG_BRING_TO_FOREGROUND = 6;
-    private static final int MSG_START_ACTIVITY = 7;
 
     /** Default Handler used to consolidate binder method calls onto a single thread. */
     private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@@ -89,15 +88,6 @@
                 case MSG_BRING_TO_FOREGROUND:
                     mPhone.internalBringToForeground(msg.arg1 == 1);
                     break;
-                case MSG_START_ACTIVITY:
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    try {
-                        mPhone.internalStartActivity(
-                                (String) args.arg1, (PendingIntent) args.arg2);
-                    } finally {
-                        args.recycle();
-                    }
-                    break;
                 default:
                     break;
             }
@@ -143,14 +133,6 @@
         public void bringToForeground(boolean showDialpad) {
             mHandler.obtainMessage(MSG_BRING_TO_FOREGROUND, showDialpad ? 1 : 0, 0).sendToTarget();
         }
-
-        @Override
-        public void startActivity(String callId, PendingIntent intent) {
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = callId;
-            args.arg2 = intent;
-            mHandler.obtainMessage(MSG_START_ACTIVITY, args).sendToTarget();
-        }
     }
 
     private Phone mPhone;
diff --git a/telecomm/java/android/telecomm/Phone.java b/telecomm/java/android/telecomm/Phone.java
index d90d954..8831f8f 100644
--- a/telecomm/java/android/telecomm/Phone.java
+++ b/telecomm/java/android/telecomm/Phone.java
@@ -150,14 +150,6 @@
         fireBringToForeground(showDialpad);
     }
 
-    /** {@hide} */
-    final void internalStartActivity(String telecommId, PendingIntent intent) {
-        Call call = mCallByTelecommCallId.get(telecommId);
-        if (call != null) {
-            call.internalStartActivity(intent);
-        }
-    }
-
     /**
      * Called to destroy the phone and cleanup any lingering calls.
      * @hide
diff --git a/telecomm/java/android/telecomm/PhoneAccount.java b/telecomm/java/android/telecomm/PhoneAccount.java
index 5b46409..1d61a6e 100644
--- a/telecomm/java/android/telecomm/PhoneAccount.java
+++ b/telecomm/java/android/telecomm/PhoneAccount.java
@@ -23,7 +23,12 @@
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.TextUtils;
 
+import java.lang.String;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 import java.util.MissingResourceException;
 
 /**
@@ -77,6 +82,21 @@
      */
     public static final int CAPABILITY_VIDEO_CALLING = 0x8;
 
+    /**
+     * URI scheme for telephone number URIs.
+     */
+    public static final String SCHEME_TEL = "tel";
+
+    /**
+     * URI scheme for voicemail URIs.
+     */
+    public static final String SCHEME_VOICEMAIL = "voicemail";
+
+    /**
+     * URI scheme for SIP URIs.
+     */
+    public static final String SCHEME_SIP = "sip";
+
     private final PhoneAccountHandle mAccountHandle;
     private final Uri mHandle;
     private final String mSubscriptionNumber;
@@ -84,6 +104,7 @@
     private final int mIconResId;
     private final CharSequence mLabel;
     private final CharSequence mShortDescription;
+    private final List<String> mSupportedUriSchemes;
 
     public static class Builder {
         private PhoneAccountHandle mAccountHandle;
@@ -93,6 +114,7 @@
         private int mIconResId;
         private CharSequence mLabel;
         private CharSequence mShortDescription;
+        private List<String> mSupportedUriSchemes = new ArrayList<String>();
 
         public Builder() {}
 
@@ -131,7 +153,40 @@
             return this;
         }
 
+        /**
+         * Specifies an additional URI scheme supported by the {@link PhoneAccount}.
+         *
+         * @param uriScheme The URI scheme.
+         * @return The Builder.
+         */
+        public Builder withSupportedUriScheme(String uriScheme) {
+            if (!TextUtils.isEmpty(uriScheme) && !mSupportedUriSchemes.contains(uriScheme)) {
+                this.mSupportedUriSchemes.add(uriScheme);
+            }
+            return this;
+        }
+
+        /**
+         * Specifies additional URI schemes supported by the {@link PhoneAccount}.
+         *
+         * @param uriSchemes The URI schemes.
+         * @return The Builder.
+         */
+        public Builder withSupportedUriSchemes(List<String> uriSchemes) {
+            if (uriSchemes != null && !uriSchemes.isEmpty()) {
+                for (String uriScheme : uriSchemes) {
+                    withSupportedUriScheme(uriScheme);
+                }
+            }
+            return this;
+        }
+
         public PhoneAccount build() {
+            // If no supported URI schemes were defined, assume "tel" is supported.
+            if (mSupportedUriSchemes.isEmpty()) {
+                withSupportedUriScheme(SCHEME_TEL);
+            }
+
             return new PhoneAccount(
                     mAccountHandle,
                     mHandle,
@@ -139,7 +194,8 @@
                     mCapabilities,
                     mIconResId,
                     mLabel,
-                    mShortDescription);
+                    mShortDescription,
+                    mSupportedUriSchemes);
         }
     }
 
@@ -150,7 +206,8 @@
             int capabilities,
             int iconResId,
             CharSequence label,
-            CharSequence shortDescription) {
+            CharSequence shortDescription,
+            List<String> supportedUriSchemes) {
         mAccountHandle = account;
         mHandle = handle;
         mSubscriptionNumber = subscriptionNumber;
@@ -158,6 +215,7 @@
         mIconResId = iconResId;
         mLabel = label;
         mShortDescription = shortDescription;
+        mSupportedUriSchemes = Collections.unmodifiableList(supportedUriSchemes);
     }
 
     public static Builder builder() { return new Builder(); }
@@ -228,6 +286,36 @@
     }
 
     /**
+     * The URI schemes supported by this {@code PhoneAccount}.
+     *
+     * @return The URI schemes.
+     */
+    public List<String> getSupportedUriSchemes() {
+        return mSupportedUriSchemes;
+    }
+
+    /**
+     * Determines if the {@link PhoneAccount} supports calls to/from handles with a specified URI
+     * scheme.
+     *
+     * @param uriScheme The URI scheme to check.
+     * @return {@code True} if the {@code PhoneAccount} supports calls to/from handles with the
+     * specified URI scheme.
+     */
+    public boolean supportsUriScheme(String uriScheme) {
+        if (mSupportedUriSchemes == null || uriScheme == null) {
+            return false;
+        }
+
+        for (String scheme : mSupportedUriSchemes) {
+            if (scheme != null && scheme.equals(uriScheme)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
      * The icon resource ID for the icon of this {@code PhoneAccount}.
      *
      * @return A resource ID.
@@ -281,6 +369,7 @@
         out.writeInt(mIconResId);
         out.writeCharSequence(mLabel);
         out.writeCharSequence(mShortDescription);
+        out.writeList(mSupportedUriSchemes);
     }
 
     public static final Creator<PhoneAccount> CREATOR
@@ -297,6 +386,8 @@
     };
 
     private PhoneAccount(Parcel in) {
+        ClassLoader classLoader = PhoneAccount.class.getClassLoader();
+
         mAccountHandle = in.readParcelable(getClass().getClassLoader());
         mHandle = in.readParcelable(getClass().getClassLoader());
         mSubscriptionNumber = in.readString();
@@ -304,5 +395,9 @@
         mIconResId = in.readInt();
         mLabel = in.readCharSequence();
         mShortDescription = in.readCharSequence();
+
+        List<String> supportedUriSchemes = new ArrayList<>();
+        in.readList(supportedUriSchemes, classLoader);
+        mSupportedUriSchemes = Collections.unmodifiableList(supportedUriSchemes);
     }
 }
diff --git a/telecomm/java/android/telecomm/RemoteConnection.java b/telecomm/java/android/telecomm/RemoteConnection.java
index b7e4b2a..31afb4b 100644
--- a/telecomm/java/android/telecomm/RemoteConnection.java
+++ b/telecomm/java/android/telecomm/RemoteConnection.java
@@ -163,16 +163,6 @@
         public void onVideoStateChanged(RemoteConnection connection, int videoState) {}
 
         /**
-         * Indicates that this {@code RemoteConnection} is requesting that the in-call UI
-         * launch the specified activity.
-         *
-         * @param connection The {@code RemoteConnection} invoking this method.
-         * @param intent A {@link PendingIntent} that the {@code RemoteConnection} wishes to
-         *         have launched on its behalf.
-         */
-        public void onStartActivityFromInCall(RemoteConnection connection, PendingIntent intent) {}
-
-        /**
          * Indicates that this {@code RemoteConnection} has been destroyed. No further requests
          * should be made to the {@code RemoteConnection}, and references to it should be cleared.
          *
@@ -729,13 +719,6 @@
     }
 
     /** @hide */
-    void startActivityFromInCall(PendingIntent intent) {
-        for (Listener l : mListeners) {
-            l.onStartActivityFromInCall(this, intent);
-        }
-    }
-
-    /** @hide */
     void setConferenceableConnections(List<RemoteConnection> conferenceableConnections) {
         mConferenceableConnections.clear();
         mConferenceableConnections.addAll(conferenceableConnections);
diff --git a/telecomm/java/android/telecomm/RemoteConnectionService.java b/telecomm/java/android/telecomm/RemoteConnectionService.java
index 51722fe..0b6badb 100644
--- a/telecomm/java/android/telecomm/RemoteConnectionService.java
+++ b/telecomm/java/android/telecomm/RemoteConnectionService.java
@@ -261,12 +261,6 @@
         }
 
         @Override
-        public void startActivityFromInCall(String callId, PendingIntent intent) {
-            findConnectionForAction(callId, "startActivityFromInCall")
-                    .startActivityFromInCall(intent);
-        }
-
-        @Override
         public IBinder asBinder() {
             throw new UnsupportedOperationException();
         }
diff --git a/telecomm/java/android/telecomm/TelecommManager.java b/telecomm/java/android/telecomm/TelecommManager.java
index 2243288..071b719 100644
--- a/telecomm/java/android/telecomm/TelecommManager.java
+++ b/telecomm/java/android/telecomm/TelecommManager.java
@@ -258,8 +258,8 @@
 
     /**
      * Return the {@link PhoneAccount} which is the user-chosen default for making outgoing phone
-     * calls. This {@code PhoneAccount} will always be a member of the list which is returned from
-     * calling {@link #getEnabledPhoneAccounts()}.
+     * calls with a specified URI scheme. This {@code PhoneAccount} will always be a member of the
+     * list which is returned from calling {@link #getEnabledPhoneAccounts()}.
      * <p>
      * Apps must be prepared for this method to return {@code null}, indicating that there currently
      * exists no user-chosen default {@code PhoneAccount}. In this case, apps wishing to initiate a
@@ -272,11 +272,13 @@
      * {@code Intent} with no {@link TelecommManager#EXTRA_PHONE_ACCOUNT_HANDLE} is valid, and
      * subsequent steps in the phone call flow are responsible for presenting the user with an
      * affordance, if necessary, to choose a {@code PhoneAccount}.
+     *
+     * @param uriScheme The URI scheme.
      */
-    public PhoneAccountHandle getDefaultOutgoingPhoneAccount() {
+    public PhoneAccountHandle getDefaultOutgoingPhoneAccount(String uriScheme) {
         try {
             if (isServiceConnected()) {
-                return getTelecommService().getDefaultOutgoingPhoneAccount();
+                return getTelecommService().getDefaultOutgoingPhoneAccount(uriScheme);
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelecommService#getDefaultOutgoingPhoneAccount", e);
@@ -366,6 +368,29 @@
     }
 
     /**
+     * Returns a list of {@link PhoneAccountHandle}s which can be used to make and receive phone
+     * calls which support the specified URI scheme.
+     * <P>
+     * For example, invoking with {@code "tel"} will find all {@link PhoneAccountHandle}s which
+     * support telephone calls (e.g. URIs such as {@code tel:555-555-1212}).  Invoking with
+     * {@code "sip"} will find all {@link PhoneAccountHandle}s which support SIP calls (e.g. URIs
+     * such as {@code sip:example@sipexample.com}).
+     *
+     * @param uriScheme The URI scheme.
+     * @return A list of {@code PhoneAccountHandle} objects supporting the URI scheme.
+     */
+    public List<PhoneAccountHandle> getPhoneAccountsSupportingScheme(String uriScheme) {
+        try {
+            if (isServiceConnected()) {
+                return getTelecommService().getPhoneAccountsSupportingScheme(uriScheme);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelecommService#getPhoneAccountsSupportingScheme", e);
+        }
+        return new ArrayList<>();
+    }
+
+    /**
      * Determine whether the device has more than one account registered and enabled.
      *
      * @return {@code true} if the device has more than one account registered and enabled and
diff --git a/telecomm/java/com/android/internal/telecomm/IConnectionServiceAdapter.aidl b/telecomm/java/com/android/internal/telecomm/IConnectionServiceAdapter.aidl
index ef1769f..610178e 100644
--- a/telecomm/java/com/android/internal/telecomm/IConnectionServiceAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecomm/IConnectionServiceAdapter.aidl
@@ -76,6 +76,4 @@
     void setCallerDisplayName(String callId, String callerDisplayName, int presentation);
 
     void setConferenceableConnections(String callId, in List<String> conferenceableCallIds);
-
-    void startActivityFromInCall(String callId, in PendingIntent intent);
 }
diff --git a/telecomm/java/com/android/internal/telecomm/IInCallService.aidl b/telecomm/java/com/android/internal/telecomm/IInCallService.aidl
index 5d4992f..23dbaf4 100644
--- a/telecomm/java/com/android/internal/telecomm/IInCallService.aidl
+++ b/telecomm/java/com/android/internal/telecomm/IInCallService.aidl
@@ -43,6 +43,4 @@
     void onAudioStateChanged(in AudioState audioState);
 
     void bringToForeground(boolean showDialpad);
-
-    void startActivity(String callId, in PendingIntent intent);
 }
diff --git a/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
index 131307a..a6ab3ac 100644
--- a/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
+++ b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
@@ -37,7 +37,7 @@
     /**
      * @see TelecommServiceImpl#getDefaultOutgoingPhoneAccount
      */
-    PhoneAccountHandle getDefaultOutgoingPhoneAccount();
+    PhoneAccountHandle getDefaultOutgoingPhoneAccount(in String uriScheme);
 
     /**
      * @see TelecommServiceImpl#setDefaultOutgoingPhoneAccount
@@ -50,7 +50,12 @@
     List<PhoneAccountHandle> getOutgoingPhoneAccounts();
 
     /**
-     * @see TelecommServiceImpl#getPhoneAccount
+     * @see TelecommManager#getPhoneAccountsSupportingScheme
+     */
+    List<PhoneAccountHandle> getPhoneAccountsSupportingScheme(in String uriScheme);
+
+    /**
+     * @see TelecommManager#getPhoneAccount
      */
     PhoneAccount getPhoneAccount(in PhoneAccountHandle account);
 
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 350c27e..34da1c9 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -221,18 +221,39 @@
 
     private final Handler mHandler;
 
+    /**
+     * Create a PhoneStateListener for the Phone with the default subscription.
+     * This class requires Looper.myLooper() not return null. To supply your
+     * own non-null looper use PhoneStateListener(Looper looper) below.
+     */
     public PhoneStateListener() {
         this(SubscriptionManager.DEFAULT_SUB_ID, Looper.myLooper());
     }
 
     /**
+     * Create a PhoneStateListener for the Phone with the default subscription
+     * using a particular non-null Looper.
+     * @hide
+     */
+    public PhoneStateListener(Looper looper) {
+        this(SubscriptionManager.DEFAULT_SUB_ID, looper);
+    }
+
+    /**
+     * Create a PhoneStateListener for the Phone using the specified subscription.
+     * This class requires Looper.myLooper() not return null. To supply your
+     * own non-null Looper use PhoneStateListener(long subId, Looper looper) below.
      * @hide
      */
     public PhoneStateListener(long subId) {
         this(subId, Looper.myLooper());
     }
 
-    /** @hide */
+    /**
+     * Create a PhoneStateListener for the Phone using the specified subscription
+     * and non-null Looper.
+     * @hide
+     */
     public PhoneStateListener(long subId, Looper looper) {
         if (DBG) log("ctor: subId=" + subId + " looper=" + looper);
         mSubId = subId;
diff --git a/telephony/java/android/telephony/SubInfoRecord.java b/telephony/java/android/telephony/SubInfoRecord.java
index ced8e2f..55781fa 100644
--- a/telephony/java/android/telephony/SubInfoRecord.java
+++ b/telephony/java/android/telephony/SubInfoRecord.java
@@ -33,34 +33,33 @@
     public int mNameSource;
     public int mColor;
     public String mNumber;
-    public int mDispalyNumberFormat;
+    public int mDisplayNumberFormat;
     public int mDataRoaming;
     public int[] mSimIconRes;
 
     public SubInfoRecord() {
-        this.mSubId = -1;
+        this.mSubId = SubscriptionManager.INVALID_SUB_ID;
         this.mIccId = "";
-        this.mSlotId = -1;
+        this.mSlotId = SubscriptionManager.INVALID_SLOT_ID;
         this.mDisplayName = "";
         this.mNameSource = 0;
         this.mColor = 0;
         this.mNumber = "";
-        this.mDispalyNumberFormat = 0;
+        this.mDisplayNumberFormat = 0;
         this.mDataRoaming = 0;
         this.mSimIconRes = new int[2];
     }
 
-
-    public SubInfoRecord(long subId, String iccId, int slotId, String displayname, int nameSource,
-            int mColor, String mNumber, int displayFormat, int roaming, int[] iconRes) {
+    public SubInfoRecord(long subId, String iccId, int slotId, String displayName,
+            int nameSource, int mColor, String mNumber, int displayFormat, int roaming, int[] iconRes) {
         this.mSubId = subId;
         this.mIccId = iccId;
         this.mSlotId = slotId;
-        this.mDisplayName = displayname;
+        this.mDisplayName = displayName;
         this.mNameSource = nameSource;
         this.mColor = mColor;
         this.mNumber = mNumber;
-        this.mDispalyNumberFormat = displayFormat;
+        this.mDisplayNumberFormat = displayFormat;
         this.mDataRoaming = roaming;
         this.mSimIconRes = iconRes;
     }
@@ -74,13 +73,13 @@
             int mNameSource = source.readInt();
             int mColor = source.readInt();
             String mNumber = source.readString();
-            int mDispalyNumberFormat = source.readInt();
+            int mDisplayNumberFormat = source.readInt();
             int mDataRoaming = source.readInt();
             int[] iconRes = new int[2];
             source.readIntArray(iconRes);
 
             return new SubInfoRecord(mSubId, mIccId, mSlotId, mDisplayName, mNameSource, mColor, mNumber,
-                mDispalyNumberFormat, mDataRoaming, iconRes);
+                mDisplayNumberFormat, mDataRoaming, iconRes);
         }
 
         public SubInfoRecord[] newArray(int size) {
@@ -96,7 +95,7 @@
         dest.writeInt(mNameSource);
         dest.writeInt(mColor);
         dest.writeString(mNumber);
-        dest.writeInt(mDispalyNumberFormat);
+        dest.writeInt(mDisplayNumberFormat);
         dest.writeInt(mDataRoaming);
         dest.writeIntArray(mSimIconRes);
     }
@@ -109,7 +108,7 @@
         return "{mSubId=" + mSubId + ", mIccId=" + mIccId + " mSlotId=" + mSlotId
                 + " mDisplayName=" + mDisplayName + " mNameSource=" + mNameSource
                 + " mColor=" + mColor + " mNumber=" + mNumber
-                + " mDispalyNumberFormat=" + mDispalyNumberFormat + " mDataRoaming=" + mDataRoaming
+                + " mDisplayNumberFormat=" + mDisplayNumberFormat + " mDataRoaming=" + mDataRoaming
                 + " mSimIconRes=" + mSimIconRes + "}";
     }
 }
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 79e9fd5..2bb2404 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1,31 +1,24 @@
 /*
-* Copyright (C) 2011-2014 MediaTek Inc.
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-*      http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 package android.telephony;
 
-import static android.Manifest.permission.READ_PHONE_STATE;
-
-import android.app.ActivityManagerNative;
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.Context;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
 import android.content.Intent;
-import android.database.Cursor;
-import android.os.UserHandle;
 import android.net.Uri;
 import android.provider.BaseColumns;
 import android.telephony.Rlog;
@@ -34,123 +27,181 @@
 
 import com.android.internal.telephony.ISub;
 import com.android.internal.telephony.PhoneConstants;
-import com.android.internal.telephony.TelephonyIntents;
-
-import java.util.ArrayList;
 import java.util.List;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map.Entry;
 
 /**
- *@hide
+ * SubscriptionManager is the application interface to SubscriptionController
+ * and provides information about the current Telephony Subscriptions.
+ *
+ * @hide
  */
 public class SubscriptionManager implements BaseColumns {
     private static final String LOG_TAG = "SUB";
     private static final boolean DBG = true;
     private static final boolean VDBG = false;
 
+    // An invalid phone identifier
+    /** @hide */
+    public static final int INVALID_PHONE_ID = -1000;
+
+    // Indicates the caller wants the default phone id.
+    /** @hide */
+    public static final int DEFAULT_PHONE_ID = Integer.MAX_VALUE;
+
+    // An invalid slot identifier
+    /** @hide */
+    public static final int INVALID_SLOT_ID = -1000;
+
+    // Indicates the caller wants the default slot id.
+    /** @hide */
+    public static final int DEFAULT_SLOT_ID = Integer.MAX_VALUE;
+
     // An invalid subscription identifier
-    public static final long INVALID_SUB_ID = Long.MAX_VALUE;
+    /** @hide */
+    public static final long INVALID_SUB_ID = -1000;
 
-    // The default subscription identifier
-    public static final long DEFAULT_SUB_ID = Long.MAX_VALUE - 1;
+    // Indicates the user should be asked which sub to use.
+    /** @hide */
+    public static final long ASK_USER_SUB_ID = -1001;
 
+    // Indicates the caller wants the default sub id.
+    /** @hide */
+    public static final long DEFAULT_SUB_ID = Long.MAX_VALUE;
+
+    /** @hide */
     public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo");
 
+    /** @hide */
     public static final int DEFAULT_INT_VALUE = -100;
 
+    /** @hide */
     public static final String DEFAULT_STRING_VALUE = "N/A";
 
+    /** @hide */
     public static final int EXTRA_VALUE_NEW_SIM = 1;
+
+    /** @hide */
     public static final int EXTRA_VALUE_REMOVE_SIM = 2;
+    /** @hide */
     public static final int EXTRA_VALUE_REPOSITION_SIM = 3;
+    /** @hide */
     public static final int EXTRA_VALUE_NOCHANGE = 4;
 
+    /** @hide */
     public static final String INTENT_KEY_DETECT_STATUS = "simDetectStatus";
+    /** @hide */
     public static final String INTENT_KEY_SIM_COUNT = "simCount";
+    /** @hide */
     public static final String INTENT_KEY_NEW_SIM_SLOT = "newSIMSlot";
+    /** @hide */
     public static final String INTENT_KEY_NEW_SIM_STATUS = "newSIMStatus";
 
     /**
      * The ICC ID of a SIM.
      * <P>Type: TEXT (String)</P>
      */
+    /** @hide */
     public static final String ICC_ID = "icc_id";
 
     /**
      * <P>Type: INTEGER (int)</P>
      */
+    /** @hide */
     public static final String SIM_ID = "sim_id";
-
+    /** @hide */
     public static final int SIM_NOT_INSERTED = -1;
 
     /**
      * The display name of a SIM.
      * <P>Type: TEXT (String)</P>
      */
+    /** @hide */
     public static final String DISPLAY_NAME = "display_name";
 
+    /** @hide */
     public static final int DEFAULT_NAME_RES = com.android.internal.R.string.unknownName;
 
     /**
      * The display name source of a SIM.
      * <P>Type: INT (int)</P>
      */
+    /** @hide */
     public static final String NAME_SOURCE = "name_source";
 
-    public static final int DEFAULT_SOURCE = 0;
+    /** @hide */
+    public static final int NAME_SOURCE_UNDEFINDED = -1;
 
-    public static final int SIM_SOURCE = 1;
+    /** @hide */
+    public static final int NAME_SOURCE_DEFAULT_SOURCE = 0;
 
-    public static final int USER_INPUT = 2;
+    /** @hide */
+    public static final int NAME_SOURCE_SIM_SOURCE = 1;
+
+    /** @hide */
+    public static final int NAME_SOURCE_USER_INPUT = 2;
 
     /**
      * The color of a SIM.
      * <P>Type: INTEGER (int)</P>
      */
+    /** @hide */
     public static final String COLOR = "color";
 
+    /** @hide */
     public static final int COLOR_1 = 0;
 
+    /** @hide */
     public static final int COLOR_2 = 1;
 
+    /** @hide */
     public static final int COLOR_3 = 2;
 
+    /** @hide */
     public static final int COLOR_4 = 3;
 
+    /** @hide */
     public static final int COLOR_DEFAULT = COLOR_1;
 
     /**
      * The phone number of a SIM.
      * <P>Type: TEXT (String)</P>
      */
+    /** @hide */
     public static final String NUMBER = "number";
 
     /**
      * The number display format of a SIM.
      * <P>Type: INTEGER (int)</P>
      */
+    /** @hide */
     public static final String DISPLAY_NUMBER_FORMAT = "display_number_format";
 
-    public static final int DISPALY_NUMBER_NONE = 0;
+    /** @hide */
+    public static final int DISPLAY_NUMBER_NONE = 0;
 
+    /** @hide */
     public static final int DISPLAY_NUMBER_FIRST = 1;
 
+    /** @hide */
     public static final int DISPLAY_NUMBER_LAST = 2;
 
+    /** @hide */
     public static final int DISLPAY_NUMBER_DEFAULT = DISPLAY_NUMBER_FIRST;
 
     /**
      * Permission for data roaming of a SIM.
      * <P>Type: INTEGER (int)</P>
      */
+    /** @hide */
     public static final String DATA_ROAMING = "data_roaming";
 
+    /** @hide */
     public static final int DATA_ROAMING_ENABLE = 1;
 
+    /** @hide */
     public static final int DATA_ROAMING_DISABLE = 0;
 
+    /** @hide */
     public static final int DATA_ROAMING_DEFAULT = DATA_ROAMING_DISABLE;
 
     private static final int RES_TYPE_BACKGROUND_DARK = 0;
@@ -159,24 +210,29 @@
 
     private static final int[] sSimBackgroundDarkRes = setSimResource(RES_TYPE_BACKGROUND_DARK);
 
-    private static final int[] sSimBackgroundLightRes = setSimResource(RES_TYPE_BACKGROUND_LIGHT);
+    /**
+     * Broadcast Action: The user has changed one of the default subs related to
+     * data, phone calls, or sms</p>
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String SUB_DEFAULT_CHANGED_ACTION =
+        "android.intent.action.SUB_DEFAULT_CHANGED";
 
-    private static HashMap<Integer, Long> mSimInfo = new HashMap<Integer, Long>();
-
+    /** @hide */
     public SubscriptionManager() {
         if (DBG) logd("SubscriptionManager created");
     }
 
     /**
      * Get the SubInfoRecord according to an index
-     * @param context Context provided by caller
      * @param subId The unique SubInfoRecord index in database
      * @return SubInfoRecord, maybe null
+     * @hide
      */
-    public static SubInfoRecord getSubInfoUsingSubId(Context context, long subId) {
-        if (VDBG) logd("[getSubInfoUsingSubIdx]+ subId:" + subId);
-        if (subId <= 0) {
-            if (VDBG) logd("[getSubInfoUsingSubIdx]- subId <= 0");
+    public static SubInfoRecord getSubInfoUsingSubId(long subId) {
+        if (!isValidSubId(subId)) {
+            logd("[getSubInfoUsingSubIdx]- invalid subId");
             return null;
         }
 
@@ -197,11 +253,11 @@
 
     /**
      * Get the SubInfoRecord according to an IccId
-     * @param context Context provided by caller
      * @param iccId the IccId of SIM card
      * @return SubInfoRecord, maybe null
+     * @hide
      */
-    public static List<SubInfoRecord> getSubInfoUsingIccId(Context context, String iccId) {
+    public static List<SubInfoRecord> getSubInfoUsingIccId(String iccId) {
         if (VDBG) logd("[getSubInfoUsingIccId]+ iccId=" + iccId);
         if (iccId == null) {
             logd("[getSubInfoUsingIccId]- null iccid");
@@ -224,14 +280,14 @@
 
     /**
      * Get the SubInfoRecord according to slotId
-     * @param context Context provided by caller
      * @param slotId the slot which the SIM is inserted
      * @return SubInfoRecord, maybe null
+     * @hide
      */
-    public static List<SubInfoRecord> getSubInfoUsingSlotId(Context context, int slotId) {
-        if (VDBG) logd("[getSubInfoUsingSlotId]- slotId=" + slotId);
-        if (slotId < 0) {
-            logd("[getSubInfoUsingSlotId]- return null, slotId < 0");
+    public static List<SubInfoRecord> getSubInfoUsingSlotId(int slotId) {
+        // FIXME: Consider never returning null
+        if (!isValidSlotId(slotId)) {
+            logd("[getSubInfoUsingSlotId]- invalid slotId");
             return null;
         }
 
@@ -251,10 +307,10 @@
 
     /**
      * Get all the SubInfoRecord(s) in subinfo database
-     * @param context Context provided by caller
      * @return Array list of all SubInfoRecords in database, include thsoe that were inserted before
+     * @hide
      */
-    public static List<SubInfoRecord> getAllSubInfoList(Context context) {
+    public static List<SubInfoRecord> getAllSubInfoList() {
         if (VDBG) logd("[getAllSubInfoList]+");
 
         List<SubInfoRecord> result = null;
@@ -273,18 +329,16 @@
 
     /**
      * Get the SubInfoRecord(s) of the currently inserted SIM(s)
-     * @param context Context provided by caller
      * @return Array list of currently inserted SubInfoRecord(s)
+     * @hide
      */
-    public static List<SubInfoRecord> getActivatedSubInfoList(Context context) {
-        if (VDBG) logd("[getActivatedSubInfoList]+");
-
+    public static List<SubInfoRecord> getActiveSubInfoList() {
         List<SubInfoRecord> result = null;
 
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
             if (iSub != null) {
-                result = iSub.getActivatedSubInfoList();
+                result = iSub.getActiveSubInfoList();
             }
         } catch (RemoteException ex) {
             // ignore it
@@ -295,10 +349,10 @@
 
     /**
      * Get the SUB count of all SUB(s) in subinfo database
-     * @param context Context provided by caller
      * @return all SIM count in database, include what was inserted before
+     * @hide
      */
-    public static int getAllSubInfoCount(Context context) {
+    public static int getAllSubInfoCount() {
         if (VDBG) logd("[getAllSubInfoCount]+");
 
         int result = 0;
@@ -316,17 +370,40 @@
     }
 
     /**
+     * Get the count of active SUB(s)
+     * @return active SIM count
+     * @hide
+     */
+    public static int getActiveSubInfoCount() {
+        int result = 0;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                result = iSub.getActiveSubInfoCount();
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return result;
+    }
+
+    /**
      * Add a new SubInfoRecord to subinfo database if needed
-     * @param context Context provided by caller
      * @param iccId the IccId of the SIM card
      * @param slotId the slot which the SIM is inserted
      * @return the URL of the newly created row or the updated row
+     * @hide
      */
-    public static Uri addSubInfoRecord(Context context, String iccId, int slotId) {
+    public static Uri addSubInfoRecord(String iccId, int slotId) {
         if (VDBG) logd("[addSubInfoRecord]+ iccId:" + iccId + " slotId:" + slotId);
         if (iccId == null) {
             logd("[addSubInfoRecord]- null iccId");
         }
+        if (!isValidSlotId(slotId)) {
+            logd("[addSubInfoRecord]- invalid slotId");
+        }
 
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
@@ -345,15 +422,15 @@
 
     /**
      * Set SIM color by simInfo index
-     * @param context Context provided by caller
      * @param color the color of the SIM
      * @param subId the unique SubInfoRecord index in database
      * @return the number of records updated
+     * @hide
      */
-    public static int setColor(Context context, int color, long subId) {
+    public static int setColor(int color, long subId) {
         if (VDBG) logd("[setColor]+ color:" + color + " subId:" + subId);
         int size = sSimBackgroundDarkRes.length;
-        if (subId <= 0 || color < 0 || color >= size) {
+        if (!isValidSubId(subId) || color < 0 || color >= size) {
             logd("[setColor]- fail");
             return -1;
         }
@@ -375,26 +452,30 @@
 
     /**
      * Set display name by simInfo index
-     * @param context Context provided by caller
      * @param displayName the display name of SIM card
      * @param subId the unique SubInfoRecord index in database
      * @return the number of records updated
+     * @hide
      */
-    public static int setDisplayName(Context context, String displayName, long subId) {
-        return setDisplayName(context, displayName, subId, -1);
+    public static int setDisplayName(String displayName, long subId) {
+        return setDisplayName(displayName, subId, NAME_SOURCE_UNDEFINDED);
     }
 
     /**
      * Set display name by simInfo index with name source
-     * @param context Context provided by caller
      * @param displayName the display name of SIM card
      * @param subId the unique SubInfoRecord index in database
-     * @param nameSource, 0: DEFAULT_SOURCE, 1: SIM_SOURCE, 2: USER_INPUT
-     * @return the number of records updated
+     * @param nameSource 0: NAME_SOURCE_DEFAULT_SOURCE, 1: NAME_SOURCE_SIM_SOURCE,
+     *                   2: NAME_SOURCE_USER_INPUT, -1 NAME_SOURCE_UNDEFINED
+     * @return the number of records updated or -1 if invalid subId
+     * @hide
      */
-    public static int setDisplayName(Context context, String displayName, long subId, long nameSource) {
-        if (VDBG) logd("[setDisplayName]+  displayName:" + displayName + " subId:" + subId + " nameSource:" + nameSource);
-        if (subId <= 0) {
+    public static int setDisplayName(String displayName, long subId, long nameSource) {
+        if (VDBG) {
+            logd("[setDisplayName]+  displayName:" + displayName + " subId:" + subId
+                    + " nameSource:" + nameSource);
+        }
+        if (!isValidSubId(subId)) {
             logd("[setDisplayName]- fail");
             return -1;
         }
@@ -416,15 +497,14 @@
 
     /**
      * Set phone number by subId
-     * @param context Context provided by caller
      * @param number the phone number of the SIM
      * @param subId the unique SubInfoRecord index in database
      * @return the number of records updated
+     * @hide
      */
-    public static int setDispalyNumber(Context context, String number, long subId) {
-        if (VDBG) logd("[setDispalyNumber]+ number:" + number + " subId:" + subId);
-        if (number == null || subId <= 0) {
-            logd("[setDispalyNumber]- fail");
+    public static int setDisplayNumber(String number, long subId) {
+        if (number == null || !isValidSubId(subId)) {
+            logd("[setDisplayNumber]- fail");
             return -1;
         }
 
@@ -433,7 +513,7 @@
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
             if (iSub != null) {
-                result = iSub.setDispalyNumber(number, subId);
+                result = iSub.setDisplayNumber(number, subId);
             }
         } catch (RemoteException ex) {
             // ignore it
@@ -445,14 +525,14 @@
 
     /**
      * Set number display format. 0: none, 1: the first four digits, 2: the last four digits
-     * @param context Context provided by caller
      * @param format the display format of phone number
      * @param subId the unique SubInfoRecord index in database
      * @return the number of records updated
+     * @hide
      */
-    public static int setDisplayNumberFormat(Context context, int format, long subId) {
+    public static int setDisplayNumberFormat(int format, long subId) {
         if (VDBG) logd("[setDisplayNumberFormat]+ format:" + format + " subId:" + subId);
-        if (format < 0 || subId <= 0) {
+        if (format < 0 || !isValidSubId(subId)) {
             logd("[setDisplayNumberFormat]- fail, return -1");
             return -1;
         }
@@ -474,14 +554,14 @@
 
     /**
      * Set data roaming by simInfo index
-     * @param context Context provided by caller
      * @param roaming 0:Don't allow data when roaming, 1:Allow data when roaming
      * @param subId the unique SubInfoRecord index in database
      * @return the number of records updated
+     * @hide
      */
-    public static int setDataRoaming(Context context, int roaming, long subId) {
+    public static int setDataRoaming(int roaming, long subId) {
         if (VDBG) logd("[setDataRoaming]+ roaming:" + roaming + " subId:" + subId);
-        if (roaming < 0 || subId <= 0) {
+        if (roaming < 0 || !isValidSubId(subId)) {
             logd("[setDataRoaming]- fail");
             return -1;
         }
@@ -500,10 +580,13 @@
         return result;
     }
 
+    /** @hide */
     public static int getSlotId(long subId) {
-        if (VDBG) logd("[getSlotId]+ subId:" + subId);
+        if (!isValidSubId(subId)) {
+            logd("[getSlotId]- fail");
+        }
 
-        int result = 0;
+        int result = INVALID_SLOT_ID;
 
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
@@ -518,8 +601,12 @@
 
     }
 
+    /** @hide */
     public static long[] getSubId(int slotId) {
-        if (VDBG) logd("[getSubId]+ slotId:" + slotId);
+        if (!isValidSlotId(slotId)) {
+            logd("[getSubId]- fail");
+            return null;
+        }
 
         long[] subId = null;
 
@@ -535,10 +622,14 @@
         return subId;
     }
 
+    /** @hide */
     public static int getPhoneId(long subId) {
-        if (VDBG) logd("[getPhoneId]+ subId=" + subId);
+        if (!isValidSubId(subId)) {
+            logd("[getPhoneId]- fail");
+            return INVALID_PHONE_ID;
+        }
 
-        int result = 0;
+        int result = INVALID_PHONE_ID;
 
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
@@ -549,7 +640,7 @@
             // ignore it
         }
 
-        if (VDBG) logd("[getPhoneId]- phonId=" + result);
+        if (VDBG) logd("[getPhoneId]- phoneId=" + result);
         return result;
 
     }
@@ -583,23 +674,14 @@
         Rlog.d(LOG_TAG, "[SubManager] " + msg);
     }
 
-    public static long normalizeSubId(long subId) {
-        long retVal = (subId == DEFAULT_SUB_ID) ? getDefaultSubId() : subId;
-        Rlog.d(LOG_TAG, "[SubManager] normalizeSubId subId=" + retVal);
-        return retVal;
-    }
-
-    public static boolean validSubId(long subId) {
-        return (subId != DEFAULT_SUB_ID) && (subId != -1);
-    }
-
     /**
      * @return the "system" defaultSubId on a voice capable device this
      * will be getDefaultVoiceSubId() and on a data only device it will be
      * getDefaultDataSubId().
+     * @hide
      */
     public static long getDefaultSubId() {
-        long subId = 1;
+        long subId = INVALID_SUB_ID;
 
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
@@ -614,8 +696,9 @@
         return subId;
     }
 
+    /** @hide */
     public static long getDefaultVoiceSubId() {
-        long subId = 1;
+        long subId = INVALID_SUB_ID;
 
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
@@ -626,10 +709,11 @@
             // ignore it
         }
 
-        if (VDBG) logd("getDefaultSubId, sub id = " + subId);
+        if (VDBG) logd("getDefaultVoiceSubId, sub id = " + subId);
         return subId;
     }
 
+    /** @hide */
     public static void setDefaultVoiceSubId(long subId) {
         if (VDBG) logd("setDefaultVoiceSubId sub id = " + subId);
         try {
@@ -638,34 +722,78 @@
                 iSub.setDefaultVoiceSubId(subId);
             }
         } catch (RemoteException ex) {
-         // ignore it
+            // ignore it
         }
     }
 
-    public static long getPreferredSmsSubId() {
-        // FIXME add framework support to get the preferred sub
-        return getDefaultSubId();
+    /** @hide */
+    public static SubInfoRecord getDefaultVoiceSubInfo() {
+        return getSubInfoUsingSubId(getDefaultVoiceSubId());
     }
 
-    public static long getPreferredDataSubId() {
-        // FIXME add framework support to get the preferred sub
-        return getDefaultSubId();
+    /** @hide */
+    public static int getDefaultVoicePhoneId() {
+        return getPhoneId(getDefaultVoiceSubId());
     }
 
-    public static long getDefaultDataSubId() {
+    /** @hide */
+    public static long getDefaultSmsSubId() {
+        long subId = INVALID_SUB_ID;
 
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
             if (iSub != null) {
-                return iSub.getDefaultDataSubId();
-            } else {
-                return -1;
+                subId = iSub.getDefaultSmsSubId();
             }
         } catch (RemoteException ex) {
-            return -1;
+            // ignore it
+        }
+
+        if (VDBG) logd("getDefaultSmsSubId, sub id = " + subId);
+        return subId;
+    }
+
+    /** @hide */
+    public static void setDefaultSmsSubId(long subId) {
+        if (VDBG) logd("setDefaultSmsSubId sub id = " + subId);
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                iSub.setDefaultSmsSubId(subId);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
         }
     }
 
+    /** @hide */
+    public static SubInfoRecord getDefaultSmsSubInfo() {
+        return getSubInfoUsingSubId(getDefaultSmsSubId());
+    }
+
+    /** @hide */
+    public static int getDefaultSmsPhoneId() {
+        return getPhoneId(getDefaultSmsSubId());
+    }
+
+    /** @hide */
+    public static long getDefaultDataSubId() {
+        long subId = INVALID_SUB_ID;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                subId = iSub.getDefaultDataSubId();
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        if (VDBG) logd("getDefaultDataSubId, sub id = " + subId);
+        return subId;
+    }
+
+    /** @hide */
     public static void setDefaultDataSubId(long subId) {
         if (VDBG) logd("setDataSubscription sub id = " + subId);
         try {
@@ -674,14 +802,22 @@
                 iSub.setDefaultDataSubId(subId);
             }
         } catch (RemoteException ex) {
-         // ignore it
+            // ignore it
         }
     }
 
-    public static void clearSubInfo()
-    {
-        if (VDBG) logd("[clearSubInfo]+");
+    /** @hide */
+    public static SubInfoRecord getDefaultDataSubInfo() {
+        return getSubInfoUsingSubId(getDefaultDataSubId());
+    }
 
+    /** @hide */
+    public static int getDefaultDataPhoneId() {
+        return getPhoneId(getDefaultDataSubId());
+    }
+
+    /** @hide */
+    public static void clearSubInfo() {
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
             if (iSub != null) {
@@ -694,19 +830,97 @@
         return;
     }
 
+    //FIXME this is vulnerable to race conditions
+    /** @hide */
+    public static boolean allDefaultsSelected() {
+        if (getDefaultDataSubId() == INVALID_SUB_ID) {
+            return false;
+        }
+        if (getDefaultSmsSubId() == INVALID_SUB_ID) {
+            return false;
+        }
+        if (getDefaultVoiceSubId() == INVALID_SUB_ID) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * If a default is set to subscription which is not active, this will reset that default back to
+     * INVALID_SUB_ID.
+     * @hide
+     */
+    public static void clearDefaultsForInactiveSubIds() {
+        if (VDBG) logd("clearDefaultsForInactiveSubIds");
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                iSub.clearDefaultsForInactiveSubIds();
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+    }
+
+    /** @hide */
+    public static boolean isValidSubId(long subId) {
+        return subId > INVALID_SUB_ID ;
+    }
+
+    /** @hide */
+    public static boolean isValidSlotId(int slotId) {
+        return slotId > INVALID_SLOT_ID && slotId < TelephonyManager.getDefault().getSimCount();
+    }
+
+    /** @hide */
+    public static boolean isValidPhoneId(int phoneId) {
+        return phoneId > INVALID_PHONE_ID
+                && phoneId < TelephonyManager.getDefault().getPhoneCount();
+    }
+
+    /** @hide */
     public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId) {
-        long [] subId = SubscriptionManager.getSubId(phoneId);
-        if ((subId != null) && (subId.length >= 1)) {
-            putPhoneIdAndSubIdExtra(intent, phoneId, subId[0]);
+        long[] subIds = SubscriptionManager.getSubId(phoneId);
+        if (subIds != null && subIds.length > 0) {
+            putPhoneIdAndSubIdExtra(intent, phoneId, subIds[0]);
         } else {
             logd("putPhoneIdAndSubIdExtra: no valid subs");
         }
     }
 
+    /** @hide */
     public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId, long subId) {
         if (VDBG) logd("putPhoneIdAndSubIdExtra: phoneId=" + phoneId + " subId=" + subId);
-        intent.putExtra(PhoneConstants.SLOT_KEY, phoneId); //FIXME: RENAME TO PHONE_ID_KEY ??
         intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
+        intent.putExtra(PhoneConstants.PHONE_KEY, phoneId);
+        //FIXME this is using phoneId and slotId interchangeably
+        //Eventually, this should be removed as it is not the slot id
+        intent.putExtra(PhoneConstants.SLOT_KEY, phoneId);
+    }
+
+    /**
+     * @return the list of subId's that are active,
+     *         is never null but the length maybe 0.
+     * @hide
+     */
+    public static long[] getActiveSubIdList() {
+        long[] subId = null;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                subId = iSub.getActiveSubIdList();
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        if (subId == null) {
+            subId = new long[0];
+        }
+
+        return subId;
+
     }
 }
 
diff --git a/telephony/java/com/android/internal/telephony/IMms.aidl b/telephony/java/com/android/internal/telephony/IMms.aidl
index 2aeb42f..63b7a53 100644
--- a/telephony/java/com/android/internal/telephony/IMms.aidl
+++ b/telephony/java/com/android/internal/telephony/IMms.aidl
@@ -30,7 +30,8 @@
      *
      * @param subId the SIM id
      * @param callingPkg the package name of the calling app
-     * @param pdu the MMS message encoded in standard MMS PDU format
+     * @param contentUri the content uri from which to read MMS message encoded in standard MMS
+     *  PDU format
      * @param locationUrl the optional location url for where this message should be sent to
      * @param configOverrides the carrier-specific messaging configuration values to override for
      *  sending the message. See {@link android.telephony.MessagingConfigurationManager} for the
@@ -38,8 +39,8 @@
      * @param sentIntent if not NULL this <code>PendingIntent</code> is
      *  broadcast when the message is successfully sent, or failed
      */
-    void sendMessage(long subId, String callingPkg, in byte[] pdu, String locationUrl,
-            in ContentValues configOverrides, in PendingIntent sentIntent);
+    void sendMessage(long subId, String callingPkg, in Uri contentUri,
+            String locationUrl, in ContentValues configOverrides, in PendingIntent sentIntent);
 
     /**
      * Download an MMS message using known location and transaction id
@@ -48,6 +49,7 @@
      * @param callingPkg the package name of the calling app
      * @param locationUrl the location URL of the MMS message to be downloaded, usually obtained
      *  from the MMS WAP push notification
+     * @param contentUri a contentUri to which the downloaded MMS message will be written
      * @param configOverrides the carrier-specific messaging configuration values to override for
      *  downloading the message. See {@link android.telephony.MessagingConfigurationManager} for the
      *  value names and types.
@@ -55,7 +57,8 @@
      *  broadcast when the message is downloaded, or the download is failed
      */
     void downloadMessage(long subId, String callingPkg, String locationUrl,
-            in ContentValues configOverrides, in PendingIntent downloadedIntent);
+            in Uri contentUri, in ContentValues configOverrides,
+            in PendingIntent downloadedIntent);
 
     /**
      * Update the status of a pending (send-by-IP) MMS message handled by the carrier app.
@@ -104,14 +107,14 @@
       * Import a multimedia message into system's MMS store
       *
       * @param callingPkg the package name of the calling app
-      * @param pdu the PDU of the message to import
+      * @param contentUri the content uri from which to read PDU of the message to import
       * @param messageId the optional message id
       * @param timestampSecs the message timestamp in seconds
       * @param seen if the message is seen
       * @param read if the message is read
       * @return the message URI, null if failed
       */
-    Uri importMultimediaMessage(String callingPkg, in byte[] pdu, String messageId,
+    Uri importMultimediaMessage(String callingPkg, in Uri contentUri, String messageId,
             long timestampSecs, boolean seen, boolean read);
 
     /**
@@ -168,10 +171,10 @@
      * Add a multimedia message draft to system MMS store
      *
      * @param callingPkg the package name of the calling app
-     * @param pdu the PDU data of the draft MMS
+     * @param contentUri the content Uri from which to read PDU data of the draft MMS
      * @return the URI of the stored draft message
      */
-    Uri addMultimediaMessageDraft(String callingPkg, in byte[] pdu);
+    Uri addMultimediaMessageDraft(String callingPkg, in Uri contentUri);
 
     /**
      * Send a system stored MMS message
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index 6021ccf..46d0660 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -1,18 +1,18 @@
 /*
-* Copyright (C) 2011-2014 MediaTek Inc.
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-*      http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 package com.android.internal.telephony;
 
@@ -22,7 +22,6 @@
 interface ISub {
     /**
      * Get the SubInfoRecord according to an index
-     * @param context Context provided by caller
      * @param subId The unique SubInfoRecord index in database
      * @return SubInfoRecord, maybe null
      */
@@ -30,7 +29,6 @@
 
     /**
      * Get the SubInfoRecord according to an IccId
-     * @param context Context provided by caller
      * @param iccId the IccId of SIM card
      * @return SubInfoRecord, maybe null
      */
@@ -38,7 +36,6 @@
 
     /**
      * Get the SubInfoRecord according to slotId
-     * @param context Context provided by caller
      * @param slotId the slot which the SIM is inserted
      * @return SubInfoRecord, maybe null
      */
@@ -46,28 +43,30 @@
 
     /**
      * Get all the SubInfoRecord(s) in subinfo database
-     * @param context Context provided by caller
      * @return Array list of all SubInfoRecords in database, include thsoe that were inserted before
      */
     List<SubInfoRecord> getAllSubInfoList();
 
     /**
      * Get the SubInfoRecord(s) of the currently inserted SIM(s)
-     * @param context Context provided by caller
      * @return Array list of currently inserted SubInfoRecord(s)
      */
-    List<SubInfoRecord> getActivatedSubInfoList();
+    List<SubInfoRecord> getActiveSubInfoList();
 
     /**
      * Get the SUB count of all SUB(s) in subinfo database
-     * @param context Context provided by caller
      * @return all SIM count in database, include what was inserted before
      */
     int getAllSubInfoCount();
 
     /**
+     * Get the count of active SUB(s)
+     * @return active SIM count
+     */
+    int getActiveSubInfoCount();
+
+    /**
      * Add a new SubInfoRecord to subinfo database if needed
-     * @param context Context provided by caller
      * @param iccId the IccId of the SIM card
      * @param slotId the slot which the SIM is inserted
      * @return the URL of the newly created row or the updated row
@@ -76,7 +75,6 @@
 
     /**
      * Set SIM color by simInfo index
-     * @param context Context provided by caller
      * @param color the color of the SIM
      * @param subId the unique SubInfoRecord index in database
      * @return the number of records updated
@@ -85,7 +83,6 @@
 
     /**
      * Set display name by simInfo index
-     * @param context Context provided by caller
      * @param displayName the display name of SIM card
      * @param subId the unique SubInfoRecord index in database
      * @return the number of records updated
@@ -94,7 +91,6 @@
 
     /**
      * Set display name by simInfo index with name source
-     * @param context Context provided by caller
      * @param displayName the display name of SIM card
      * @param subId the unique SubInfoRecord index in database
      * @param nameSource, 0: DEFAULT_SOURCE, 1: SIM_SOURCE, 2: USER_INPUT
@@ -104,16 +100,14 @@
 
     /**
      * Set phone number by subId
-     * @param context Context provided by caller
      * @param number the phone number of the SIM
      * @param subId the unique SubInfoRecord index in database
      * @return the number of records updated
      */
-    int setDispalyNumber(String number, long subId);
+    int setDisplayNumber(String number, long subId);
 
     /**
      * Set number display format. 0: none, 1: the first four digits, 2: the last four digits
-     * @param context Context provided by caller
      * @param format the display format of phone number
      * @param subId the unique SubInfoRecord index in database
      * @return the number of records updated
@@ -122,7 +116,6 @@
 
     /**
      * Set data roaming by simInfo index
-     * @param context Context provided by caller
      * @param roaming 0:Don't allow data when roaming, 1:Allow data when roaming
      * @param subId the unique SubInfoRecord index in database
      * @return the number of records updated
@@ -150,4 +143,12 @@
     long getDefaultVoiceSubId();
 
     void setDefaultVoiceSubId(long subId);
+
+    long getDefaultSmsSubId();
+
+    void setDefaultSmsSubId(long subId);
+
+    void clearDefaultsForInactiveSubIds();
+
+    long[] getActiveSubIdList();
 }
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index b4b1ea5..62b5596 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -136,14 +136,6 @@
     /** APN type for IA Emergency PDN */
     public static final String APN_TYPE_EMERGENCY = "emergency";
 
-    // FIXME: This looks to be used as default phoneId, rename
-    // or use SubscriptionManager.DEFAULT_SUB_ID
-    public static final int DEFAULT_SUBSCRIPTION = 0;
-
-    // FIXME: This looks to be used as invalid phoneId, rename
-    // or use SubscriptionManager.INVALID_SUB_ID
-    public static final int INVALID_SUBSCRIPTION = -1;
-
     public static final int RIL_CARD_MAX_APPS    = 8;
 
     public static final int DEFAULT_CARD_INDEX   = 0;
@@ -154,10 +146,14 @@
 
     public static final int MAX_PHONE_COUNT_TRI_SIM = 3;
 
-    public static final String SUBSCRIPTION_KEY  = "subscription";
+    public static final String PHONE_KEY = "phone";
 
     public static final String SLOT_KEY  = "slot";
 
+    // FIXME: This is used to pass a subId via intents, we need to look at its usage, which is
+    // FIXME: extensive, and see if this should be an array of all active subId's or ...?
+    public static final String SUBSCRIPTION_KEY  = "subscription";
+
     public static final String SUB_SETTING  = "subSettings";
 
     public static final int SUB1 = 0;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 85ceefd..e7aca90 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -391,4 +391,14 @@
      */
     public static final String ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED
             = "android.intent.action.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED";
+
+    /**
+     * Broadcast Action: The default sms subscription has changed.  This has the following
+     * extra values:</p>
+     * <ul>
+     *   <li><em>subscription</em> - A int, the current sms default subscription.</li>
+     * </ul>
+     */
+    public static final String ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED
+            = "android.intent.action.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED";
 }
diff --git a/tools/layoutlib/.idea/libraries/asm_4_0.xml b/tools/layoutlib/.idea/libraries/asm_4_0.xml
index 578a7bf..7df287f 100644
--- a/tools/layoutlib/.idea/libraries/asm_4_0.xml
+++ b/tools/layoutlib/.idea/libraries/asm_4_0.xml
@@ -1,11 +1,11 @@
 <component name="libraryTable">
   <library name="asm-4.0">
     <CLASSES>
-      <root url="jar://$ANDROID_BUILD_TOP$/prebuilts/misc/common/asm/asm-4.0.jar!/" />
+      <root url="jar://$PROJECT_DIR$/../../../../prebuilts/misc/common/asm/asm-4.0.jar!/" />
     </CLASSES>
     <JAVADOC />
     <SOURCES>
-      <root url="jar://$ANDROID_BUILD_TOP$/prebuilts/misc/common/asm/src.zip!/" />
+      <root url="jar://$PROJECT_DIR$/../../../../prebuilts/misc/common/asm/src.zip!/" />
     </SOURCES>
   </library>
 </component>
\ No newline at end of file
diff --git a/tools/layoutlib/.idea/libraries/framework_jar.xml b/tools/layoutlib/.idea/libraries/framework_jar.xml
index 11f5b89..6695a36 100644
--- a/tools/layoutlib/.idea/libraries/framework_jar.xml
+++ b/tools/layoutlib/.idea/libraries/framework_jar.xml
@@ -1,13 +1,13 @@
 <component name="libraryTable">
   <library name="framework.jar">
     <CLASSES>
-      <root url="jar://$ANDROID_BUILD_TOP$/out/host/common/obj/JAVA_LIBRARIES/temp_layoutlib_intermediates/javalib.jar!/" />
+      <root url="jar://$PROJECT_DIR$/../../../../out/host/common/obj/JAVA_LIBRARIES/temp_layoutlib_intermediates/javalib.jar!/" />
     </CLASSES>
     <JAVADOC />
     <SOURCES>
-      <root url="file://$ANDROID_BUILD_TOP$/frameworks/base/core/java" />
-      <root url="file://$ANDROID_BUILD_TOP$/frameworks/base/graphics/java" />
-      <root url="file://$ANDROID_BUILD_TOP$/libcore/luni/src/main/java" />
+      <root url="file://$PROJECT_DIR$/../../core/java" />
+      <root url="file://$PROJECT_DIR$/../../graphics/java" />
+      <root url="file://$PROJECT_DIR$/../../../../libcore/luni/src/main/java" />
     </SOURCES>
   </library>
 </component>
\ No newline at end of file
diff --git a/tools/layoutlib/.idea/libraries/guava.xml b/tools/layoutlib/.idea/libraries/guava.xml
index de5607e..d47fc06 100644
--- a/tools/layoutlib/.idea/libraries/guava.xml
+++ b/tools/layoutlib/.idea/libraries/guava.xml
@@ -1,11 +1,11 @@
 <component name="libraryTable">
   <library name="guava">
     <CLASSES>
-      <root url="jar://$ANDROID_BUILD_TOP$/out/host/common/obj/JAVA_LIBRARIES/guavalib_intermediates/javalib.jar!/" />
+      <root url="jar://$PROJECT_DIR$/../../../../out/host/common/obj/JAVA_LIBRARIES/guavalib_intermediates/javalib.jar!/" />
     </CLASSES>
     <JAVADOC />
     <SOURCES>
-      <root url="file://$ANDROID_BUILD_TOP$/external/guava/guava/src" />
+      <root url="file://$PROJECT_DIR$/../../../../external/guava/guava/src" />
     </SOURCES>
   </library>
 </component>
\ No newline at end of file
diff --git a/tools/layoutlib/.idea/libraries/icu4j.xml b/tools/layoutlib/.idea/libraries/icu4j.xml
index 8d9a318..dbe0bd7 100644
--- a/tools/layoutlib/.idea/libraries/icu4j.xml
+++ b/tools/layoutlib/.idea/libraries/icu4j.xml
@@ -1,7 +1,7 @@
 <component name="libraryTable">
   <library name="icu4j">
     <CLASSES>
-      <root url="jar://$ANDROID_BUILD_TOP$/prebuilts/misc/common/icu4j/icu4j.jar!/" />
+      <root url="jar://$PROJECT_DIR$/../../../../prebuilts/misc/common/icu4j/icu4j.jar!/" />
     </CLASSES>
     <JAVADOC>
       <root url="http://icu-project.org/apiref/icu4j50rc/" />
diff --git a/tools/layoutlib/.idea/libraries/kxml2_2_3_0.xml b/tools/layoutlib/.idea/libraries/kxml2_2_3_0.xml
index 91feaea..2a65050 100644
--- a/tools/layoutlib/.idea/libraries/kxml2_2_3_0.xml
+++ b/tools/layoutlib/.idea/libraries/kxml2_2_3_0.xml
@@ -1,11 +1,11 @@
 <component name="libraryTable">
   <library name="kxml2-2.3.0">
     <CLASSES>
-      <root url="jar://$ANDROID_BUILD_TOP$/prebuilts/misc/common/kxml2/kxml2-2.3.0.jar!/" />
+      <root url="jar://$PROJECT_DIR$/../../../../prebuilts/misc/common/kxml2/kxml2-2.3.0.jar!/" />
     </CLASSES>
     <JAVADOC />
     <SOURCES>
-      <root url="file://$ANDROID_BUILD_TOP$/libcore/xml/src/main/java" />
+      <root url="file://$PROJECT_DIR$/../../../../libcore/xml/src/main/java" />
     </SOURCES>
   </library>
 </component>
\ No newline at end of file
diff --git a/tools/layoutlib/.idea/libraries/layoutlib_api_prebuilt.xml b/tools/layoutlib/.idea/libraries/layoutlib_api_prebuilt.xml
index be928da..5952002 100644
--- a/tools/layoutlib/.idea/libraries/layoutlib_api_prebuilt.xml
+++ b/tools/layoutlib/.idea/libraries/layoutlib_api_prebuilt.xml
@@ -1,7 +1,7 @@
 <component name="libraryTable">
   <library name="layoutlib_api-prebuilt">
     <CLASSES>
-      <root url="jar://$ANDROID_BUILD_TOP$/prebuilts/misc/common/layoutlib_api/layoutlib_api-prebuilt.jar!/" />
+      <root url="jar://$PROJECT_DIR$/../../../../prebuilts/misc/common/layoutlib_api/layoutlib_api-prebuilt.jar!/" />
     </CLASSES>
     <JAVADOC />
     <SOURCES>
diff --git a/tools/layoutlib/.idea/libraries/ninepatch_prebuilt.xml b/tools/layoutlib/.idea/libraries/ninepatch_prebuilt.xml
index 338137b..f34f7dd 100644
--- a/tools/layoutlib/.idea/libraries/ninepatch_prebuilt.xml
+++ b/tools/layoutlib/.idea/libraries/ninepatch_prebuilt.xml
@@ -1,7 +1,7 @@
 <component name="libraryTable">
   <library name="ninepatch-prebuilt">
     <CLASSES>
-      <root url="jar://$ANDROID_BUILD_TOP$/prebuilts/misc/common/ninepatch/ninepatch-prebuilt.jar!/" />
+      <root url="jar://$PROJECT_DIR$/../../../../prebuilts/misc/common/ninepatch/ninepatch-prebuilt.jar!/" />
     </CLASSES>
     <JAVADOC />
     <SOURCES>
diff --git a/tools/layoutlib/.idea/libraries/tools_common_prebuilt.xml b/tools/layoutlib/.idea/libraries/tools_common_prebuilt.xml
index 6479886..b325ad4 100644
--- a/tools/layoutlib/.idea/libraries/tools_common_prebuilt.xml
+++ b/tools/layoutlib/.idea/libraries/tools_common_prebuilt.xml
@@ -4,7 +4,7 @@
       <root url="file://$PROJECT_DIR$" />
     </ANNOTATIONS>
     <CLASSES>
-      <root url="jar://$ANDROID_BUILD_TOP$/prebuilts/misc/common/tools-common/tools-common-prebuilt.jar!/" />
+      <root url="jar://$PROJECT_DIR$/../../../../prebuilts/misc/common/tools-common/tools-common-prebuilt.jar!/" />
     </CLASSES>
     <JAVADOC />
     <SOURCES>
diff --git a/tools/layoutlib/.idea/runConfigurations/All_in_bridge.xml b/tools/layoutlib/.idea/runConfigurations/All_in_bridge.xml
index badbbab..f965ba7 100644
--- a/tools/layoutlib/.idea/runConfigurations/All_in_bridge.xml
+++ b/tools/layoutlib/.idea/runConfigurations/All_in_bridge.xml
@@ -8,7 +8,7 @@
     <option name="MAIN_CLASS_NAME" value="" />
     <option name="METHOD_NAME" value="" />
     <option name="TEST_OBJECT" value="package" />
-    <option name="VM_PARAMETERS" value="-ea -Dplatform.dir=&quot;$ANDROID_BUILD_TOP$/out/host/linux-x86/sdk/sdk/android-sdk_eng.deepanshu_linux-x86/platforms/android-L&quot; -Dtest_res.dir=&quot;$PROJECT_DIR$/bridge/tests/res&quot;" />
+    <option name="VM_PARAMETERS" value="-ea -Dtest_res.dir=&quot;$PROJECT_DIR$/bridge/tests/res&quot;" />
     <option name="PARAMETERS" value="" />
     <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
     <option name="ENV_VARIABLES" />
diff --git a/tools/layoutlib/.idea/runConfigurations/Create.xml b/tools/layoutlib/.idea/runConfigurations/Create.xml
index e62925b..fb0b866 100644
--- a/tools/layoutlib/.idea/runConfigurations/Create.xml
+++ b/tools/layoutlib/.idea/runConfigurations/Create.xml
@@ -4,7 +4,7 @@
     <option name="MAIN_CLASS_NAME" value="com.android.tools.layoutlib.create.Main" />
     <option name="VM_PARAMETERS" value="" />
     <option name="PROGRAM_PARAMETERS" value="out/host/common/obj/JAVA_LIBRARIES/temp_layoutlib_intermediates/javalib.jar out/target/common/obj/JAVA_LIBRARIES/core-libart_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/ext_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/ext_intermediates/javalib.jar" />
-    <option name="WORKING_DIRECTORY" value="file://$ANDROID_BUILD_TOP$/" />
+    <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/../../../../" />
     <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
     <option name="ALTERNATIVE_JRE_PATH" value="1.6" />
     <option name="ENABLE_SWING_INSPECTOR" value="false" />
diff --git a/tools/layoutlib/.idea/vcs.xml b/tools/layoutlib/.idea/vcs.xml
index 8114960..9ab281a 100644
--- a/tools/layoutlib/.idea/vcs.xml
+++ b/tools/layoutlib/.idea/vcs.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project version="4">
   <component name="VcsDirectoryMappings">
-    <mapping directory="$ANDROID_BUILD_TOP$/frameworks/base" vcs="Git" />
+    <mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
   </component>
 </project>
 
diff --git a/tools/layoutlib/bridge/bridge.iml b/tools/layoutlib/bridge/bridge.iml
index 7553b59..0f96916 100644
--- a/tools/layoutlib/bridge/bridge.iml
+++ b/tools/layoutlib/bridge/bridge.iml
@@ -34,11 +34,11 @@
     <orderEntry type="module-library" scope="TEST">
       <library>
         <CLASSES>
-          <root url="jar://$ANDROID_BUILD_TOP$/prebuilts/misc/common/sdk-common/sdk-common.jar!/" />
+          <root url="jar://$MODULE_DIR$/../../../../../prebuilts/misc/common/sdk-common/sdk-common.jar!/" />
         </CLASSES>
         <JAVADOC />
         <SOURCES>
-          <root url="jar://$ANDROID_BUILD_TOP$/prebuilts/misc/common/sdk-common/sdk-common-sources.jar!/" />
+          <root url="jar://$MODULE_DIR$/../../../../../prebuilts/misc/common/sdk-common/sdk-common-sources.jar!/" />
         </SOURCES>
       </library>
     </orderEntry>
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
index 5b69681..fbe21a8 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
@@ -90,9 +90,16 @@
         // fills TypedArray.mIndices which is used to implement getIndexCount/getIndexAt
         // first count the array size
         int count = 0;
-        for (ResourceValue data : mResourceData) {
-            if (data != null && !RenderResources.REFERENCE_NULL.equals(data.getValue())) {
-                count++;
+        for (int i = 0; i < mResourceData.length; i++) {
+            ResourceValue data = mResourceData[i];
+            if (data != null) {
+                if (RenderResources.REFERENCE_NULL.equals(data.getValue())) {
+                    // No need to store this resource value. This saves needless checking for
+                    // "@null" every time  an attribute is requested.
+                    mResourceData[i] = null;
+                } else {
+                    count++;
+                }
             }
         }
 
@@ -103,8 +110,7 @@
         // fill the array with the indices.
         int index = 1;
         for (int i = 0 ; i < mResourceData.length ; i++) {
-            if (mResourceData[i] != null
-                    && !RenderResources.REFERENCE_NULL.equals(mResourceData[i].getValue())) {
+            if (mResourceData[i] != null) {
                 mIndices[index++] = i;
             }
         }
@@ -215,10 +221,6 @@
 
         String s = mResourceData[index].getValue();
 
-        if (RenderResources.REFERENCE_NULL.equals(s)) {
-            return defValue;
-        }
-
         if (s == null || s.length() == 0) {
             return defValue;
         }
@@ -231,6 +233,20 @@
 
         // Field is not null and is not an integer.
         // Check for possible constants and try to find them.
+        return (int) resolveEnumAttribute(index, defValue);
+    }
+
+    /**
+     * Searches for the string in the attributes (flag or enums) and returns the integer.
+     * If found, it will return an integer matching the value. However, if the value is not found,
+     * it returns {@code defValue} which may be a float.
+     *
+     * @param index Index of attribute to retrieve.
+     * @param defValue Value to return if the attribute is not found.
+     *
+     * @return Attribute int value, or defValue if not defined.
+     */
+    private float resolveEnumAttribute(int index, float defValue) {
         // Get the map of attribute-constant -> IntegerValue
         Map<String, Integer> map = null;
         if (mIsFramework[index]) {
@@ -249,7 +265,7 @@
             int result = 0;
 
             // split the value in case this is a mix of several flags.
-            String[] keywords = s.split("\\|");
+            String[] keywords = mResourceData[index].getValue().split("\\|");
             for (String keyword : keywords) {
                 Integer i = map.get(keyword.trim());
                 if (i != null) {
@@ -258,7 +274,7 @@
                     Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
                             String.format(
                                 "\"%s\" in attribute \"%2$s\" is not a valid value",
-                                keyword, mNames[index]), null /*data*/);
+                                keyword, mNames[index]), null);
                 }
             }
             return result;
@@ -293,7 +309,7 @@
                 Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
                         String.format(
                             "\"%s\" in attribute \"%2$s\" cannot be converted to float.",
-                            s, mNames[index]), null /*data*/);
+                            s, mNames[index]), null);
 
                 // we'll return the default value below.
             }
@@ -358,10 +374,6 @@
             return null;
         }
 
-        if (RenderResources.REFERENCE_NULL.equals(value)) {
-            return null;
-        }
-
         // let the framework inflate the ColorStateList from the XML file.
         File f = new File(value);
         if (f.isFile()) {
@@ -377,13 +389,13 @@
                 }
             } catch (XmlPullParserException e) {
                 Bridge.getLog().error(LayoutLog.TAG_BROKEN,
-                        "Failed to configure parser for " + value, e, null /*data*/);
+                        "Failed to configure parser for " + value, e, null);
                 return null;
             } catch (Exception e) {
                 // this is an error and not warning since the file existence is checked before
                 // attempting to parse it.
                 Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
-                        "Failed to parse file " + value, e, null /*data*/);
+                        "Failed to parse file " + value, e, null);
 
                 return null;
             }
@@ -393,7 +405,7 @@
             int color = ResourceHelper.getColor(value);
             return ColorStateList.valueOf(color);
         } catch (NumberFormatException e) {
-            Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT, e.getMessage(), e, null /*data*/);
+            Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT, e.getMessage(), e, null);
         }
 
         return null;
@@ -443,26 +455,15 @@
 
         if (s == null) {
             return defValue;
-        } else if (s.equals(BridgeConstants.MATCH_PARENT) ||
-                s.equals(BridgeConstants.FILL_PARENT)) {
-            return LayoutParams.MATCH_PARENT;
-        } else if (s.equals(BridgeConstants.WRAP_CONTENT)) {
-            return LayoutParams.WRAP_CONTENT;
-        } else if (RenderResources.REFERENCE_NULL.equals(s)) {
-            return defValue;
         }
 
-        if (ResourceHelper.parseFloatAttribute(mNames[index], s, mValue, true /*requireUnit*/)) {
+        if (ResourceHelper.parseFloatAttribute(mNames[index], s, mValue, true)) {
             return mValue.getDimension(mBridgeResources.getDisplayMetrics());
         }
 
-        // looks like we were unable to resolve the dimension value
-        Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
-                String.format(
-                    "\"%1$s\" in attribute \"%2$s\" is not a valid format.",
-                    s, mNames[index]), null /*data*/);
-
-        return defValue;
+        // looks like we were unable to resolve the dimension value. Check if it is an attribute
+        // constant.
+        return resolveEnumAttribute(index, defValue);
     }
 
     /**
@@ -518,7 +519,7 @@
                     Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
                             String.format(
                                 "\"%1$s\" in attribute \"%2$s\" is not a valid format.",
-                                s, mNames[index]), null /*data*/);
+                                s, mNames[index]), null);
                 }
             }
 
@@ -575,11 +576,9 @@
             return LayoutParams.MATCH_PARENT;
         } else if (s.equals(BridgeConstants.WRAP_CONTENT)) {
             return LayoutParams.WRAP_CONTENT;
-        } else if (RenderResources.REFERENCE_NULL.equals(s)) {
-            throw new RuntimeException();
         }
 
-        if (ResourceHelper.parseFloatAttribute(mNames[index], s, mValue, true /*requireUnit*/)) {
+        if (ResourceHelper.parseFloatAttribute(mNames[index], s, mValue, true)) {
             float f = mValue.getDimension(mBridgeResources.getDisplayMetrics());
 
             final int res = (int)(f+0.5f);
@@ -621,16 +620,15 @@
             return defValue;
         }
 
-        if (ResourceHelper.parseFloatAttribute(mNames[index], value, mValue,
-                false /*requireUnit*/)) {
+        if (ResourceHelper.parseFloatAttribute(mNames[index], value, mValue, false)) {
             return mValue.getFraction(base, pbase);
         }
 
         // looks like we were unable to resolve the fraction value
         Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
                 String.format(
-                    "\"%1$s\" in attribute \"%2$s\" cannot be converted to a fraction.",
-                    value, mNames[index]), null /*data*/);
+                        "\"%1$s\" in attribute \"%2$s\" cannot be converted to a fraction.",
+                        value, mNames[index]), null);
 
         return defValue;
     }
@@ -669,10 +667,6 @@
             return mContext.getDynamicIdByStyle((StyleResourceValue)resValue);
         }
 
-        if (RenderResources.REFERENCE_NULL.equals(resValue.getValue())) {
-            return defValue;
-        }
-
         // if the attribute was a reference to a resource, and not a declaration of an id (@+id),
         // then the xml attribute value was "resolved" which leads us to a ResourceValue with a
         // valid getType() and getName() returning a resource name.
@@ -782,7 +776,7 @@
 
         ResourceValue value = mResourceData[index];
         String stringValue = value.getValue();
-        if (stringValue == null || RenderResources.REFERENCE_NULL.equals(stringValue)) {
+        if (stringValue == null) {
             return null;
         }
 
@@ -812,17 +806,13 @@
 
         String value = mResourceData[index].getValue();
         if (value != null) {
-            if (RenderResources.REFERENCE_NULL.equals(value)) {
-                return null;
-            }
-
             return new CharSequence[] { value };
         }
 
         Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
                 String.format(
                     String.format("Unknown value for getTextArray(%d) => %s", //DEBUG
-                    index, mResourceData[index].getName())), null /*data*/);
+                    index, mResourceData[index].getName())), null);
 
         return null;
     }
@@ -862,8 +852,7 @@
 
         String s = mResourceData[index].getValue();
 
-        return ResourceHelper.parseFloatAttribute(mNames[index], s, outValue,
-                false /*requireUnit*/);
+        return ResourceHelper.parseFloatAttribute(mNames[index], s, outValue, false);
     }
 
     /**
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
index adb0937..99ae7c9 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
@@ -63,11 +63,11 @@
      * Returns the color value represented by the given string value
      * @param value the color value
      * @return the color as an int
-     * @throw NumberFormatException if the conversion failed.
+     * @throws NumberFormatException if the conversion failed.
      */
     public static int getColor(String value) {
         if (value != null) {
-            if (value.startsWith("#") == false) {
+            if (!value.startsWith("#")) {
                 throw new NumberFormatException(
                         String.format("Color value '%s' must start with #", value));
             }
@@ -113,7 +113,7 @@
 
     public static ColorStateList getColorStateList(ResourceValue resValue, BridgeContext context) {
         String value = resValue.getValue();
-        if (value != null && RenderResources.REFERENCE_NULL.equals(value) == false) {
+        if (value != null && !RenderResources.REFERENCE_NULL.equals(value)) {
             // first check if the value is a file (xml most likely)
             File f = new File(value);
             if (f.isFile()) {
@@ -360,7 +360,7 @@
      */
     public static boolean parseFloatAttribute(String attribute, String value,
             TypedValue outValue, boolean requireUnit) {
-        assert requireUnit == false || attribute != null;
+        assert !requireUnit || attribute != null;
 
         // remove the space before and after
         value = value.trim();
@@ -379,7 +379,7 @@
         }
 
         // check the first character
-        if (buf[0] < '0' && buf[0] > '9' && buf[0] != '.' && buf[0] != '-') {
+        if ((buf[0] < '0' || buf[0] > '9') && buf[0] != '.' && buf[0] != '-' && buf[0] != '+') {
             return false;
         }
 
@@ -411,7 +411,7 @@
 
             if (end.length() == 0) {
                 if (outValue != null) {
-                    if (requireUnit == false) {
+                    if (!requireUnit) {
                         outValue.type = TypedValue.TYPE_FLOAT;
                         outValue.data = Float.floatToIntBits(f);
                     } else {
@@ -489,6 +489,8 @@
 
     private static void applyUnit(UnitEntry unit, TypedValue outValue, float[] outScale) {
         outValue.type = unit.type;
+        // COMPLEX_UNIT_SHIFT is 0 and hence intelliJ complains about it. Suppress the warning.
+        //noinspection PointlessBitwiseExpression
         outValue.data = unit.unit << TypedValue.COMPLEX_UNIT_SHIFT;
         outScale[0] = unit.scale;
     }
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
index 31b3e25..a2588a6 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
@@ -104,9 +104,61 @@
             return platformDir;
         }
         // System Property not set. Try to find the directory in the build directory.
-        String out = System.getenv("ANDROID_HOST_OUT");
-        if (out == null || out.isEmpty() || !new File(out).isDirectory()) {
-            // Can't find the out directory.
+        String androidHostOut = System.getenv("ANDROID_HOST_OUT");
+        if (androidHostOut != null) {
+            platformDir = getPlatformDirFromHostOut(new File(androidHostOut));
+            if (platformDir != null) {
+                return platformDir;
+            }
+        }
+        String workingDirString = System.getProperty("user.dir");
+        File workingDir = new File(workingDirString);
+        // Test if workingDir is android checkout root.
+        platformDir = getPlatformDirFromRoot(workingDir);
+        if (platformDir != null) {
+            return platformDir;
+        }
+        // Test if workingDir is  platform/frameworks/base/tools/layoutlib. That is, root should be
+        // workingDir/../../../../  (4 levels up)
+        File currentDir = workingDir;
+        for (int i = 0; i < 4; i++) {
+            if (currentDir != null) {
+                currentDir = currentDir.getParentFile();
+            }
+        }
+        return currentDir == null ? null : getPlatformDirFromRoot(currentDir);
+    }
+
+    private static String getPlatformDirFromRoot(File root) {
+        if (!root.isDirectory()) {
+            return null;
+        }
+        File out = new File(root, "out");
+        if (!out.isDirectory()) {
+            return null;
+        }
+        File host = new File(out, "host");
+        if (!host.isDirectory()) {
+            return null;
+        }
+        File[] hosts = host.listFiles(new FileFilter() {
+            @Override
+            public boolean accept(File path) {
+                return path.isDirectory() && (path.getName().startsWith("linux-") || path.getName()
+                        .startsWith("darwin-"));
+            }
+        });
+        for (File hostOut : hosts) {
+            String platformDir = getPlatformDirFromHostOut(hostOut);
+            if (platformDir != null) {
+                return platformDir;
+            }
+        }
+        return null;
+    }
+
+    private static String getPlatformDirFromHostOut(File out) {
+        if (!out.isDirectory()) {
             return null;
         }
         File sdkDir = new File(out, "sdk" + File.separator + "sdk");
@@ -117,7 +169,7 @@
         File[] possibleSdks = sdkDir.listFiles(new FileFilter() {
             @Override
             public boolean accept(File path) {
-                return path.isDirectory() && path.getAbsolutePath().contains("android-sdk");
+                return path.isDirectory() && path.getName().contains("android-sdk");
             }
         });
         for (File possibleSdk : possibleSdks) {
diff --git a/tools/layoutlib/create/tests/Android.mk b/tools/layoutlib/create/tests/Android.mk
new file mode 100644
index 0000000..0052ec2
--- /dev/null
+++ b/tools/layoutlib/create/tests/Android.mk
@@ -0,0 +1,32 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+# Only compile source java files in this lib.
+LOCAL_SRC_FILES := $(call all-java-files-under, com)
+
+LOCAL_JAVA_RESOURCE_DIRS := data mock_data
+
+LOCAL_MODULE := layoutlib-create-tests
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_JAVA_LIBRARIES := layoutlib_create junit
+LOCAL_STATIC_JAVA_LIBRARIES := asm-4.0
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+# Build all sub-directories
+include $(call all-makefiles-under,$(LOCAL_PATH))