am b9a28ae1: am f916524f: Merge "Add support for --user to "pm path" for work profile use"

* commit 'b9a28ae199ad44b07682f7417bc146acdc411c2a':
  Add support for --user to "pm path" for work profile use
diff --git a/Android.mk b/Android.mk
index 1247ae3..8888697 100644
--- a/Android.mk
+++ b/Android.mk
@@ -348,6 +348,7 @@
 	media/java/android/media/IRingtonePlayer.aidl \
 	media/java/android/media/IVolumeController.aidl \
 	media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl \
+	media/java/android/media/midi/IBluetoothMidiService.aidl \
 	media/java/android/media/midi/IMidiDeviceListener.aidl \
 	media/java/android/media/midi/IMidiDeviceOpenCallback.aidl \
 	media/java/android/media/midi/IMidiDeviceServer.aidl \
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 0adce5d..7cae745 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1619,7 +1619,8 @@
         // System apps and apps demanding internal storage can't be moved
         // anywhere else
         if (app.isSystemApp()
-                || app.installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
+                || app.installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY
+                || app.installLocation == PackageInfo.INSTALL_LOCATION_UNSPECIFIED) {
             return false;
         }
 
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index dac17d5..3d0c572 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3159,6 +3159,13 @@
     @SdkConstant(SdkConstantType.INTENT_CATEGORY)
     public static final String CATEGORY_HOME = "android.intent.category.HOME";
     /**
+     * This is the home activity that is displayed when the device is finished setting up and ready
+     * for use.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+    public static final String CATEGORY_HOME_MAIN = "android.intent.category.HOME_MAIN";
+    /**
      * This is the setup wizard activity, that is the first activity that is displayed
      * when the user sets up the device for the first time.
      * @hide
diff --git a/core/java/android/net/DhcpResults.java b/core/java/android/net/DhcpResults.java
index 87c063f..97bd5d2 100644
--- a/core/java/android/net/DhcpResults.java
+++ b/core/java/android/net/DhcpResults.java
@@ -21,7 +21,6 @@
 import android.text.TextUtils;
 import android.util.Log;
 
-import java.net.InetAddress;
 import java.net.Inet4Address;
 import java.util.Objects;
 
@@ -34,7 +33,7 @@
 public class DhcpResults extends StaticIpConfiguration {
     private static final String TAG = "DhcpResults";
 
-    public InetAddress serverAddress;
+    public Inet4Address serverAddress;
 
     /** Vendor specific information (from RFC 2132). */
     public String vendorInfo;
@@ -142,7 +141,7 @@
     private static void readFromParcel(DhcpResults dhcpResults, Parcel in) {
         StaticIpConfiguration.readFromParcel(dhcpResults, in);
         dhcpResults.leaseDuration = in.readInt();
-        dhcpResults.serverAddress = NetworkUtils.unparcelInetAddress(in);
+        dhcpResults.serverAddress = (Inet4Address) NetworkUtils.unparcelInetAddress(in);
         dhcpResults.vendorInfo = in.readString();
     }
 
@@ -183,8 +182,8 @@
 
     public boolean setServerAddress(String addrString) {
         try {
-            serverAddress = NetworkUtils.numericToInetAddress(addrString);
-        } catch (IllegalArgumentException e) {
+            serverAddress = (Inet4Address) NetworkUtils.numericToInetAddress(addrString);
+        } catch (IllegalArgumentException|ClassCastException e) {
             Log.e(TAG, "setServerAddress failed with addrString " + addrString);
             return true;
         }
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 02dae8a..eab22b8 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -51,12 +51,13 @@
     public static final int POLICY_ALLOW_BACKGROUND_BATTERY_SAVE = 0x2;
 
     /* RULE_* are not masks and they must be exclusive */
+    public static final int RULE_UNKNOWN = -1;
     /** All network traffic should be allowed. */
-    public static final int RULE_ALLOW_ALL = 0x0;
+    public static final int RULE_ALLOW_ALL = 0;
     /** Reject traffic on metered networks. */
-    public static final int RULE_REJECT_METERED = 0x1;
+    public static final int RULE_REJECT_METERED = 1;
     /** Reject traffic on all networks. */
-    public static final int RULE_REJECT_ALL = 0x2;
+    public static final int RULE_REJECT_ALL = 2;
 
     public static final int FIREWALL_RULE_DEFAULT = 0;
     public static final int FIREWALL_RULE_ALLOW = 1;
@@ -375,25 +376,4 @@
         // nothing found above; we can apply policy to UID
         return true;
     }
-
-    /** {@hide} */
-    public static void dumpPolicy(PrintWriter fout, int policy) {
-        fout.write("[");
-        if ((policy & POLICY_REJECT_METERED_BACKGROUND) != 0) {
-            fout.write("REJECT_METERED_BACKGROUND");
-        }
-        fout.write("]");
-    }
-
-    /** {@hide} */
-    public static void dumpRules(PrintWriter fout, int rules) {
-        fout.write("[");
-        if ((rules & RULE_REJECT_METERED) != 0) {
-            fout.write("REJECT_METERED");
-        } else if ((rules & RULE_REJECT_ALL) != 0) {
-            fout.write("REJECT_ALL");
-        }
-        fout.write("]");
-    }
-
 }
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 2374899..862f4c4 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -577,7 +577,7 @@
         public static final int KITKAT = 19;
 
         /**
-         * Android 4.4W: KitKat for watches, snacks on the run.
+         * June 2014: Android 4.4W. KitKat for watches, snacks on the run.
          *
          * <p>Applications targeting this or a later release will get these
          * new changes in behavior:</p>
@@ -595,7 +595,7 @@
         public static final int L = 21;
 
         /**
-         * Lollipop.  A flat one with beautiful shadows.  But still tasty.
+         * November 2014: Lollipop.  A flat one with beautiful shadows.  But still tasty.
          *
          * <p>Applications targeting this or a later release will get these
          * new changes in behavior:</p>
@@ -626,12 +626,38 @@
         public static final int LOLLIPOP = 21;
 
         /**
-         * Lollipop with an extra sugar coating on the outside!
+         * March 2015: Lollipop with an extra sugar coating on the outside!
          */
         public static final int LOLLIPOP_MR1 = 22;
 
         /**
-         * M comes after L.
+         * M is for Marshmallow!
+         *
+         * <p>Applications targeting this or a later release will get these
+         * new changes in behavior:</p>
+         * <ul>
+         * <li> Runtime permissions.  Dangerous permissions are no longer granted at
+         * install time, but must be requested by the application at runtime through
+         * {@link android.app.Activity#requestPermissions}.</li>
+         * <li> Bluetooth and Wi-Fi scanning now requires holding the location permission.</li>
+         * <li> {@link android.app.AlarmManager#setTimeZone AlarmManager.setTimeZone} will fail if
+         * the given timezone is non-Olson.</li>
+         * <li> Activity transitions will only return shared
+         * elements mapped in the returned view hierarchy back to the calling activity.</li>
+         * <li> {@link android.view.View} allows a number of behaviors that may break
+         * existing apps: Canvas throws an exception if restore() is called too many times,
+         * widgets may return a hint size when returning UNSPECIFIED measure specs, and it
+         * will respect the attributes {@link android.R.attr#foreground},
+         * {@link android.R.attr#foregroundGravity}, {@link android.R.attr#foregroundTint}, and
+         * {@link android.R.attr#foregroundTintMode}.</li>
+         * <li> {@link android.view.MotionEvent#getButtonState MotionEvent.getButtonState}
+         * will no longer report {@link android.view.MotionEvent#BUTTON_PRIMARY}
+         * and {@link android.view.MotionEvent#BUTTON_SECONDARY} as synonyms for
+         * {@link android.view.MotionEvent#BUTTON_STYLUS_PRIMARY} and
+         * {@link android.view.MotionEvent#BUTTON_STYLUS_SECONDARY}.</li>
+         * <li> {@link android.widget.ScrollView} now respects the layout param margins
+         * when measuring.</li>
+         * </ul>
          */
         public static final int M = 23;
     }
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 97b85e2..fdd34f5 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -471,7 +471,7 @@
        *     </tbody>
        * </table>
        */
-        public String getMemoryStat(String statName) {
+       public String getMemoryStat(String statName) {
             switch(statName) {
                 case "summary.java-heap":
                     return Integer.toString(getSummaryJavaHeap());
@@ -1538,7 +1538,13 @@
 
     /**
      * Retrieves information about this processes memory usages. This information is broken down by
-     * how much is in use by dalivk, the native heap, and everything else.
+     * how much is in use by dalvik, the native heap, and everything else.
+     *
+     * <p><b>Note:</b> this method directly retrieves memory information for the give process
+     * from low-level data available to it.  It may not be able to retrieve information about
+     * some protected allocations, such as graphics.  If you want to be sure you can see
+     * all information about allocations by the process, use instead
+     * {@link android.app.ActivityManager#getProcessMemoryInfo(int[])}.</p>
      */
     public static native void getMemoryInfo(MemoryInfo memoryInfo);
 
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index 979c828..2445bc2 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -383,6 +383,7 @@
                 final IntentFilter filter = new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION);
                 filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION);
                 filter.addAction(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
+                filter.addAction(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
                 mContext.registerReceiver(this, filter);
             } else {
                 mContext.unregisterReceiver(this);
@@ -395,13 +396,7 @@
             if (AudioManager.VOLUME_CHANGED_ACTION.equals(action)) {
                 int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
                 int streamValue = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1);
-                final boolean streamMatch = mNotificationOrRing ? isNotificationOrRing(streamType)
-                        : (streamType == mStreamType);
-                if (mSeekBar != null && streamMatch && streamValue != -1) {
-                    final boolean muted = mAudioManager.isStreamMute(mStreamType)
-                            || streamValue == 0;
-                    mUiHandler.postUpdateSlider(streamValue, mLastAudibleStreamVolume, muted);
-                }
+                updateVolumeSlider(streamType, streamValue);
             } else if (AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION.equals(action)) {
                 if (mNotificationOrRing) {
                     mRingerMode = mAudioManager.getRingerModeInternal();
@@ -409,10 +404,24 @@
                 if (mAffectedByRingerMode) {
                     updateSlider();
                 }
+            } else if (AudioManager.STREAM_DEVICES_CHANGED_ACTION.equals(action)) {
+                int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
+                int streamVolume = mAudioManager.getStreamVolume(streamType);
+                updateVolumeSlider(streamType, streamVolume);
             } else if (NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED.equals(action)) {
                 mZenMode = mNotificationManager.getZenMode();
                 updateSlider();
             }
         }
+
+        private void updateVolumeSlider(int streamType, int streamValue) {
+            final boolean streamMatch = mNotificationOrRing ? isNotificationOrRing(streamType)
+                    : (streamType == mStreamType);
+            if (mSeekBar != null && streamMatch && streamValue != -1) {
+                final boolean muted = mAudioManager.isStreamMute(mStreamType)
+                        || streamValue == 0;
+                mUiHandler.postUpdateSlider(streamValue, mLastAudibleStreamVolume, muted);
+            }
+        }
     }
 }
diff --git a/core/java/android/text/Hyphenator.java b/core/java/android/text/Hyphenator.java
index 10a994a..f2b6041 100644
--- a/core/java/android/text/Hyphenator.java
+++ b/core/java/android/text/Hyphenator.java
@@ -16,15 +16,17 @@
 
 package android.text;
 
-import com.android.internal.annotations.GuardedBy;
-
 import android.annotation.Nullable;
 import android.util.Log;
 
-import libcore.io.IoUtils;
+import com.android.internal.annotations.GuardedBy;
 
 import java.io.File;
 import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
 import java.util.HashMap;
 import java.util.Locale;
 
@@ -45,19 +47,29 @@
     @GuardedBy("sLock")
     final static HashMap<Locale, Hyphenator> sMap = new HashMap<Locale, Hyphenator>();
 
-    final static Hyphenator sEmptyHyphenator = new Hyphenator(StaticLayout.nLoadHyphenator(""));
+    final static Hyphenator sEmptyHyphenator =
+            new Hyphenator(StaticLayout.nLoadHyphenator(null, 0), null);
 
     final private long mNativePtr;
 
-    private Hyphenator(long nativePtr) {
+    // We retain a reference to the buffer to keep the memory mapping valid
+    @SuppressWarnings("unused")
+    final private ByteBuffer mBuffer;
+
+    private Hyphenator(long nativePtr, ByteBuffer b) {
         mNativePtr = nativePtr;
+        mBuffer = b;
     }
 
-    public static long get(@Nullable Locale locale) {
+    public long getNativePtr() {
+        return mNativePtr;
+    }
+
+    public static Hyphenator get(@Nullable Locale locale) {
         synchronized (sLock) {
             Hyphenator result = sMap.get(locale);
             if (result != null) {
-                return result.mNativePtr;
+                return result;
             }
 
             // TODO: Convert this a proper locale-fallback system
@@ -67,7 +79,7 @@
             result = sMap.get(languageOnlyLocale);
             if (result != null) {
                 sMap.put(locale, result);
-                return result.mNativePtr;
+                return result;
             }
 
             // Fall back to script-only, if available
@@ -80,22 +92,28 @@
                 result = sMap.get(scriptOnlyLocale);
                 if (result != null) {
                     sMap.put(locale, result);
-                    return result.mNativePtr;
+                    return result;
                 }
             }
 
             sMap.put(locale, sEmptyHyphenator);  // To remember we found nothing.
         }
-        return sEmptyHyphenator.mNativePtr;
+        return sEmptyHyphenator;
     }
 
     private static Hyphenator loadHyphenator(String languageTag) {
-        String patternFilename = "hyph-"+languageTag.toLowerCase(Locale.US)+".pat.txt";
+        String patternFilename = "hyph-" + languageTag.toLowerCase(Locale.US) + ".hyb";
         File patternFile = new File(getSystemHyphenatorLocation(), patternFilename);
         try {
-            String patternData = IoUtils.readFileAsString(patternFile.getAbsolutePath());
-            long nativePtr = StaticLayout.nLoadHyphenator(patternData);
-            return new Hyphenator(nativePtr);
+            RandomAccessFile f = new RandomAccessFile(patternFile, "r");
+            try {
+                FileChannel fc = f.getChannel();
+                MappedByteBuffer buf = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
+                long nativePtr = StaticLayout.nLoadHyphenator(buf, 0);
+                return new Hyphenator(nativePtr, buf);
+            } finally {
+                f.close();
+            }
         } catch (IOException e) {
             Log.e(TAG, "error loading hyphenation " + patternFile, e);
             return null;
@@ -148,7 +166,7 @@
         sMap.put(null, null);
 
         // TODO: replace this with a discovery-based method that looks into /system/usr/hyphen-data
-        String[] availableLanguages = {"en-US", "eu", "hu", "hy", "nb", "nn", "sa", "und-Ethi"};
+        String[] availableLanguages = {"en-US", "eu", "hu", "hy", "nb", "nn", "und-Ethi"};
         for (int i = 0; i < availableLanguages.length; i++) {
             String languageTag = availableLanguages[i];
             Hyphenator h = loadHyphenator(languageTag);
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 3b0def2..b0b08db 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -29,6 +29,7 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.GrowingArrayUtils;
 
+import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.Locale;
 
@@ -341,7 +342,8 @@
 
         private void setLocale(Locale locale) {
             if (!locale.equals(mLocale)) {
-                nSetLocale(mNativePtr, locale.toLanguageTag(), Hyphenator.get(locale));
+                nSetLocale(mNativePtr, locale.toLanguageTag(),
+                        Hyphenator.get(locale).getNativePtr());
                 mLocale = locale;
             }
         }
@@ -1243,7 +1245,7 @@
     private static native void nFreeBuilder(long nativePtr);
     private static native void nFinishBuilder(long nativePtr);
 
-    /* package */ static native long nLoadHyphenator(String patternData);
+    /* package */ static native long nLoadHyphenator(ByteBuffer buf, int offset);
 
     private static native void nSetLocale(long nativePtr, String locale, long nativeHyphenator);
 
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index da3a99b..d85ea65 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2355,7 +2355,13 @@
      *                            1      PFLAG3_APPLYING_INSETS
      *                           1       PFLAG3_FITTING_SYSTEM_WINDOWS
      *                          1        PFLAG3_NESTED_SCROLLING_ENABLED
-     *                         1         PFLAG3_ASSIST_BLOCKED
+     *                         1         PFLAG3_SCROLL_INDICATOR_TOP
+     *                        1          PFLAG3_SCROLL_INDICATOR_BOTTOM
+     *                       1           PFLAG3_SCROLL_INDICATOR_LEFT
+     *                      1            PFLAG3_SCROLL_INDICATOR_RIGHT
+     *                     1             PFLAG3_SCROLL_INDICATOR_START
+     *                    1              PFLAG3_SCROLL_INDICATOR_END
+     *                   1               PFLAG3_ASSIST_BLOCKED
      * |-------|-------|-------|-------|
      */
 
@@ -2549,7 +2555,7 @@
      * <p>Indicates that we are allowing {@link ViewStructure} to traverse
      * into this view.<p>
      */
-    static final int PFLAG3_ASSIST_BLOCKED = 0x100;
+    static final int PFLAG3_ASSIST_BLOCKED = 0x4000;
 
     /**
      * Always allow a user to over-scroll this view, provided it is a
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 2e0bf06..9708cce 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.app;
 
+import android.animation.ObjectAnimator;
+import android.annotation.NonNull;
 import android.app.Activity;
 import android.content.ComponentName;
 import android.content.Context;
@@ -29,6 +31,7 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
 import android.database.DataSetObserver;
+import android.graphics.Color;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
 import android.os.Bundle;
@@ -46,13 +49,18 @@
 import android.service.chooser.IChooserTargetResult;
 import android.service.chooser.IChooserTargetService;
 import android.text.TextUtils;
+import android.util.FloatProperty;
 import android.util.Log;
 import android.util.Slog;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.View.MeasureSpec;
 import android.view.View.OnClickListener;
 import android.view.View.OnLongClickListener;
 import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
 import android.widget.AbsListView;
 import android.widget.BaseAdapter;
 import android.widget.ListView;
@@ -80,6 +88,7 @@
     private Intent mReferrerFillInIntent;
 
     private ChooserListAdapter mChooserListAdapter;
+    private ChooserRowAdapter mChooserRowAdapter;
 
     private final List<ChooserTargetServiceConnection> mServiceConnections = new ArrayList<>();
 
@@ -253,7 +262,9 @@
             boolean alwaysUseOption) {
         final ListView listView = adapterView instanceof ListView ? (ListView) adapterView : null;
         mChooserListAdapter = (ChooserListAdapter) adapter;
-        adapterView.setAdapter(new ChooserRowAdapter(mChooserListAdapter));
+        mChooserRowAdapter = new ChooserRowAdapter(mChooserListAdapter);
+        mChooserRowAdapter.registerDataSetObserver(new OffsetDataSetObserver(adapterView));
+        adapterView.setAdapter(mChooserRowAdapter);
         if (listView != null) {
             listView.setItemsCanFocus(true);
         }
@@ -913,19 +924,111 @@
         }
     }
 
+    static class RowScale {
+        private static final int DURATION = 400;
+
+        float mScale;
+        ChooserRowAdapter mAdapter;
+        private final ObjectAnimator mAnimator;
+
+        public static final FloatProperty<RowScale> PROPERTY =
+                new FloatProperty<RowScale>("scale") {
+            @Override
+            public void setValue(RowScale object, float value) {
+                object.mScale = value;
+                object.mAdapter.notifyDataSetChanged();
+            }
+
+            @Override
+            public Float get(RowScale object) {
+                return object.mScale;
+            }
+        };
+
+        public RowScale(@NonNull ChooserRowAdapter adapter, float from, float to) {
+            mAdapter = adapter;
+            mScale = from;
+            if (from == to) {
+                mAnimator = null;
+                return;
+            }
+
+            mAnimator = ObjectAnimator.ofFloat(this, PROPERTY, from, to).setDuration(DURATION);
+        }
+
+        public RowScale setInterpolator(Interpolator interpolator) {
+            if (mAnimator != null) {
+                mAnimator.setInterpolator(interpolator);
+            }
+            return this;
+        }
+
+        public float get() {
+            return mScale;
+        }
+
+        public void startAnimation() {
+            if (mAnimator != null) {
+                mAnimator.start();
+            }
+        }
+
+        public void cancelAnimation() {
+            if (mAnimator != null) {
+                mAnimator.cancel();
+            }
+        }
+    }
+
     class ChooserRowAdapter extends BaseAdapter {
         private ChooserListAdapter mChooserListAdapter;
         private final LayoutInflater mLayoutInflater;
         private final int mColumnCount = 4;
+        private RowScale[] mServiceTargetScale;
+        private final Interpolator mInterpolator;
 
         public ChooserRowAdapter(ChooserListAdapter wrappedAdapter) {
             mChooserListAdapter = wrappedAdapter;
             mLayoutInflater = LayoutInflater.from(ChooserActivity.this);
 
+            mInterpolator = AnimationUtils.loadInterpolator(ChooserActivity.this,
+                    android.R.interpolator.decelerate_quint);
+
             wrappedAdapter.registerDataSetObserver(new DataSetObserver() {
                 @Override
                 public void onChanged() {
                     super.onChanged();
+                    final int rcount = getServiceTargetRowCount();
+                    if (mServiceTargetScale == null
+                            || mServiceTargetScale.length != rcount) {
+                        RowScale[] old = mServiceTargetScale;
+                        int oldRCount = old != null ? old.length : 0;
+                        mServiceTargetScale = new RowScale[rcount];
+                        if (old != null && rcount > 0) {
+                            System.arraycopy(old, 0, mServiceTargetScale, 0,
+                                    Math.min(old.length, rcount));
+                        }
+
+                        for (int i = rcount; i < oldRCount; i++) {
+                            old[i].cancelAnimation();
+                        }
+
+                        for (int i = oldRCount; i < rcount; i++) {
+                            final RowScale rs = new RowScale(ChooserRowAdapter.this, 0.f, 1.f)
+                                    .setInterpolator(mInterpolator);
+                            mServiceTargetScale[i] = rs;
+                        }
+
+                        // Start the animations in a separate loop.
+                        // The process of starting animations will result in
+                        // binding views to set up initial values, and we must
+                        // have ALL of the new RowScale objects created above before
+                        // we get started.
+                        for (int i = oldRCount; i < rcount; i++) {
+                            mServiceTargetScale[i].startAnimation();
+                        }
+                    }
+
                     notifyDataSetChanged();
                 }
 
@@ -933,19 +1036,43 @@
                 public void onInvalidated() {
                     super.onInvalidated();
                     notifyDataSetInvalidated();
+                    if (mServiceTargetScale != null) {
+                        for (RowScale rs : mServiceTargetScale) {
+                            rs.cancelAnimation();
+                        }
+                    }
                 }
             });
         }
 
+        private float getRowScale(int rowPosition) {
+            final int start = getCallerTargetRowCount();
+            final int end = start + getServiceTargetRowCount();
+            if (rowPosition >= start && rowPosition < end) {
+                return mServiceTargetScale[rowPosition - start].get();
+            }
+            return 1.f;
+        }
+
         @Override
         public int getCount() {
             return (int) (
-                    Math.ceil((float) mChooserListAdapter.getCallerTargetCount() / mColumnCount)
-                    + Math.ceil((float) mChooserListAdapter.getServiceTargetCount() / mColumnCount)
+                    getCallerTargetRowCount()
+                    + getServiceTargetRowCount()
                     + Math.ceil((float) mChooserListAdapter.getStandardTargetCount() / mColumnCount)
             );
         }
 
+        public int getCallerTargetRowCount() {
+            return (int) Math.ceil(
+                    (float) mChooserListAdapter.getCallerTargetCount() / mColumnCount);
+        }
+
+        public int getServiceTargetRowCount() {
+            return (int) Math.ceil(
+                    (float) mChooserListAdapter.getServiceTargetCount() / mColumnCount);
+        }
+
         @Override
         public Object getItem(int position) {
             // We have nothing useful to return here.
@@ -959,33 +1086,69 @@
 
         @Override
         public View getView(int position, View convertView, ViewGroup parent) {
-            final View[] holder;
+            final RowViewHolder holder;
             if (convertView == null) {
                 holder = createViewHolder(parent);
             } else {
-                holder = (View[]) convertView.getTag();
+                holder = (RowViewHolder) convertView.getTag();
             }
             bindViewHolder(position, holder);
 
-            // We keep the actual list item view as the last item in the holder array
-            return holder[mColumnCount];
+            return holder.row;
         }
 
-        View[] createViewHolder(ViewGroup parent) {
-            final View[] holder = new View[mColumnCount + 1];
-
+        RowViewHolder createViewHolder(ViewGroup parent) {
             final ViewGroup row = (ViewGroup) mLayoutInflater.inflate(R.layout.chooser_row,
                     parent, false);
+            final RowViewHolder holder = new RowViewHolder(row, mColumnCount);
+            final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+
             for (int i = 0; i < mColumnCount; i++) {
-                holder[i] = mChooserListAdapter.createView(row);
-                row.addView(holder[i]);
+                final View v = mChooserListAdapter.createView(row);
+                final int column = i;
+                v.setOnClickListener(new OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        startSelected(holder.itemIndices[column], false, true);
+                    }
+                });
+                v.setOnLongClickListener(new OnLongClickListener() {
+                    @Override
+                    public boolean onLongClick(View v) {
+                        showAppDetails(
+                                mChooserListAdapter.resolveInfoForPosition(
+                                        holder.itemIndices[column], true));
+                        return true;
+                    }
+                });
+                row.addView(v);
+                holder.cells[i] = v;
+
+                // Force height to be a given so we don't have visual disruption during scaling.
+                LayoutParams lp = v.getLayoutParams();
+                v.measure(spec, spec);
+                if (lp == null) {
+                    lp = new LayoutParams(LayoutParams.MATCH_PARENT, v.getMeasuredHeight());
+                    row.setLayoutParams(lp);
+                } else {
+                    lp.height = v.getMeasuredHeight();
+                }
+            }
+
+            // Pre-measure so we can scale later.
+            holder.measure();
+            LayoutParams lp = row.getLayoutParams();
+            if (lp == null) {
+                lp = new LayoutParams(LayoutParams.MATCH_PARENT, holder.measuredRowHeight);
+                row.setLayoutParams(lp);
+            } else {
+                lp.height = holder.measuredRowHeight;
             }
             row.setTag(holder);
-            holder[mColumnCount] = row;
             return holder;
         }
 
-        void bindViewHolder(int rowPosition, View[] holder) {
+        void bindViewHolder(int rowPosition, RowViewHolder holder) {
             final int start = getFirstRowPosition(rowPosition);
             final int startType = mChooserListAdapter.getPositionTargetType(start);
 
@@ -994,34 +1157,26 @@
                 end--;
             }
 
-            final ViewGroup row = (ViewGroup) holder[mColumnCount];
-
             if (startType == ChooserListAdapter.TARGET_SERVICE) {
-                row.setBackgroundColor(getColor(R.color.chooser_service_row_background_color));
+                holder.row.setBackgroundColor(
+                        getColor(R.color.chooser_service_row_background_color));
             } else {
-                row.setBackground(null);
+                holder.row.setBackgroundColor(Color.TRANSPARENT);
+            }
+
+            final int oldHeight = holder.row.getLayoutParams().height;
+            holder.row.getLayoutParams().height = Math.max(1,
+                    (int) (holder.measuredRowHeight * getRowScale(rowPosition)));
+            if (holder.row.getLayoutParams().height != oldHeight) {
+                holder.row.requestLayout();
             }
 
             for (int i = 0; i < mColumnCount; i++) {
-                final View v = holder[i];
+                final View v = holder.cells[i];
                 if (start + i <= end) {
                     v.setVisibility(View.VISIBLE);
-                    final int itemIndex = start + i;
-                    mChooserListAdapter.bindView(itemIndex, v);
-                    v.setOnClickListener(new OnClickListener() {
-                        @Override
-                        public void onClick(View v) {
-                            startSelected(itemIndex, false, true);
-                        }
-                    });
-                    v.setOnLongClickListener(new OnLongClickListener() {
-                        @Override
-                        public boolean onLongClick(View v) {
-                            showAppDetails(
-                                    mChooserListAdapter.resolveInfoForPosition(itemIndex, true));
-                            return true;
-                        }
-                    });
+                    holder.itemIndices[i] = start + i;
+                    mChooserListAdapter.bindView(holder.itemIndices[i], v);
                 } else {
                     v.setVisibility(View.GONE);
                 }
@@ -1048,6 +1203,25 @@
         }
     }
 
+    static class RowViewHolder {
+        final View[] cells;
+        final ViewGroup row;
+        int measuredRowHeight;
+        int[] itemIndices;
+
+        public RowViewHolder(ViewGroup row, int cellCount) {
+            this.row = row;
+            this.cells = new View[cellCount];
+            this.itemIndices = new int[cellCount];
+        }
+
+        public void measure() {
+            final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+            row.measure(spec, spec);
+            measuredRowHeight = row.getMeasuredHeight();
+        }
+    }
+
     static class ChooserTargetServiceConnection implements ServiceConnection {
         private final DisplayResolveInfo mOriginalTarget;
         private ComponentName mConnectedComponent;
@@ -1199,4 +1373,44 @@
             mSelectedTarget = null;
         }
     }
+
+    class OffsetDataSetObserver extends DataSetObserver {
+        private final AbsListView mListView;
+        private int mCachedViewType = -1;
+        private View mCachedView;
+
+        public OffsetDataSetObserver(AbsListView listView) {
+            mListView = listView;
+        }
+
+        @Override
+        public void onChanged() {
+            if (mResolverDrawerLayout == null) {
+                return;
+            }
+
+            final int chooserTargetRows = mChooserRowAdapter.getServiceTargetRowCount();
+            int offset = 0;
+            for (int i = 0; i < chooserTargetRows; i++)  {
+                final int pos = mChooserRowAdapter.getCallerTargetRowCount() + i;
+                final int vt = mChooserRowAdapter.getItemViewType(pos);
+                if (vt != mCachedViewType) {
+                    mCachedView = null;
+                }
+                final View v = mChooserRowAdapter.getView(pos, mCachedView, mListView);
+                int height = ((RowViewHolder) (v.getTag())).measuredRowHeight;
+
+                offset += (int) (height * mChooserRowAdapter.getRowScale(pos));
+
+                if (vt >= 0) {
+                    mCachedViewType = vt;
+                    mCachedView = v;
+                } else {
+                    mCachedViewType = -1;
+                }
+            }
+
+            mResolverDrawerLayout.setCollapsibleHeightReserved(offset);
+        }
+    }
 }
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 1710489..ba0912a 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -103,6 +103,8 @@
     private ResolverComparator mResolverComparator;
     private PickTargetOptionRequest mPickOptionRequest;
 
+    protected ResolverDrawerLayout mResolverDrawerLayout;
+
     private boolean mRegistered;
     private final PackageMonitor mPackageMonitor = new PackageMonitor() {
         @Override public void onSomePackagesChanged() {
@@ -253,6 +255,7 @@
             if (isVoiceInteraction()) {
                 rdl.setCollapsed(false);
             }
+            mResolverDrawerLayout = rdl;
         }
 
         if (title == null) {
@@ -1570,7 +1573,10 @@
 
         private void onBindView(View view, TargetInfo info) {
             final ViewHolder holder = (ViewHolder) view.getTag();
-            holder.text.setText(info.getDisplayLabel());
+            final CharSequence label = info.getDisplayLabel();
+            if (!TextUtils.equals(holder.text.getText(), label)) {
+                holder.text.setText(info.getDisplayLabel());
+            }
             if (showsExtendedInfo(info)) {
                 holder.text2.setVisibility(View.VISIBLE);
                 holder.text2.setText(info.getExtendedInfo());
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index 7679624..c4347f8 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -69,6 +69,12 @@
     private int mCollapsibleHeight;
     private int mUncollapsibleHeight;
 
+    /**
+     * The height in pixels of reserved space added to the top of the collapsed UI;
+     * e.g. chooser targets
+     */
+    private int mCollapsibleHeightReserved;
+
     private int mTopOffset;
 
     private boolean mIsDragging;
@@ -153,12 +159,62 @@
         }
     }
 
+    public void setCollapsibleHeightReserved(int heightPixels) {
+        final int oldReserved = mCollapsibleHeightReserved;
+        mCollapsibleHeightReserved = heightPixels;
+
+        final int dReserved = mCollapsibleHeightReserved - oldReserved;
+        if (dReserved != 0 && mIsDragging) {
+            mLastTouchY -= dReserved;
+        }
+
+        final int oldCollapsibleHeight = mCollapsibleHeight;
+        mCollapsibleHeight = Math.max(mCollapsibleHeight, getMaxCollapsedHeight());
+
+        if (updateCollapseOffset(oldCollapsibleHeight, !isDragging())) {
+            return;
+        }
+
+        invalidate();
+    }
+
     private boolean isMoving() {
         return mIsDragging || !mScroller.isFinished();
     }
 
+    private boolean isDragging() {
+        return mIsDragging || getNestedScrollAxes() == SCROLL_AXIS_VERTICAL;
+    }
+
+    private boolean updateCollapseOffset(int oldCollapsibleHeight, boolean remainClosed) {
+        if (oldCollapsibleHeight == mCollapsibleHeight) {
+            return false;
+        }
+
+        if (isLaidOut()) {
+            final boolean isCollapsedOld = mCollapseOffset != 0;
+            if (remainClosed && (oldCollapsibleHeight < mCollapsibleHeight
+                    && mCollapseOffset == oldCollapsibleHeight)) {
+                // Stay closed even at the new height.
+                mCollapseOffset = mCollapsibleHeight;
+            } else {
+                mCollapseOffset = Math.min(mCollapseOffset, mCollapsibleHeight);
+            }
+            final boolean isCollapsedNew = mCollapseOffset != 0;
+            if (isCollapsedOld != isCollapsedNew) {
+                notifyViewAccessibilityStateChangedIfNeeded(
+                        AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+            }
+        } else {
+            // Start out collapsed at first unless we restored state for otherwise
+            mCollapseOffset = mOpenOnLayout ? 0 : mCollapsibleHeight;
+        }
+        return true;
+    }
+
     private int getMaxCollapsedHeight() {
-        return isSmallCollapsed() ? mMaxCollapsedHeightSmall : mMaxCollapsedHeight;
+        return (isSmallCollapsed() ? mMaxCollapsedHeightSmall : mMaxCollapsedHeight)
+                + mCollapsibleHeightReserved;
     }
 
     public void setOnDismissedListener(OnDismissedListener listener) {
@@ -676,7 +732,7 @@
             final LayoutParams lp = (LayoutParams) child.getLayoutParams();
             if (lp.alwaysShow && child.getVisibility() != GONE) {
                 measureChildWithMargins(child, widthSpec, widthPadding, heightSpec, heightUsed);
-                heightUsed += lp.topMargin + child.getMeasuredHeight() + lp.bottomMargin;
+                heightUsed += getHeightUsed(child);
             }
         }
 
@@ -688,7 +744,7 @@
             final LayoutParams lp = (LayoutParams) child.getLayoutParams();
             if (!lp.alwaysShow && child.getVisibility() != GONE) {
                 measureChildWithMargins(child, widthSpec, widthPadding, heightSpec, heightUsed);
-                heightUsed += lp.topMargin + child.getMeasuredHeight() + lp.bottomMargin;
+                heightUsed += getHeightUsed(child);
             }
         }
 
@@ -697,30 +753,43 @@
                 heightUsed - alwaysShowHeight - getMaxCollapsedHeight());
         mUncollapsibleHeight = heightUsed - mCollapsibleHeight;
 
-        if (isLaidOut()) {
-            final boolean isCollapsedOld = mCollapseOffset != 0;
-            if (oldCollapsibleHeight < mCollapsibleHeight
-                    && mCollapseOffset == oldCollapsibleHeight) {
-                // Stay closed even at the new height.
-                mCollapseOffset = mCollapsibleHeight;
-            } else {
-                mCollapseOffset = Math.min(mCollapseOffset, mCollapsibleHeight);
-            }
-            final boolean isCollapsedNew = mCollapseOffset != 0;
-            if (isCollapsedOld != isCollapsedNew) {
-                notifyViewAccessibilityStateChangedIfNeeded(
-                        AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
-            }
-        } else {
-            // Start out collapsed at first unless we restored state for otherwise
-            mCollapseOffset = mOpenOnLayout ? 0 : mCollapsibleHeight;
-        }
+        updateCollapseOffset(oldCollapsibleHeight, !isDragging());
 
         mTopOffset = Math.max(0, heightSize - heightUsed) + (int) mCollapseOffset;
 
         setMeasuredDimension(sourceWidth, heightSize);
     }
 
+    private int getHeightUsed(View child) {
+        // This method exists because we're taking a fast path at measuring ListViews that
+        // lets us get away with not doing the more expensive wrap_content measurement which
+        // imposes double child view measurement costs. If we're looking at a ListView, we can
+        // check against the lowest child view plus padding and margin instead of the actual
+        // measured height of the ListView. This lets the ListView hang off the edge when
+        // all of the content would fit on-screen.
+
+        int heightUsed = child.getMeasuredHeight();
+        if (child instanceof AbsListView) {
+            final AbsListView lv = (AbsListView) child;
+            final int lvPaddingBottom = lv.getPaddingBottom();
+
+            int lowest = 0;
+            for (int i = 0, N = lv.getChildCount(); i < N; i++) {
+                final int bottom = lv.getChildAt(i).getBottom() + lvPaddingBottom;
+                if (bottom > lowest) {
+                    lowest = bottom;
+                }
+            }
+
+            if (lowest < heightUsed) {
+                heightUsed = lowest;
+            }
+        }
+
+        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+        return lp.topMargin + heightUsed + lp.bottomMargin;
+    }
+
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         final int width = getWidth();
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index a151e00..83f76ea 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -117,9 +117,17 @@
     b->finish();
 }
 
-static jlong nLoadHyphenator(JNIEnv* env, jclass, jstring patternData) {
-    ScopedStringChars str(env, patternData);
-    Hyphenator* hyphenator = Hyphenator::load(str.get(), str.size());
+static jlong nLoadHyphenator(JNIEnv* env, jclass, jobject buffer, jint offset) {
+    const uint8_t* bytebuf = nullptr;
+    if (buffer != nullptr) {
+        void* rawbuf = env->GetDirectBufferAddress(buffer);
+        if (rawbuf != nullptr) {
+            bytebuf = reinterpret_cast<const uint8_t*>(rawbuf) + offset;
+        } else {
+            ALOGE("failed to get direct buffer address");
+        }
+    }
+    Hyphenator* hyphenator = Hyphenator::loadBinary(bytebuf);
     return reinterpret_cast<jlong>(hyphenator);
 }
 
@@ -177,7 +185,7 @@
     {"nNewBuilder", "()J", (void*) nNewBuilder},
     {"nFreeBuilder", "(J)V", (void*) nFreeBuilder},
     {"nFinishBuilder", "(J)V", (void*) nFinishBuilder},
-    {"nLoadHyphenator", "(Ljava/lang/String;)J", (void*) nLoadHyphenator},
+    {"nLoadHyphenator", "(Ljava/nio/ByteBuffer;I)J", (void*) nLoadHyphenator},
     {"nSetLocale", "(JLjava/lang/String;J)V", (void*) nSetLocale},
     {"nSetupParagraph", "(J[CIFIF[IIII)V", (void*) nSetupParagraph},
     {"nSetIndents", "(J[I)V", (void*) nSetIndents},
diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml
index dcdfb6c..41726fb 100644
--- a/core/res/res/layout/chooser_grid.xml
+++ b/core/res/res/layout/chooser_grid.xml
@@ -85,7 +85,7 @@
 
     <ListView
             android:layout_width="match_parent"
-            android:layout_height="wrap_content"
+            android:layout_height="match_parent"
             android:id="@+id/resolver_list"
             android:clipToPadding="false"
             android:scrollbarStyle="outsideOverlay"
diff --git a/core/res/res/layout/resolve_grid_item.xml b/core/res/res/layout/resolve_grid_item.xml
index 1c496f6..0a7ac77 100644
--- a/core/res/res/layout/resolve_grid_item.xml
+++ b/core/res/res/layout/resolve_grid_item.xml
@@ -70,6 +70,7 @@
               android:minLines="2"
               android:maxLines="2"
               android:gravity="top|center_horizontal"
-              android:ellipsize="marquee" />
+              android:ellipsize="marquee"
+              android:visibility="gone" />
 </LinearLayout>
 
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 1a45b3a..cf08dea 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2095,6 +2095,10 @@
             <enum name="hdpi" value="240" />
             <!-- An extra high density screen, approximately 320dpi. -->
             <enum name="xhdpi" value="320" />
+            <!-- An extra extra high density screen, approximately 480dpi. -->
+            <enum name="xxhdpi" value="480" />
+            <!-- An extra extra extra high density screen, approximately 640dpi. -->
+            <enum name="xxxhdpi" value="640" />
         </attr>
     </declare-styleable>
 
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 0859e5a..e2d4468 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -938,6 +938,9 @@
     <!-- Is the device capable of hot swapping an UICC Card -->
     <bool name="config_hotswapCapable">false</bool>
 
+    <!-- Component name of the ICC hotswap prompt for restart dialog -->
+    <string name="config_iccHotswapPromptForRestartDialogComponent" translateable="false">@null</string>
+
     <!-- Enable puk unlockscreen by default.
          If unlock screen is disabled, the puk should be unlocked through Emergency Dialer -->
     <bool name="config_enable_puk_unlock_screen">true</bool>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 6d8c38f..b399fba 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2336,4 +2336,6 @@
 
   <java-symbol type="string" name="config_networkPolicyNotificationComponent" />
   <java-symbol type="drawable" name="platlogo_m" />
+
+  <java-symbol type="string" name="config_iccHotswapPromptForRestartDialogComponent" />
 </resources>
diff --git a/data/keyboards/Vendor_18d1_Product_5018.kcm b/data/keyboards/Vendor_18d1_Product_5018.kcm
new file mode 100644
index 0000000..0ca85a2
--- /dev/null
+++ b/data/keyboards/Vendor_18d1_Product_5018.kcm
@@ -0,0 +1,321 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Key character map for Google Pixel C Keyboard
+#
+
+type FULL
+
+### Basic QWERTY keys ###
+
+key A {
+    label:                              'A'
+    base:                               'a'
+    shift, capslock:                    'A'
+}
+
+key B {
+    label:                              'B'
+    base:                               'b'
+    shift, capslock:                    'B'
+}
+
+key C {
+    label:                              'C'
+    base:                               'c'
+    shift, capslock:                    'C'
+    alt:                                '\u00e7'
+    shift+alt:                          '\u00c7'
+}
+
+key D {
+    label:                              'D'
+    base:                               'd'
+    shift, capslock:                    'D'
+}
+
+key E {
+    label:                              'E'
+    base:                               'e'
+    shift, capslock:                    'E'
+    alt:                                '\u0301'
+}
+
+key F {
+    label:                              'F'
+    base:                               'f'
+    shift, capslock:                    'F'
+}
+
+key G {
+    label:                              'G'
+    base:                               'g'
+    shift, capslock:                    'G'
+}
+
+key H {
+    label:                              'H'
+    base:                               'h'
+    shift, capslock:                    'H'
+}
+
+key I {
+    label:                              'I'
+    base:                               'i'
+    shift, capslock:                    'I'
+    alt:                                '\u0302'
+}
+
+key J {
+    label:                              'J'
+    base:                               'j'
+    shift, capslock:                    'J'
+}
+
+key K {
+    label:                              'K'
+    base:                               'k'
+    shift, capslock:                    'K'
+}
+
+key L {
+    label:                              'L'
+    base:                               'l'
+    shift, capslock:                    'L'
+}
+
+key M {
+    label:                              'M'
+    base:                               'm'
+    shift, capslock:                    'M'
+}
+
+key N {
+    label:                              'N'
+    base:                               'n'
+    shift, capslock:                    'N'
+    alt:                                '\u0303'
+}
+
+key O {
+    label:                              'O'
+    base:                               'o'
+    shift, capslock:                    'O'
+    ralt:                               '['
+    ralt+shift:                         '{'
+}
+
+key P {
+    label:                              'P'
+    base:                               'p'
+    shift, capslock:                    'P'
+    ralt:                               ']'
+    ralt+shift:                         '}'
+}
+
+key Q {
+    label:                              'Q'
+    base:                               'q'
+    shift, capslock:                    'Q'
+}
+
+key R {
+    label:                              'R'
+    base:                               'r'
+    shift, capslock:                    'R'
+}
+
+key S {
+    label:                              'S'
+    base:                               's'
+    shift, capslock:                    'S'
+    alt:                                '\u00df'
+}
+
+key T {
+    label:                              'T'
+    base:                               't'
+    shift, capslock:                    'T'
+}
+
+key U {
+    label:                              'U'
+    base:                               'u'
+    shift, capslock:                    'U'
+    alt:                                '\u0308'
+}
+
+key V {
+    label:                              'V'
+    base:                               'v'
+    shift, capslock:                    'V'
+}
+
+key W {
+    label:                              'W'
+    base:                               'w'
+    shift, capslock:                    'W'
+}
+
+key X {
+    label:                              'X'
+    base:                               'x'
+    shift, capslock:                    'X'
+}
+
+key Y {
+    label:                              'Y'
+    base:                               'y'
+    shift, capslock:                    'Y'
+}
+
+key Z {
+    label:                              'Z'
+    base:                               'z'
+    shift, capslock:                    'Z'
+}
+
+key 0 {
+    label:                              '0'
+    base:                               '0'
+    shift:                              ')'
+}
+
+key 1 {
+    label:                              '1'
+    base:                               '1'
+    shift:                              '!'
+    ralt:                               replace ESCAPE
+}
+
+key 2 {
+    label:                              '2'
+    base:                               '2'
+    shift:                              '@'
+    ralt:                               '`'
+    ralt+shift:                         '~'
+}
+
+key 3 {
+    label:                              '3'
+    base:                               '3'
+    shift:                              '#'
+}
+
+key 4 {
+    label:                              '4'
+    base:                               '4'
+    shift:                              '$'
+}
+
+key 5 {
+    label:                              '5'
+    base:                               '5'
+    shift:                              '%'
+}
+
+key 6 {
+    label:                              '6'
+    base:                               '6'
+    shift:                              '^'
+    alt+shift:                          '\u0302'
+}
+
+key 7 {
+    label:                              '7'
+    base:                               '7'
+    shift:                              '&'
+}
+
+key 8 {
+    label:                              '8'
+    base:                               '8'
+    shift:                              '*'
+}
+
+key 9 {
+    label:                              '9'
+    base:                               '9'
+    shift:                              '('
+}
+
+key SPACE {
+    label:                              ' '
+    base:                               ' '
+    alt, meta:                          fallback SEARCH
+    ctrl:                               fallback LANGUAGE_SWITCH
+}
+
+key ENTER {
+    label:                              '\n'
+    base:                               '\n'
+}
+
+key TAB {
+    label:                              '\t'
+    base:                               '\t'
+}
+
+key COMMA {
+    label:                              ','
+    base:                               ','
+    shift:                              '<'
+}
+
+key PERIOD {
+    label:                              '.'
+    base:                               '.'
+    shift:                              '>'
+}
+
+key SLASH {
+    label:                              '/'
+    base:                               '/'
+    shift:                              '?'
+}
+
+key MINUS {
+    label:                              '-'
+    base:                               '-'
+    shift:                              '_'
+}
+
+key EQUALS {
+    label:                              '='
+    base:                               '='
+    shift:                              '+'
+    ralt:                               '\\'
+    ralt+shift:                         '|'
+}
+
+key SEMICOLON {
+    label:                              ';'
+    base:                               ';'
+    shift:                              ':'
+}
+
+key APOSTROPHE {
+    label:                              '\''
+    base:                               '\''
+    shift:                              '"'
+}
+
+### Non-printing keys ###
+
+key ESCAPE {
+    base:                               fallback BACK
+    alt, meta:                          fallback HOME
+    ctrl:                               fallback MENU
+}
diff --git a/data/keyboards/Vendor_18d1_Product_5018.kl b/data/keyboards/Vendor_18d1_Product_5018.kl
new file mode 100644
index 0000000..e95ccb5
--- /dev/null
+++ b/data/keyboards/Vendor_18d1_Product_5018.kl
@@ -0,0 +1,84 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Key layout for Google Pixel C Keyboard
+#
+
+# Row 1
+key 2     1
+key 3     2
+key 4     3
+key 5     4
+key 6     5
+key 7     6
+key 8     7
+key 9     8
+key 10    9
+key 11    0
+key 12    MINUS
+key 14    DEL         # Backspace
+
+# Row 2
+key 15    TAB
+key 16    Q
+key 17    W
+key 18    E
+key 19    R
+key 20    T
+key 21    Y
+key 22    U
+key 23    I
+key 24    O
+key 25    P
+key 13    EQUALS
+key 28    ENTER
+
+# Row 3
+key 125   META_LEFT   # "Search key"
+key 30    A
+key 31    S
+key 32    D
+key 33    F
+key 34    G
+key 35    H
+key 36    J
+key 37    K
+key 38    L
+key 39    SEMICOLON
+key 40    APOSTROPHE
+
+# Row 4
+key 42    SHIFT_LEFT
+key 44    Z
+key 45    X
+key 46    C
+key 47    V
+key 48    B
+key 49    N
+key 50    M
+key 51    COMMA
+key 52    PERIOD
+key 53    SLASH
+key 54    SHIFT_RIGHT
+
+# Row 5
+key 29    CTRL_LEFT
+key 56    ALT_LEFT
+key 57    SPACE
+key 100   ALT_RIGHT
+key 103   DPAD_UP
+key 105   DPAD_LEFT
+key 106   DPAD_RIGHT
+key 108   DPAD_DOWN
diff --git a/docs/html/guide/topics/manifest/compatible-screens-element.jd b/docs/html/guide/topics/manifest/compatible-screens-element.jd
index 3606b15..de921d2 100644
--- a/docs/html/guide/topics/manifest/compatible-screens-element.jd
+++ b/docs/html/guide/topics/manifest/compatible-screens-element.jd
@@ -9,7 +9,7 @@
 <pre>
 &lt;<a href="#compatible-screens">compatible-screens</a>&gt;
     &lt;<a href="#screen">screen</a> android:<a href="#screenSize">screenSize</a>=["small" | "normal" | "large" | "xlarge"]
-            android:<a href="#screenDensity">screenDensity</a>=["ldpi" | "mdpi" | "hdpi" | "xhdpi"] /&gt;
+            android:<a href="#screenDensity">screenDensity</a>=["ldpi" | "mdpi" | "hdpi" | "xhdpi" | "xxhdpi" | "xxxhdpi"] /&gt;
     ...
 &lt;/compatible-screens&gt;
 </pre>
@@ -94,11 +94,9 @@
             <li>{@code mdpi}</li>
             <li>{@code hdpi}</li>
             <li>{@code xhdpi}</li>
+            <li>{@code xxhdpi}</li>
+            <li>{@code xxxhdpi}</li>
           </ul>
-          <p class="note"><strong>Note:</strong> This attribute currently does not accept
-          {@code xxhdpi} as a valid value, but you can instead specify {@code 480}
-          as the value, which is the approximate threshold for xhdpi screens.</p>
-
           <p>For information about the different screen densities, see <a
 href="{@docRoot}guide/practices/screens_support.html#range">Supporting Multiple Screens</a>.</p>
         </dd>
@@ -110,8 +108,8 @@
 <dt>example</dt>
 <dd>
 <p>If your application is compatible with only small and normal screens, regardless
-of screen density, then you must specify eight different {@code &lt;screen&gt;} elements,
-because each screen size has four different density configurations. You must declare each one of
+of screen density, then you must specify twelve different {@code &lt;screen&gt;} elements,
+because each screen size has six different density configurations. You must declare each one of
 these; any combination of size and density that you do <em>not</em> specify is considered a screen
 configuration with which your application is <em>not</em> compatible. Here's what the manifest
 entry looks like if your application is compatible with only small and normal screens:</p>
@@ -125,11 +123,15 @@
         &lt;screen android:screenSize="small" android:screenDensity="mdpi" />
         &lt;screen android:screenSize="small" android:screenDensity="hdpi" />
         &lt;screen android:screenSize="small" android:screenDensity="xhdpi" />
+        &lt;screen android:screenSize="small" android:screenDensity="xxhdpi" />
+        &lt;screen android:screenSize="small" android:screenDensity="xxxhdpi" />
         &lt;!-- all normal size screens -->
         &lt;screen android:screenSize="normal" android:screenDensity="ldpi" />
         &lt;screen android:screenSize="normal" android:screenDensity="mdpi" />
         &lt;screen android:screenSize="normal" android:screenDensity="hdpi" />
         &lt;screen android:screenSize="normal" android:screenDensity="xhdpi" />
+        &lt;screen android:screenSize="normal" android:screenDensity="xxhdpi" />
+        &lt;screen android:screenSize="normal" android:screenDensity="xxxhdpi" />
     &lt;/compatible-screens>
     &lt;application ... >
         ...
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index bbd4c30..1c2c940 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -479,11 +479,6 @@
  *     <td>{} </p></td>
  *     <td>This method can be called in any state and calling it does not change
  *         the object state. </p></td></tr>
- * <tr><td>setPlaybackRate</p></td>
- *     <td>any </p></td>
- *     <td>{} </p></td>
- *     <td>This method can be called in any state and calling it does not change
- *         the object state. </p></td></tr>
  * <tr><td>setPlaybackParams</p></td>
  *     <td>any </p></td>
  *     <td>{} </p></td>
@@ -2243,10 +2238,14 @@
         final InputStream fIs = is;
         final MediaFormat fFormat = format;
 
-        // Ensure all input streams are closed.  It is also a handy
-        // way to implement timeouts in the future.
-        synchronized(mOpenSubtitleSources) {
-            mOpenSubtitleSources.add(is);
+        if (is != null) {
+            // Ensure all input streams are closed.  It is also a handy
+            // way to implement timeouts in the future.
+            synchronized(mOpenSubtitleSources) {
+                mOpenSubtitleSources.add(is);
+            }
+        } else {
+            Log.w(TAG, "addSubtitleSource called with null InputStream");
         }
 
         // process each subtitle in its own thread
diff --git a/media/java/android/media/midi/IBluetoothMidiService.aidl b/media/java/android/media/midi/IBluetoothMidiService.aidl
new file mode 100644
index 0000000..fe5566d
--- /dev/null
+++ b/media/java/android/media/midi/IBluetoothMidiService.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.midi;
+
+import android.bluetooth.BluetoothDevice;
+import android.os.IBinder;
+
+/** @hide */
+interface IBluetoothMidiService
+{
+    IBinder addBluetoothDevice(in BluetoothDevice bluetoothDevice);
+}
diff --git a/media/java/android/media/midi/MidiManager.java b/media/java/android/media/midi/MidiManager.java
index 7197dc0..266b0d9 100644
--- a/media/java/android/media/midi/MidiManager.java
+++ b/media/java/android/media/midi/MidiManager.java
@@ -169,6 +169,13 @@
     /**
      * Registers a callback to receive notifications when MIDI devices are added and removed.
      *
+     * The {@link  DeviceCallback#onDeviceStatusChanged} method will be called immediately
+     * for any devices that have open ports. This allows applications to know which input
+     * ports are already in use and, therefore, unavailable.
+     *
+     * Applications should call {@link #getDevices} before registering the callback
+     * to get a list of devices already added.
+     *
      * @param callback a {@link DeviceCallback} for MIDI device notifications
      * @param handler The {@link android.os.Handler Handler} that will be used for delivering the
      *                device notifications. If handler is null, then the thread used for the
@@ -288,7 +295,6 @@
                         // fetch MidiDeviceInfo from the server
                         MidiDeviceInfo deviceInfo = server.getDeviceInfo();
                         device = new MidiDevice(deviceInfo, server, mService, mToken, deviceToken);
-                        sendOpenDeviceResponse(device, listenerF, handlerF);
                     } catch (RemoteException e) {
                         Log.e(TAG, "remote exception in getDeviceInfo()");
                     }
diff --git a/media/packages/BluetoothMidiService/Android.mk b/media/packages/BluetoothMidiService/Android.mk
index 2c9c3c5..0565925 100644
--- a/media/packages/BluetoothMidiService/Android.mk
+++ b/media/packages/BluetoothMidiService/Android.mk
@@ -3,7 +3,8 @@
 
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_SRC_FILES += \
+      $(call all-java-files-under,src)
 
 LOCAL_PACKAGE_NAME := BluetoothMidiService
 LOCAL_CERTIFICATE := platform
diff --git a/media/packages/BluetoothMidiService/AndroidManifest.xml b/media/packages/BluetoothMidiService/AndroidManifest.xml
index b0b389a..1cfd55d 100644
--- a/media/packages/BluetoothMidiService/AndroidManifest.xml
+++ b/media/packages/BluetoothMidiService/AndroidManifest.xml
@@ -8,7 +8,7 @@
 
     <application
         android:label="@string/app_name">
-        <service android:name="BluetoothMidiService"
+        <service android:name=".BluetoothMidiService"
             android:permission="android.permission.BIND_MIDI_DEVICE_SERVICE">
             <intent-filter>
                 <action android:name="android.media.midi.BluetoothMidiService" />
diff --git a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java
index e6d59e4..444705c 100644
--- a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java
+++ b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java
@@ -147,14 +147,22 @@
             // switch to receiving notifications after initial characteristic read
             mBluetoothGatt.setCharacteristicNotification(characteristic, true);
 
+            // Use writeType that requests acknowledgement.
+            // This improves compatibility with various BLE-MIDI devices.
+            int originalWriteType = characteristic.getWriteType();
+            characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
+
             BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
                     CLIENT_CHARACTERISTIC_CONFIG);
             if (descriptor != null) {
                 descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
-                mBluetoothGatt.writeDescriptor(descriptor);
+                boolean result = mBluetoothGatt.writeDescriptor(descriptor);
+                Log.d(TAG, "writeDescriptor returned " + result);
             } else {
                 Log.e(TAG, "No CLIENT_CHARACTERISTIC_CONFIG for device " + mBluetoothDevice);
             }
+
+            characteristic.setWriteType(originalWriteType);
         }
 
         @Override
diff --git a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiService.java b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiService.java
index fbde2b4..5541f9f 100644
--- a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiService.java
+++ b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiService.java
@@ -19,6 +19,7 @@
 import android.app.Service;
 import android.bluetooth.BluetoothDevice;
 import android.content.Intent;
+import android.media.midi.IBluetoothMidiService;
 import android.media.midi.MidiManager;
 import android.os.IBinder;
 import android.util.Log;
@@ -34,24 +35,31 @@
 
     @Override
     public IBinder onBind(Intent intent) {
-        if (MidiManager.BLUETOOTH_MIDI_SERVICE_INTENT.equals(intent.getAction())) {
-            BluetoothDevice bluetoothDevice = (BluetoothDevice)intent.getParcelableExtra("device");
+        // Return the interface
+        return mBinder;
+    }
+
+
+    private final IBluetoothMidiService.Stub mBinder = new IBluetoothMidiService.Stub() {
+
+        public IBinder addBluetoothDevice(BluetoothDevice bluetoothDevice) {
+            BluetoothMidiDevice device;
             if (bluetoothDevice == null) {
-                Log.e(TAG, "no BluetoothDevice in onBind intent");
+                Log.e(TAG, "no BluetoothDevice in addBluetoothDevice()");
                 return null;
             }
-
-            BluetoothMidiDevice device;
             synchronized (mDeviceServerMap) {
                 device = mDeviceServerMap.get(bluetoothDevice);
                 if (device == null) {
-                    device = new BluetoothMidiDevice(this, bluetoothDevice, this);
+                    device = new BluetoothMidiDevice(BluetoothMidiService.this,
+                            bluetoothDevice, BluetoothMidiService.this);
+                    mDeviceServerMap.put(bluetoothDevice, device);
                 }
             }
             return device.getBinder();
         }
-        return null;
-    }
+
+    };
 
     void deviceClosed(BluetoothDevice device) {
         synchronized (mDeviceServerMap) {
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index 382b2d0..ff14f94 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -3,6 +3,7 @@
 
     <uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />
     <uses-permission android:name="android.permission.REMOVE_TASKS" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
 
     <application
         android:name=".DocumentsApplication"
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
index 506ec5833..f270d9e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
@@ -32,6 +32,7 @@
 import android.os.CancellationSignal;
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
+import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.provider.DocumentsContract;
@@ -65,6 +66,8 @@
     // TODO: Move it to a shared file when more operations are implemented.
     public static final int FAILURE_COPY = 1;
 
+    private PowerManager mPowerManager;
+
     private NotificationManager mNotificationManager;
     private Notification.Builder mProgressBuilder;
 
@@ -129,10 +132,14 @@
             return;
         }
 
+        final PowerManager.WakeLock wakeLock = mPowerManager
+                .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
         final ArrayList<DocumentInfo> srcs = intent.getParcelableArrayListExtra(EXTRA_SRC_LIST);
         final DocumentStack stack = intent.getParcelableExtra(EXTRA_STACK);
 
         try {
+            wakeLock.acquire();
+
             // Acquire content providers.
             mSrcClient = DocumentsApplication.acquireUnstableProviderOrThrow(getContentResolver(),
                     srcs.get(0).authority);
@@ -151,6 +158,8 @@
             ContentProviderClient.releaseQuietly(mSrcClient);
             ContentProviderClient.releaseQuietly(mDstClient);
 
+            wakeLock.release();
+
             // Dismiss the ongoing copy notification when the copy is done.
             mNotificationManager.cancel(mJobId, 0);
 
@@ -179,7 +188,8 @@
     @Override
     public void onCreate() {
         super.onCreate();
-        mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+        mPowerManager = getSystemService(PowerManager.class);
+        mNotificationManager = getSystemService(NotificationManager.class);
     }
 
     /**
diff --git a/packages/SystemUI/res/values-en/donottranslate.xml b/packages/SystemUI/res/values-en/donottranslate.xml
deleted file mode 100644
index 9f04e1f..0000000
--- a/packages/SystemUI/res/values-en/donottranslate.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-
-<resources>
-    <!-- DO NOT TRANSLATE - temporary hack to show the speed-less label if no translation is available -->
-    <item type="string" name="keyguard_indication_charging_time_fast_if_translated">@string/keyguard_indication_charging_time_fast</item>
-    <!-- DO NOT TRANSLATE - temporary hack to show the speed-less label if no translation is available -->
-    <item type="string" name="keyguard_indication_charging_time_slowly_if_translated">@string/keyguard_indication_charging_time_slowly</item>
-</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/donottranslate.xml b/packages/SystemUI/res/values/donottranslate.xml
index 30ff704..351a1fd 100644
--- a/packages/SystemUI/res/values/donottranslate.xml
+++ b/packages/SystemUI/res/values/donottranslate.xml
@@ -20,10 +20,4 @@
     <!-- Date format for display: should match the lockscreen in /policy.  -->
     <string name="system_ui_date_pattern">@*android:string/system_ui_date_pattern</string>
 
-    <!-- DO NOT TRANSLATE - temporary hack to show the speed-less label if no translation is available -->
-    <item type="string" name="keyguard_indication_charging_time_fast_if_translated">@string/keyguard_indication_charging_time</item>
-
-    <!-- DO NOT TRANSLATE - temporary hack to show the speed-less label if no translation is available -->
-    <item type="string" name="keyguard_indication_charging_time_slowly_if_translated">@string/keyguard_indication_charging_time</item>
-
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
index 803a014..728d558 100644
--- a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
@@ -21,6 +21,7 @@
 import android.media.AudioManager;
 import android.media.MediaPlayer;
 import android.media.MediaPlayer.OnCompletionListener;
+import android.media.MediaPlayer.OnErrorListener;
 import android.net.Uri;
 import android.os.Looper;
 import android.os.PowerManager;
@@ -36,7 +37,7 @@
  * - whenever audio is played, audio focus is requested,
  * - whenever audio playback is stopped or the playback completed, audio focus is abandoned.
  */
-public class NotificationPlayer implements OnCompletionListener {
+public class NotificationPlayer implements OnCompletionListener, OnErrorListener {
     private static final int PLAY = 1;
     private static final int STOP = 2;
     private static final boolean mDebug = false;
@@ -112,6 +113,7 @@
                     //  done playing. This class should be modified to use a single thread, on which
                     //  command are issued, and on which it receives the completion callbacks.
                     player.setOnCompletionListener(NotificationPlayer.this);
+                    player.setOnErrorListener(NotificationPlayer.this);
                     player.start();
                     if (mPlayer != null) {
                         mPlayer.release();
@@ -245,6 +247,13 @@
         }
     }
 
+    public boolean onError(MediaPlayer mp, int what, int extra) {
+        Log.e(mTag, "error " + what + " (extra=" + extra + ") playing notification");
+        // error happened, handle it just like a completion
+        onCompletion(mp);
+        return true;
+    }
+
     private String mTag;
     private CmdThread mThread;
     private CreationAndCompletionThread mCompletionThread;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index b330582..e4a37fb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs;
 
+import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.drawable.Animatable;
@@ -320,6 +321,7 @@
 
     public interface Host {
         void startActivityDismissingKeyguard(Intent intent);
+        void startActivityDismissingKeyguard(PendingIntent intent);
         void warn(String message, Throwable t);
         void collapsePanels();
         Looper getLooper();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
index 3d0dc7b..c7f2284 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
@@ -99,7 +99,7 @@
         try {
             if (pi != null) {
                 if (pi.isActivity()) {
-                    getHost().startActivityDismissingKeyguard(pi.getIntent());
+                    getHost().startActivityDismissingKeyguard(pi);
                 } else {
                     pi.send();
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index 2e0b80a..be618e2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -162,6 +162,14 @@
                 mVelocityTracker.addMovement(createMotionEventForStackScroll(ev));
                 break;
             }
+            case MotionEvent.ACTION_POINTER_DOWN: {
+                final int index = ev.getActionIndex();
+                mActivePointerId = ev.getPointerId(index);
+                mLastMotionX = (int) ev.getX(index);
+                mLastMotionY = (int) ev.getY(index);
+                mLastP = mSv.mLayoutAlgorithm.screenYToCurveProgress(mLastMotionY);
+                break;
+            }
             case MotionEvent.ACTION_MOVE: {
                 if (mActivePointerId == INACTIVE_POINTER_ID) break;
 
@@ -187,6 +195,20 @@
                 mLastP = mSv.mLayoutAlgorithm.screenYToCurveProgress(mLastMotionY);
                 break;
             }
+            case MotionEvent.ACTION_POINTER_UP: {
+                int pointerIndex = ev.getActionIndex();
+                int pointerId = ev.getPointerId(pointerIndex);
+                if (pointerId == mActivePointerId) {
+                    // Select a new active pointer id and reset the motion state
+                    final int newPointerIndex = (pointerIndex == 0) ? 1 : 0;
+                    mActivePointerId = ev.getPointerId(newPointerIndex);
+                    mLastMotionX = (int) ev.getX(newPointerIndex);
+                    mLastMotionY = (int) ev.getY(newPointerIndex);
+                    mLastP = mSv.mLayoutAlgorithm.screenYToCurveProgress(mLastMotionY);
+                    mVelocityTracker.clear();
+                }
+                break;
+            }
             case MotionEvent.ACTION_CANCEL:
             case MotionEvent.ACTION_UP: {
                 // Animate the scroll back if we've cancelled
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index eecac63..9ff86eb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1490,6 +1490,59 @@
         return true;
     }
 
+    public void startPendingIntentDismissingKeyguard(final PendingIntent intent) {
+        if (!isDeviceProvisioned()) return;
+
+        final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
+        final boolean afterKeyguardGone = intent.isActivity()
+                && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
+                mCurrentUserId);
+        dismissKeyguardThenExecute(new OnDismissAction() {
+            public boolean onDismiss() {
+                new Thread() {
+                    @Override
+                    public void run() {
+                        try {
+                            if (keyguardShowing && !afterKeyguardGone) {
+                                ActivityManagerNative.getDefault()
+                                        .keyguardWaitingForActivityDrawn();
+                            }
+
+                            // The intent we are sending is for the application, which
+                            // won't have permission to immediately start an activity after
+                            // the user switches to home.  We know it is safe to do at this
+                            // point, so make sure new activity switches are now allowed.
+                            ActivityManagerNative.getDefault().resumeAppSwitches();
+                        } catch (RemoteException e) {
+                        }
+
+                        try {
+                            intent.send();
+                        } catch (PendingIntent.CanceledException e) {
+                            // the stack trace isn't very helpful here.
+                            // Just log the exception message.
+                            Log.w(TAG, "Sending intent failed: " + e);
+
+                            // TODO: Dismiss Keyguard.
+                        }
+                        if (intent.isActivity()) {
+                            mAssistManager.hideAssist();
+                            overrideActivityPendingAppTransition(keyguardShowing
+                                    && !afterKeyguardGone);
+                        }
+                    }
+                }.start();
+
+                // close the shade if it was open
+                animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
+                        true /* force */, true /* delayed */);
+                visibilityChanged(false);
+
+                return true;
+            }
+        }, afterKeyguardGone);
+    }
+
     private final class NotificationClicker implements View.OnClickListener {
         public void onClick(final View v) {
             if (!(v instanceof ExpandableNotificationRow)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 50d274d..fd84345 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -200,12 +200,12 @@
         switch (mChargingSpeed) {
             case KeyguardUpdateMonitor.BatteryStatus.CHARGING_FAST:
                 chargingId = hasChargingTime
-                        ? R.string.keyguard_indication_charging_time_fast_if_translated
+                        ? R.string.keyguard_indication_charging_time_fast
                         : R.string.keyguard_plugged_in_charging_fast;
                 break;
             case KeyguardUpdateMonitor.BatteryStatus.CHARGING_SLOWLY:
                 chargingId = hasChargingTime
-                        ? R.string.keyguard_indication_charging_time_slowly_if_translated
+                        ? R.string.keyguard_indication_charging_time_slowly
                         : R.string.keyguard_plugged_in_charging_slowly;
                 break;
             default:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index f7c3c67..cc30882 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -250,6 +250,7 @@
     @Override
     public void setNoSims(boolean show) {
         mNoSimsVisible = show && !mBlockMobile;
+        apply();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java
index 9ef320bc..8f689c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.app.PendingIntent;
 import android.content.Intent;
 
 /**
@@ -24,6 +25,7 @@
  * Keyguard.
  */
 public interface ActivityStarter {
+    void startPendingIntentDismissingKeyguard(PendingIntent intent);
     void startActivity(Intent intent, boolean dismissShade);
     void startActivity(Intent intent, boolean dismissShade, Callback callback);
     void preventNextAnimation();
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 8465101..73361bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -3210,6 +3210,15 @@
         return !isDeviceProvisioned() || (mDisabled1 & StatusBarManager.DISABLE_SEARCH) != 0;
     }
 
+    public void postStartActivityDismissingKeyguard(final PendingIntent intent) {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                startPendingIntentDismissingKeyguard(intent);
+            }
+        });
+    }
+
     public void postStartActivityDismissingKeyguard(final Intent intent, int delay) {
         mHandler.postDelayed(new Runnable() {
             @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 12434ac..e66c63b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
@@ -134,6 +135,11 @@
     }
 
     @Override
+    public void startActivityDismissingKeyguard(PendingIntent intent) {
+        mStatusBar.postStartActivityDismissingKeyguard(intent);
+    }
+
+    @Override
     public void warn(String message, Throwable t) {
         // already logged
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
index e9c4e49..971978d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -527,8 +527,8 @@
             startBatteryActivity();
         } else if (v == mAlarmStatus && mNextAlarm != null) {
             PendingIntent showIntent = mNextAlarm.getShowIntent();
-            if (showIntent != null && showIntent.isActivity()) {
-                mActivityStarter.startActivity(showIntent.getIntent(), true /* dismissShade */);
+            if (showIntent != null) {
+                mActivityStarter.startPendingIntentDismissingKeyguard(showIntent);
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index 7836411..e9f1095 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -104,6 +104,7 @@
     private final SpTexts mSpTexts;
     private final SparseBooleanArray mDynamic = new SparseBooleanArray();
     private final KeyguardManager mKeyguard;
+    private final AudioManager mAudioManager;
     private final int mExpandButtonAnimationDuration;
     private final ZenFooter mZenFooter;
     private final LayoutTransition mLayoutTransition;
@@ -135,6 +136,7 @@
         mCallback = callback;
         mSpTexts = new SpTexts(mContext);
         mKeyguard = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
+        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
 
         mDialog = new CustomDialog(mContext);
 
@@ -636,7 +638,8 @@
     private void updateFooterH() {
         if (D.BUG) Log.d(TAG, "updateFooterH");
         final boolean wasVisible = mZenFooter.getVisibility() == View.VISIBLE;
-        final boolean visible = mState.zenMode != Global.ZEN_MODE_OFF;
+        final boolean visible = mState.zenMode != Global.ZEN_MODE_OFF
+                && mAudioManager.isStreamAffectedByRingerMode(mActiveStream);
         if (wasVisible != visible && !visible) {
             prepareForCollapse();
         }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 6190a5a..4c03143 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -946,13 +946,13 @@
             uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
         }
 
-        if ((uidRules & RULE_REJECT_ALL) != 0
-                || (networkCostly && (uidRules & RULE_REJECT_METERED) != 0)) {
+        if (uidRules == RULE_REJECT_ALL) {
             return true;
+        } else if ((uidRules == RULE_REJECT_METERED) && networkCostly) {
+            return true;
+        } else {
+            return false;
         }
-
-        // no restrictive rules; network is visible
-        return false;
     }
 
     /**
@@ -3212,6 +3212,11 @@
             final String profileName = new String(mKeyStore.get(Credentials.LOCKDOWN_VPN));
             final VpnProfile profile = VpnProfile.decode(
                     profileName, mKeyStore.get(Credentials.VPN + profileName));
+            if (profile == null) {
+                Slog.e(TAG, "Lockdown VPN configured invalid profile " + profileName);
+                setLockdownTracker(null);
+                return true;
+            }
             int user = UserHandle.getUserId(Binder.getCallingUid());
             synchronized(mVpns) {
                 setLockdownTracker(new LockdownVpnTracker(mContext, mNetd, this, mVpns.get(user),
@@ -3724,7 +3729,7 @@
             synchronized(mRulesLock) {
                 uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
             }
-            if ((uidRules & (RULE_REJECT_METERED | RULE_REJECT_ALL)) != 0) {
+            if (uidRules != RULE_ALLOW_ALL) {
                 // we could silently fail or we can filter the available nets to only give
                 // them those they have access to.  Chose the more useful
                 networkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 5239ede..230c7c9 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -244,6 +244,14 @@
             if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
                 int plugged = intent.getIntExtra("plugged", 0);
                 updateChargingLocked(plugged != 0);
+            } else if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
+                if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+                    Uri data = intent.getData();
+                    String ssp;
+                    if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
+                        removePowerSaveWhitelistAppInternal(ssp);
+                    }
+                }
             } else if (ACTION_STEP_IDLE_STATE.equals(intent.getAction())) {
                 synchronized (DeviceIdleController.this) {
                     stepIdleStateLocked();
@@ -979,6 +987,10 @@
                 filter.addAction(Intent.ACTION_BATTERY_CHANGED);
                 filter.addAction(ACTION_STEP_IDLE_STATE);
                 getContext().registerReceiver(mReceiver, filter);
+                filter = new IntentFilter();
+                filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+                filter.addDataScheme("package");
+                getContext().registerReceiver(mReceiver, filter);
 
                 mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
 
@@ -991,7 +1003,10 @@
     public boolean addPowerSaveWhitelistAppInternal(String name) {
         synchronized (this) {
             try {
-                ApplicationInfo ai = getContext().getPackageManager().getApplicationInfo(name, 0);
+                ApplicationInfo ai = getContext().getPackageManager().getApplicationInfo(name,
+                        PackageManager.GET_UNINSTALLED_PACKAGES
+                                | PackageManager.GET_DISABLED_COMPONENTS
+                                | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS);
                 if (mPowerSaveWhitelistUserApps.put(name, UserHandle.getAppId(ai.uid)) == null) {
                     reportPowerSaveWhitelistChangedLocked();
                     updateWhitelistAppIdsLocked();
@@ -1595,7 +1610,6 @@
             } catch (IOException e) {
             }
         }
-
     }
 
     private void readConfigFileLocked(XmlPullParser parser) {
@@ -1624,7 +1638,10 @@
                     String name = parser.getAttributeValue(null, "n");
                     if (name != null) {
                         try {
-                            ApplicationInfo ai = pm.getApplicationInfo(name, 0);
+                            ApplicationInfo ai = pm.getApplicationInfo(name,
+                                    PackageManager.GET_UNINSTALLED_PACKAGES
+                                            | PackageManager.GET_DISABLED_COMPONENTS
+                                            | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS);
                             mPowerSaveWhitelistUserApps.put(ai.packageName,
                                     UserHandle.getAppId(ai.uid));
                         } catch (PackageManager.NameNotFoundException e) {
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 4e11070..6d07a57 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -40,6 +40,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
 
+import android.annotation.Nullable;
 import android.app.ActivityManagerNative;
 import android.app.AppGlobals;
 import android.app.AlertDialog;
@@ -286,8 +287,19 @@
     boolean mSystemReady;
 
     /**
-     * Id of the currently selected input method.
+     * Id obtained with {@link InputMethodInfo#getId()} for the currently selected input method.
+     * method.  This is to be synchronized with the secure settings keyed with
+     * {@link Settings.Secure#DEFAULT_INPUT_METHOD}.
+     *
+     * <p>This can be transiently {@code null} when the system is re-initializing input method
+     * settings, e.g., the system locale is just changed.</p>
+     *
+     * <p>Note that {@link #mCurId} is used to track which IME is being connected to
+     * {@link InputMethodManagerService}.</p>
+     *
+     * @see #mCurId
      */
+    @Nullable
     String mCurMethodId;
 
     /**
@@ -317,9 +329,14 @@
     EditorInfo mCurAttribute;
 
     /**
-     * The input method ID of the input method service that we are currently
+     * Id obtained with {@link InputMethodInfo#getId()} for the input method that we are currently
      * connected to or in the process of connecting to.
+     *
+     * <p>This can be {@code null} when no input method is connected.</p>
+     *
+     * @see #mCurMethodId
      */
+    @Nullable
     String mCurId;
 
     /**
@@ -967,7 +984,6 @@
                 || (newLocale != null && !newLocale.equals(mLastSystemLocale))) {
             if (!updateOnlyWhenLocaleChanged) {
                 hideCurrentInputLocked(0, null);
-                mCurMethodId = null;
                 unbindCurrentMethodLocked(true, false);
             }
             if (DEBUG) {
@@ -1523,7 +1539,11 @@
         channel.dispose();
     }
 
-    void unbindCurrentMethodLocked(boolean reportToClient, boolean savePosition) {
+    void unbindCurrentMethodLocked(boolean resetCurrentMethodAndClient, boolean savePosition) {
+        if (resetCurrentMethodAndClient) {
+            mCurMethodId = null;
+        }
+
         if (mVisibleBound) {
             mContext.unbindService(mVisibleConnection);
             mVisibleBound = false;
@@ -1550,9 +1570,8 @@
         mCurId = null;
         clearCurMethodLocked();
 
-        if (reportToClient && mCurClient != null) {
-            executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
-                    MSG_UNBIND_METHOD, mCurSeq, mCurClient.client));
+        if (resetCurrentMethodAndClient) {
+            unbindCurrentClientLocked();
         }
     }
 
@@ -1903,13 +1922,11 @@
                 setInputMethodLocked(id, mSettings.getSelectedInputMethodSubtypeId(id));
             } catch (IllegalArgumentException e) {
                 Slog.w(TAG, "Unknown input method from prefs: " + id, e);
-                mCurMethodId = null;
                 unbindCurrentMethodLocked(true, false);
             }
             mShortcutInputMethodsAndSubtypes.clear();
         } else {
             // There is no longer an input method set, so stop any current one.
-            mCurMethodId = null;
             unbindCurrentMethodLocked(true, false);
         }
         // Here is not the perfect place to reset the switching controller. Ideally
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index af6f185..98c1d19 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -3921,7 +3921,7 @@
         mLockTaskModeTasks.add(task);
 
         if (task.mLockTaskUid == -1) {
-            task.mLockTaskUid = task.mCallingUid;
+            task.mLockTaskUid = task.effectiveUid;
         }
 
         if (andResume) {
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index bb4dbc3..835ba17 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -74,6 +74,7 @@
 
     // Set to true when the animation context has been fully prepared.
     private boolean mPrepared;
+    private boolean mCreatedResources;
     private int mMode;
 
     private final DisplayManagerInternal mDisplayManagerInternal;
@@ -169,6 +170,7 @@
         }
 
         // Done.
+        mCreatedResources = true;
         mPrepared = true;
 
         // Dejanking optimization.
@@ -313,6 +315,34 @@
     }
 
     /**
+     * Dismisses the color fade animation resources.
+     *
+     * This function destroys the resources that are created for the color fade
+     * animation but does not clean up the surface.
+     */
+    public void dismissResources() {
+        if (DEBUG) {
+            Slog.d(TAG, "dismissResources");
+        }
+
+        if (mCreatedResources) {
+            attachEglContext();
+            try {
+                destroyScreenshotTexture();
+                destroyGLShaders();
+                destroyGLBuffers();
+                destroyEglSurface();
+            } finally {
+                detachEglContext();
+            }
+            // This is being called with no active context so shouldn't be
+            // needed but is safer to not change for now.
+            GLES20.glFlush();
+            mCreatedResources = false;
+        }
+    }
+
+    /**
      * Dismisses the color fade animation surface and cleans up.
      *
      * To prevent stray photons from leaking out after the color fade has been
@@ -325,17 +355,8 @@
         }
 
         if (mPrepared) {
-            attachEglContext();
-            try {
-                destroyScreenshotTexture();
-                destroyGLShaders();
-                destroyGLBuffers();
-                destroyEglSurface();
-            } finally {
-                detachEglContext();
-            }
+            dismissResources();
             destroySurface();
-            GLES20.glFlush();
             mPrepared = false;
         }
     }
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 452378f..7b49530 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -837,6 +837,7 @@
         if (mPendingScreenOff && target != Display.STATE_OFF) {
             setScreenState(Display.STATE_OFF);
             mPendingScreenOff = false;
+            mPowerState.dismissColorFadeResources();
         }
 
         if (target == Display.STATE_ON) {
@@ -910,6 +911,7 @@
                 // A black surface is already hiding the contents of the screen.
                 setScreenState(Display.STATE_OFF);
                 mPendingScreenOff = false;
+                mPowerState.dismissColorFadeResources();
             } else if (performScreenOffTransition
                     && mPowerState.prepareColorFade(mContext,
                             mColorFadeFadesConfig ?
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index 2eabd32..9862516 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -187,7 +187,7 @@
     }
 
     /**
-     * Dismisses the electron beam surface.
+     * Dismisses the color fade surface.
      */
     public void dismissColorFade() {
         mColorFade.dismiss();
@@ -195,6 +195,13 @@
         mColorFadeReady = true;
     }
 
+   /**
+     * Dismisses the color fade resources.
+     */
+    public void dismissColorFadeResources() {
+        mColorFade.dismissResources();
+    }
+
     /**
      * Sets the level of the electron beam steering current.
      *
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index ecda36a..06bd583 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -443,13 +443,16 @@
     }
 
     /**
-     * A job is rescheduled with exponential back-off if the client requests this from their
-     * execution logic.
-     * A caveat is for idle-mode jobs, for which the idle-mode constraint will usurp the
-     * timeliness of the reschedule. For an idle-mode job, no deadline is given.
+     * Reschedules the given job based on the job's backoff policy. It doesn't make sense to
+     * specify an override deadline on a failed job (the failed job will run even though it's not
+     * ready), so we reschedule it with {@link JobStatus#NO_LATEST_RUNTIME}, but specify that any
+     * ready job with {@link JobStatus#numFailures} > 0 will be executed.
+     *
      * @param failureToReschedule Provided job status that we will reschedule.
      * @return A newly instantiated JobStatus with the same constraints as the last job except
      * with adjusted timing constraints.
+     *
+     * @see JobHandler#maybeQueueReadyJobsForExecutionLockedH
      */
     private JobStatus getRescheduleJobForFailure(JobStatus failureToReschedule) {
         final long elapsedNowMillis = SystemClock.elapsedRealtime();
@@ -479,8 +482,9 @@
     }
 
     /**
-     * Called after a periodic has executed so we can to re-add it. We take the last execution time
-     * of the job to be the time of completion (i.e. the time at which this function is called).
+     * Called after a periodic has executed so we can reschedule it. We take the last execution
+     * time of the job to be the time of completion (i.e. the time at which this function is
+     * called).
      * This could be inaccurate b/c the job can run for as long as
      * {@link com.android.server.job.JobServiceContext#EXECUTING_TIMESLICE_MILLIS}, but will lead
      * to underscheduling at least, rather than if we had taken the last execution time to be the
@@ -491,7 +495,12 @@
     private JobStatus getRescheduleJobForPeriodic(JobStatus periodicToReschedule) {
         final long elapsedNow = SystemClock.elapsedRealtime();
         // Compute how much of the period is remaining.
-        long runEarly = Math.max(periodicToReschedule.getLatestRunTimeElapsed() - elapsedNow, 0);
+        long runEarly = 0L;
+
+        // If this periodic was rescheduled it won't have a deadline.
+        if (periodicToReschedule.hasDeadlineConstraint()) {
+            runEarly = Math.max(periodicToReschedule.getLatestRunTimeElapsed() - elapsedNow, 0L);
+        }
         long newEarliestRunTimeElapsed = elapsedNow + runEarly;
         long period = periodicToReschedule.getJob().getIntervalMillis();
         long newLatestRuntimeElapsed = newEarliestRunTimeElapsed + period;
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index d26319b..d7fafe3 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -68,7 +68,7 @@
     private static final int defaultMaxActiveJobsPerService =
             ActivityManager.isLowRamDeviceStatic() ? 1 : 3;
     /** Amount of time a job is allowed to execute for before being considered timed-out. */
-    private static final long EXECUTING_TIMESLICE_MILLIS = 10 * 60 * 1000;
+    private static final long EXECUTING_TIMESLICE_MILLIS = 10 * 60 * 1000;  // 10mins.
     /** Amount of time the JobScheduler will wait for a response from an app for a message. */
     private static final long OP_TIMEOUT_MILLIS = 8 * 1000;
 
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 8845d6e..893a24c 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -39,17 +39,17 @@
 import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_STANDBY;
-import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
 import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW;
+import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
 import static android.net.NetworkPolicyManager.FIREWALL_RULE_DENY;
 import static android.net.NetworkPolicyManager.POLICY_ALLOW_BACKGROUND_BATTERY_SAVE;
 import static android.net.NetworkPolicyManager.POLICY_NONE;
 import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
+import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
 import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
+import static android.net.NetworkPolicyManager.RULE_UNKNOWN;
 import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
-import static android.net.NetworkPolicyManager.dumpPolicy;
-import static android.net.NetworkPolicyManager.dumpRules;
 import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
 import static android.net.NetworkTemplate.MATCH_MOBILE_4G;
 import static android.net.NetworkTemplate.MATCH_MOBILE_ALL;
@@ -139,6 +139,7 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
+import android.util.DebugUtils;
 import android.util.Log;
 import android.util.NtpTrustedTime;
 import android.util.Pair;
@@ -148,8 +149,6 @@
 import android.util.TrustedTime;
 import android.util.Xml;
 
-import com.android.server.DeviceIdleController;
-import com.android.server.EventLogTags;
 import libcore.io.IoUtils;
 
 import com.android.internal.R;
@@ -157,6 +156,8 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.DeviceIdleController;
+import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
 import com.google.android.collect.Lists;
 
@@ -285,6 +286,10 @@
     final SparseIntArray mUidPolicy = new SparseIntArray();
     /** Currently derived rules for each UID. */
     final SparseIntArray mUidRules = new SparseIntArray();
+
+    final SparseIntArray mUidFirewallStandbyRules = new SparseIntArray();
+    final SparseIntArray mUidFirewallDozableRules = new SparseIntArray();
+
     /** Set of states for the child firewall chains. True if the chain is active. */
     final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray();
 
@@ -457,14 +462,8 @@
             // read policy from disk
             readPolicyLocked();
 
-            if (mRestrictBackground || mRestrictPower || mDeviceIdleMode) {
-                updateRulesForGlobalChangeLocked(false);
-                updateNotificationsLocked();
-            } else {
-                // If we are not in any special mode, we just need to make sure the current
-                // app idle state is updated.
-                updateRulesForAppIdleLocked();
-            }
+            updateRulesForGlobalChangeLocked(false);
+            updateNotificationsLocked();
         }
 
         updateScreenOn();
@@ -1888,7 +1887,9 @@
             if (mDeviceIdleMode != enabled) {
                 mDeviceIdleMode = enabled;
                 if (mSystemReady) {
-                    updateRulesForDeviceIdleLocked();
+                    // Device idle change means we need to rebuild rules for all
+                    // known apps, so do a global refresh.
+                    updateRulesForGlobalChangeLocked(false);
                 }
                 if (enabled) {
                     EventLogTags.writeDeviceIdleOnPhase("net");
@@ -2026,7 +2027,7 @@
                 fout.print("UID=");
                 fout.print(uid);
                 fout.print(" policy=");
-                dumpPolicy(fout, policy);
+                fout.print(DebugUtils.flagsToString(NetworkPolicyManager.class, "POLICY_", policy));
                 fout.println();
             }
             fout.decreaseIndent();
@@ -2071,18 +2072,14 @@
                 fout.print("UID=");
                 fout.print(uid);
 
-                int state = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
+                final int state = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
                 fout.print(" state=");
                 fout.print(state);
                 fout.print(state <= ActivityManager.PROCESS_STATE_TOP ? " (fg)" : " (bg)");
 
-                fout.print(" rules=");
-                final int rulesIndex = mUidRules.indexOfKey(uid);
-                if (rulesIndex < 0) {
-                    fout.print("UNKNOWN");
-                } else {
-                    dumpRules(fout, mUidRules.valueAt(rulesIndex));
-                }
+                final int rule = mUidRules.get(uid, RULE_UNKNOWN);
+                fout.print(" rule=");
+                fout.print(DebugUtils.valueToString(NetworkPolicyManager.class, "RULE_", rule));
 
                 fout.println();
             }
@@ -2117,7 +2114,7 @@
             updateRulesForUidStateChangeLocked(uid, oldUidState, uidState);
             if (mDeviceIdleMode && isProcStateAllowedWhileIdle(oldUidState)
                     != isProcStateAllowedWhileIdle(uidState)) {
-                updateRulesForDeviceIdleLocked();
+                updateRuleForDeviceIdleLocked(uid);
             }
         }
     }
@@ -2131,7 +2128,7 @@
                 updateRulesForUidStateChangeLocked(uid, oldUidState,
                         ActivityManager.PROCESS_STATE_CACHED_EMPTY);
                 if (mDeviceIdleMode) {
-                    updateRulesForDeviceIdleLocked();
+                    updateRuleForDeviceIdleLocked(uid);
                 }
             }
         }
@@ -2178,7 +2175,8 @@
         if (mDeviceIdleMode) {
             // sync the whitelists before enable dozable chain.  We don't care about the rules if
             // we are disabling the chain.
-            SparseIntArray uidRules = new SparseIntArray();
+            final SparseIntArray uidRules = mUidFirewallDozableRules;
+            uidRules.clear();
             final List<UserInfo> users = mUserManager.getUsers();
             for (int ui = users.size() - 1; ui >= 0; ui--) {
                 UserInfo user = users.get(ui);
@@ -2202,6 +2200,7 @@
             }
             setUidFirewallRules(FIREWALL_CHAIN_DOZABLE, uidRules);
         }
+
         enableFirewallChainLocked(FIREWALL_CHAIN_DOZABLE, mDeviceIdleMode);
     }
 
@@ -2215,11 +2214,15 @@
                 setUidFirewallRule(FIREWALL_CHAIN_DOZABLE, uid, FIREWALL_RULE_DEFAULT);
             }
         }
+
+        updateRulesForUidLocked(uid);
     }
 
     void updateRulesForAppIdleLocked() {
+        final SparseIntArray uidRules = mUidFirewallStandbyRules;
+        uidRules.clear();
+
         // Fully update the app idle firewall chain.
-        SparseIntArray uidRules = new SparseIntArray();
         final List<UserInfo> users = mUserManager.getUsers();
         for (int ui = users.size() - 1; ui >= 0; ui--) {
             UserInfo user = users.get(ui);
@@ -2230,6 +2233,7 @@
                 }
             }
         }
+
         setUidFirewallRules(FIREWALL_CHAIN_STANDBY, uidRules);
     }
 
@@ -2242,11 +2246,14 @@
         } else {
             setUidFirewallRule(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DEFAULT);
         }
+
+        updateRulesForUidLocked(uid);
     }
 
     void updateRulesForAppIdleParoleLocked() {
         boolean enableChain = !mUsageStats.isAppIdleParoleOn();
         enableFirewallChainLocked(FIREWALL_CHAIN_STANDBY, enableChain);
+        updateRulesForUidsLocked(mUidFirewallStandbyRules);
     }
 
     /**
@@ -2316,6 +2323,12 @@
         return true;
     }
 
+    void updateRulesForUidsLocked(SparseIntArray uids) {
+        for (int i = 0; i < uids.size(); i++) {
+            updateRulesForUidLocked(uids.keyAt(i));
+        }
+    }
+
     /**
      * Applies network rules to bandwidth and firewall controllers based on uid policy.
      * @param uid The uid for which to apply the latest policy
@@ -2337,8 +2350,7 @@
         final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE);
         final boolean uidForeground = isUidForegroundLocked(uid);
 
-        // derive active rules based on policy and active state
-
+        // Derive active rules based on policy and active state
         int appId = UserHandle.getAppId(uid);
         int uidRules = RULE_ALLOW_ALL;
         if (!uidForeground && (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) {
@@ -2361,20 +2373,27 @@
             }
         }
 
-        final int oldRules = mUidRules.get(uid);
+        // Check dozable state, which is whitelist
+        if (mFirewallChainStates.get(FIREWALL_CHAIN_DOZABLE)
+                && mUidFirewallDozableRules.get(uid, FIREWALL_RULE_DEFAULT) != FIREWALL_RULE_ALLOW) {
+            uidRules = RULE_REJECT_ALL;
+        }
 
+        // Check standby state, which is blacklist
+        if (mFirewallChainStates.get(FIREWALL_CHAIN_STANDBY)
+                && mUidFirewallStandbyRules.get(uid, FIREWALL_RULE_DEFAULT) == FIREWALL_RULE_DENY) {
+            uidRules = RULE_REJECT_ALL;
+        }
+
+        final int oldRules = mUidRules.get(uid);
         if (uidRules == RULE_ALLOW_ALL) {
             mUidRules.delete(uid);
         } else {
             mUidRules.put(uid, uidRules);
         }
 
-        // Update bandwidth rules if necessary
-        final boolean oldRejectMetered = (oldRules & RULE_REJECT_METERED) != 0;
-        final boolean rejectMetered = (uidRules & RULE_REJECT_METERED) != 0;
-        if (oldRejectMetered != rejectMetered) {
-            setUidNetworkRules(uid, rejectMetered);
-        }
+        final boolean rejectMetered = (uidRules == RULE_REJECT_METERED);
+        setUidNetworkRules(uid, rejectMetered);
 
         // dispatch changed rule to existing listeners
         if (oldRules != uidRules) {
@@ -2560,6 +2579,12 @@
      * Add or remove a uid to the firewall blacklist for all network ifaces.
      */
     private void setUidFirewallRule(int chain, int uid, int rule) {
+        if (chain == FIREWALL_CHAIN_DOZABLE) {
+            mUidFirewallDozableRules.put(uid, rule);
+        } else if (chain == FIREWALL_CHAIN_STANDBY) {
+            mUidFirewallStandbyRules.put(uid, rule);
+        }
+
         try {
             mNetworkManager.setFirewallUidRule(chain, uid, rule);
         } catch (IllegalStateException e) {
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index b504605..8176aff 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -571,6 +571,24 @@
                 grantRuntimePermissionsLPw(musicPackage, STORAGE_PERMISSIONS, userId);
             }
 
+            // Android Wear Home
+            if (mService.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+                Intent homeIntent = new Intent(Intent.ACTION_MAIN);
+                homeIntent.addCategory(Intent.CATEGORY_HOME_MAIN);
+
+                PackageParser.Package wearHomePackage = getDefaultSystemHandlerActivityPackageLPr(
+                        homeIntent, userId);
+
+                if (wearHomePackage != null
+                        && doesPackageSupportRuntimePermissions(wearHomePackage)) {
+                    grantRuntimePermissionsLPw(wearHomePackage, CONTACTS_PERMISSIONS, false,
+                            userId);
+                    grantRuntimePermissionsLPw(wearHomePackage, PHONE_PERMISSIONS, true, userId);
+                    grantRuntimePermissionsLPw(wearHomePackage, MICROPHONE_PERMISSIONS, false,
+                            userId);
+                }
+            }
+
             mService.mSettings.onDefaultRuntimePermissionsGrantedLPr(userId);
         }
     }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 8f9b2c8..a98b8a8 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -8334,6 +8334,7 @@
 
         final int[] currentUserIds = UserManagerService.getInstance().getUserIds();
 
+        boolean runtimePermissionsRevoked = false;
         int[] changedRuntimePermissionUserIds = EMPTY_INT_ARRAY;
 
         boolean changedInstallPermission = false;
@@ -8343,6 +8344,17 @@
             if (!ps.isSharedUser()) {
                 origPermissions = new PermissionsState(permissionsState);
                 permissionsState.reset();
+            } else {
+                // We need to know only about runtime permission changes since the
+                // calling code always writes the install permissions state but
+                // the runtime ones are written only if changed. The only cases of
+                // changed runtime permissions here are promotion of an install to
+                // runtime and revocation of a runtime from a shared user.
+                changedRuntimePermissionUserIds = revokeUnusedSharedUserPermissionsLPw(
+                        ps.sharedUser, UserManagerService.getInstance().getUserIds());
+                if (!ArrayUtils.isEmpty(changedRuntimePermissionUserIds)) {
+                    runtimePermissionsRevoked = true;
+                }
             }
         }
 
@@ -8558,9 +8570,11 @@
             ps.installPermissionsFixed = true;
         }
 
-        // Persist the runtime permissions state for users with changes.
+        // Persist the runtime permissions state for users with changes. If permissions
+        // were revoked because no app in the shared user declares them we have to
+        // write synchronously to avoid losing runtime permissions state.
         for (int userId : changedRuntimePermissionUserIds) {
-            mSettings.writeRuntimePermissionsForUserLPr(userId, false);
+            mSettings.writeRuntimePermissionsForUserLPr(userId, runtimePermissionsRevoked);
         }
     }
 
@@ -12057,6 +12071,66 @@
         }
     }
 
+    private int[] revokeUnusedSharedUserPermissionsLPw(SharedUserSetting su, int[] allUserIds) {
+        // Collect all used permissions in the UID
+        ArraySet<String> usedPermissions = new ArraySet<>();
+        final int packageCount = su.packages.size();
+        for (int i = 0; i < packageCount; i++) {
+            PackageSetting ps = su.packages.valueAt(i);
+            if (ps.pkg == null) {
+                continue;
+            }
+            final int requestedPermCount = ps.pkg.requestedPermissions.size();
+            for (int j = 0; j < requestedPermCount; j++) {
+                String permission = ps.pkg.requestedPermissions.get(j);
+                BasePermission bp = mSettings.mPermissions.get(permission);
+                if (bp != null) {
+                    usedPermissions.add(permission);
+                }
+            }
+        }
+
+        PermissionsState permissionsState = su.getPermissionsState();
+        // Prune install permissions
+        List<PermissionState> installPermStates = permissionsState.getInstallPermissionStates();
+        final int installPermCount = installPermStates.size();
+        for (int i = installPermCount - 1; i >= 0;  i--) {
+            PermissionState permissionState = installPermStates.get(i);
+            if (!usedPermissions.contains(permissionState.getName())) {
+                BasePermission bp = mSettings.mPermissions.get(permissionState.getName());
+                if (bp != null) {
+                    permissionsState.revokeInstallPermission(bp);
+                    permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL,
+                            PackageManager.MASK_PERMISSION_FLAGS, 0);
+                }
+            }
+        }
+
+        int[] runtimePermissionChangedUserIds = EmptyArray.INT;
+
+        // Prune runtime permissions
+        for (int userId : allUserIds) {
+            List<PermissionState> runtimePermStates = permissionsState
+                    .getRuntimePermissionStates(userId);
+            final int runtimePermCount = runtimePermStates.size();
+            for (int i = runtimePermCount - 1; i >= 0; i--) {
+                PermissionState permissionState = runtimePermStates.get(i);
+                if (!usedPermissions.contains(permissionState.getName())) {
+                    BasePermission bp = mSettings.mPermissions.get(permissionState.getName());
+                    if (bp != null) {
+                        permissionsState.revokeRuntimePermission(bp, userId);
+                        permissionsState.updatePermissionFlags(bp, userId,
+                                PackageManager.MASK_PERMISSION_FLAGS, 0);
+                        runtimePermissionChangedUserIds = ArrayUtils.appendInt(
+                                runtimePermissionChangedUserIds, userId);
+                    }
+                }
+            }
+        }
+
+        return runtimePermissionChangedUserIds;
+    }
+
     private void updateSettingsLI(PackageParser.Package newPackage, String installerPackageName,
             String volumeUuid, int[] allUsers, boolean[] perUserInstalled, PackageInstalledInfo res,
             UserHandle user) {
diff --git a/services/midi/java/com/android/server/midi/MidiService.java b/services/midi/java/com/android/server/midi/MidiService.java
index 3ecfd55..c6d5a7e 100644
--- a/services/midi/java/com/android/server/midi/MidiService.java
+++ b/services/midi/java/com/android/server/midi/MidiService.java
@@ -27,6 +27,7 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.res.XmlResourceParser;
+import android.media.midi.IBluetoothMidiService;
 import android.media.midi.IMidiDeviceListener;
 import android.media.midi.IMidiDeviceOpenCallback;
 import android.media.midi.IMidiDeviceServer;
@@ -394,7 +395,20 @@
                     mServiceConnection = new ServiceConnection() {
                         @Override
                         public void onServiceConnected(ComponentName name, IBinder service) {
-                            IMidiDeviceServer server = IMidiDeviceServer.Stub.asInterface(service);
+                            IMidiDeviceServer server = null;
+                            if (mBluetoothDevice != null) {
+                                IBluetoothMidiService mBluetoothMidiService = IBluetoothMidiService.Stub.asInterface(service);
+                                try {
+                                    // We need to explicitly add the device in a separate method
+                                    // because onBind() is only called once.
+                                    IBinder deviceBinder = mBluetoothMidiService.addBluetoothDevice(mBluetoothDevice);
+                                    server = IMidiDeviceServer.Stub.asInterface(deviceBinder);
+                                } catch(RemoteException e) {
+                                    Log.e(TAG, "Could not call addBluetoothDevice()", e);
+                                }
+                            } else {
+                                server = IMidiDeviceServer.Stub.asInterface(service);
+                            }
                             setDeviceServer(server);
                         }
 
@@ -411,7 +425,6 @@
                         intent.setComponent(new ComponentName(
                                 MidiManager.BLUETOOTH_MIDI_SERVICE_PACKAGE,
                                 MidiManager.BLUETOOTH_MIDI_SERVICE_CLASS));
-                        intent.putExtra("device", mBluetoothDevice);
                     } else {
                         intent = new Intent(MidiDeviceService.SERVICE_INTERFACE);
                         intent.setComponent(
@@ -575,6 +588,8 @@
         Client client = getClient(token);
         if (client == null) return;
         client.addListener(listener);
+        // Let listener know whether any ports are already busy.
+        updateStickyDeviceStatus(client.mUid, listener);
     }
 
     @Override
@@ -584,6 +599,25 @@
         client.removeListener(listener);
     }
 
+    // Inform listener of the status of all known devices.
+    private void updateStickyDeviceStatus(int uid, IMidiDeviceListener listener) {
+        synchronized (mDevicesByInfo) {
+            for (Device device : mDevicesByInfo.values()) {
+                // ignore private devices that our client cannot access
+                if (device.isUidAllowed(uid)) {
+                    try {
+                        MidiDeviceStatus status = device.getDeviceStatus();
+                        if (status != null) {
+                            listener.onDeviceStatusChanged(status);
+                        }
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "remote exception", e);
+                    }
+                }
+            }
+        }
+    }
+
     private static final MidiDeviceInfo[] EMPTY_DEVICE_INFO_ARRAY = new MidiDeviceInfo[0];
 
     public MidiDeviceInfo[] getDevices() {
diff --git a/services/net/java/android/net/dhcp/DhcpAckPacket.java b/services/net/java/android/net/dhcp/DhcpAckPacket.java
index 334f708..df44b11 100644
--- a/services/net/java/android/net/dhcp/DhcpAckPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpAckPacket.java
@@ -46,7 +46,7 @@
 
         return s + " ACK: your new IP " + mYourIp +
                 ", netmask " + mSubnetMask +
-                ", gateway " + mGateway + dnsServers +
+                ", gateways " + mGateways + dnsServers +
                 ", lease time " + mLeaseTime;
     }
 
@@ -79,7 +79,7 @@
         }
 
         addTlv(buffer, DHCP_SUBNET_MASK, mSubnetMask);
-        addTlv(buffer, DHCP_ROUTER, mGateway);
+        addTlv(buffer, DHCP_ROUTER, mGateways);
         addTlv(buffer, DHCP_DOMAIN_NAME, mDomainName);
         addTlv(buffer, DHCP_BROADCAST_ADDRESS, mBroadcastAddress);
         addTlv(buffer, DHCP_DNS_SERVER, mDnsServers);
diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
index e0d2ac1..28cb114 100644
--- a/services/net/java/android/net/dhcp/DhcpClient.java
+++ b/services/net/java/android/net/dhcp/DhcpClient.java
@@ -299,6 +299,7 @@
             Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_REUSEADDR, 1);
             Os.setsockoptIfreq(mUdpSock, SOL_SOCKET, SO_BINDTODEVICE, mIfaceName);
             Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_BROADCAST, 1);
+            Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_RCVBUF, 0);
             Os.bind(mUdpSock, Inet4Address.ANY, DhcpPacket.DHCP_CLIENT);
             NetworkUtils.protectFromVpn(mUdpSock);
         } catch(SocketException|ErrnoException e) {
@@ -308,6 +309,16 @@
         return true;
     }
 
+    private boolean connectUdpSock(Inet4Address to) {
+        try {
+            Os.connect(mUdpSock, to, DhcpPacket.DHCP_SERVER);
+            return true;
+        } catch (SocketException|ErrnoException e) {
+            Log.e(TAG, "Error connecting UDP socket", e);
+            return false;
+        }
+    }
+
     private static void closeQuietly(FileDescriptor fd) {
         try {
             IoBridge.closeAndSignalBlockedThreads(fd);
@@ -325,7 +336,7 @@
         try {
             mNMService.setInterfaceConfig(mIfaceName, ifcg);
         } catch (RemoteException|IllegalStateException e) {
-            Log.e(TAG, "Error configuring IP address : " + e);
+            Log.e(TAG, "Error configuring IP address " + address + ": ", e);
             return false;
         }
         return true;
@@ -345,21 +356,22 @@
         public void run() {
             maybeLog("Receive thread started");
             while (!stopped) {
+                int length = 0;  // Or compiler can't tell it's initialized if a parse error occurs.
                 try {
-                    int length = Os.read(mPacketSock, mPacket, 0, mPacket.length);
+                    length = Os.read(mPacketSock, mPacket, 0, mPacket.length);
                     DhcpPacket packet = null;
                     packet = DhcpPacket.decodeFullPacket(mPacket, length, DhcpPacket.ENCAP_L2);
-                    if (packet != null) {
-                        maybeLog("Received packet: " + packet);
-                        sendMessage(CMD_RECEIVED_PACKET, packet);
-                    } else if (PACKET_DBG) {
-                        Log.d(TAG,
-                                "Can't parse packet" + HexDump.dumpHexString(mPacket, 0, length));
-                    }
+                    maybeLog("Received packet: " + packet);
+                    sendMessage(CMD_RECEIVED_PACKET, packet);
                 } catch (IOException|ErrnoException e) {
                     if (!stopped) {
                         Log.e(TAG, "Read error", e);
                     }
+                } catch (DhcpPacket.ParseException e) {
+                    Log.e(TAG, "Can't parse packet: " + e.getMessage());
+                    if (PACKET_DBG) {
+                        Log.d(TAG, HexDump.dumpHexString(mPacket, 0, length));
+                    }
                 }
             }
             maybeLog("Receive thread stopped");
@@ -376,8 +388,10 @@
                 maybeLog("Broadcasting " + description);
                 Os.sendto(mPacketSock, buf.array(), 0, buf.limit(), 0, mInterfaceBroadcastAddr);
             } else {
-                maybeLog("Unicasting " + description + " to " + to.getHostAddress());
-                Os.sendto(mUdpSock, buf, 0, to, DhcpPacket.DHCP_SERVER);
+                // It's safe to call getpeername here, because we only send unicast packets if we
+                // have an IP address, and we connect the UDP socket in DhcpHaveAddressState#enter.
+                maybeLog("Unicasting " + description + " to " + Os.getpeername(mUdpSock));
+                Os.write(mUdpSock, buf);
             }
         } catch(ErrnoException|IOException e) {
             Log.e(TAG, "Can't send packet: ", e);
@@ -789,6 +803,7 @@
                     transitionTo(mDhcpBoundState);
                 }
             } else if (packet instanceof DhcpNakPacket) {
+                // TODO: Wait a while before returning into INIT state.
                 Log.d(TAG, "Received NAK, returning to INIT");
                 mOffer = null;
                 transitionTo(mDhcpInitState);
@@ -806,10 +821,8 @@
         @Override
         public void enter() {
             super.enter();
-            if (setIpAddress(mDhcpLease.ipAddress)) {
-                maybeLog("Configured IP address " + mDhcpLease.ipAddress);
-            } else {
-                Log.e(TAG, "Failed to configure IP address " + mDhcpLease.ipAddress);
+            if (!setIpAddress(mDhcpLease.ipAddress) ||
+                    !connectUdpSock((mDhcpLease.serverAddress))) {
                 notifyFailure();
                 // There's likely no point in going into DhcpInitState here, we'll probably just
                 // repeat the transaction, get the same IP address as before, and fail.
diff --git a/services/net/java/android/net/dhcp/DhcpOfferPacket.java b/services/net/java/android/net/dhcp/DhcpOfferPacket.java
index 7ca7100..99154ef 100644
--- a/services/net/java/android/net/dhcp/DhcpOfferPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpOfferPacket.java
@@ -48,7 +48,7 @@
         }
 
         return s + " OFFER, ip " + mYourIp + ", mask " + mSubnetMask +
-                dnsServers + ", gateway " + mGateway +
+                dnsServers + ", gateways " + mGateways +
                 " lease time " + mLeaseTime + ", domain " + mDomainName;
     }
 
@@ -81,7 +81,7 @@
         }
 
         addTlv(buffer, DHCP_SUBNET_MASK, mSubnetMask);
-        addTlv(buffer, DHCP_ROUTER, mGateway);
+        addTlv(buffer, DHCP_ROUTER, mGateways);
         addTlv(buffer, DHCP_DOMAIN_NAME, mDomainName);
         addTlv(buffer, DHCP_BROADCAST_ADDRESS, mBroadcastAddress);
         addTlv(buffer, DHCP_DNS_SERVER, mDnsServers);
diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java
index cbf8fc2..8927bfa 100644
--- a/services/net/java/android/net/dhcp/DhcpPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpPacket.java
@@ -114,6 +114,11 @@
     protected static final int MAX_LENGTH = 1500;
 
     /**
+     * The magic cookie that identifies this as a DHCP packet instead of BOOTP.
+     */
+    private static final int DHCP_MAGIC_COOKIE = 0x63825363;
+
+    /**
      * DHCP Optional Type: DHCP Subnet Mask
      */
     protected static final byte DHCP_SUBNET_MASK = 1;
@@ -123,7 +128,7 @@
      * DHCP Optional Type: DHCP Router
      */
     protected static final byte DHCP_ROUTER = 3;
-    protected Inet4Address mGateway;
+    protected List <Inet4Address> mGateways;
 
     /**
      * DHCP Optional Type: DHCP DNS Server
@@ -403,7 +408,7 @@
                      (HWADDR_LEN - mClientMac.length) // pad addr to 16 bytes
                      + 64     // empty server host name (64 bytes)
                      + 128);  // empty boot file name (128 bytes)
-        buf.putInt(0x63825363); // magic number
+        buf.putInt(DHCP_MAGIC_COOKIE); // magic number
         finishPacket(buf);
 
         // round up to an even number of octets
@@ -668,6 +673,20 @@
         return new String(bytes, 0, length, StandardCharsets.US_ASCII);
     }
 
+    private static boolean isPacketToOrFromClient(short udpSrcPort, short udpDstPort) {
+        return (udpSrcPort == DHCP_CLIENT) || (udpDstPort == DHCP_CLIENT);
+    }
+
+    private static boolean isPacketServerToServer(short udpSrcPort, short udpDstPort) {
+        return (udpSrcPort == DHCP_SERVER) && (udpDstPort == DHCP_SERVER);
+    }
+
+    public static class ParseException extends Exception {
+        public ParseException(String msg, Object... args) {
+            super(String.format(msg, args));
+        }
+    }
+
     /**
      * Creates a concrete DhcpPacket from the supplied ByteBuffer.  The
      * buffer may have an L2 encapsulation (which is the full EthernetII
@@ -677,7 +696,7 @@
      * A subset of the optional parameters are parsed and are stored
      * in object fields.
      */
-    public static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType)
+    public static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType) throws ParseException
     {
         // bootp parameters
         int transactionId;
@@ -687,8 +706,8 @@
         Inet4Address nextIp;
         Inet4Address relayIp;
         byte[] clientMac;
-        List<Inet4Address> dnsServers = new ArrayList<Inet4Address>();
-        Inet4Address gateway = null; // aka router
+        List<Inet4Address> dnsServers = new ArrayList<>();
+        List<Inet4Address> gateways = new ArrayList<>();  // aka router
         Inet4Address serverIdentifier = null;
         Inet4Address netMask = null;
         String message = null;
@@ -720,7 +739,8 @@
         // check to see if we need to parse L2, IP, and UDP encaps
         if (pktType == ENCAP_L2) {
             if (packet.remaining() < MIN_PACKET_LENGTH_L2) {
-                return null;
+                throw new ParseException("L2 packet too short, %d < %d",
+                        packet.remaining(), MIN_PACKET_LENGTH_L2);
             }
 
             byte[] l2dst = new byte[6];
@@ -732,18 +752,20 @@
             short l2type = packet.getShort();
 
             if (l2type != OsConstants.ETH_P_IP)
-                return null;
+                throw new ParseException("Unexpected L2 type 0x%04x, expected 0x%04x",
+                        l2type, OsConstants.ETH_P_IP);
         }
 
         if (pktType <= ENCAP_L3) {
             if (packet.remaining() < MIN_PACKET_LENGTH_L3) {
-                return null;
+                throw new ParseException("L3 packet too short, %d < %d",
+                        packet.remaining(), MIN_PACKET_LENGTH_L3);
             }
 
             byte ipTypeAndLength = packet.get();
             int ipVersion = (ipTypeAndLength & 0xf0) >> 4;
             if (ipVersion != 4) {
-                return null;
+                throw new ParseException("Invalid IP version %d", ipVersion);
             }
 
             // System.out.println("ipType is " + ipType);
@@ -759,8 +781,9 @@
             ipSrc = readIpAddress(packet);
             ipDst = readIpAddress(packet);
 
-            if (ipProto != IP_TYPE_UDP) // UDP
-                return null;
+            if (ipProto != IP_TYPE_UDP) {
+                throw new ParseException("Protocol not UDP: %d", ipProto);
+            }
 
             // Skip options. This cannot cause us to read beyond the end of the buffer because the
             // IPv4 header cannot be more than (0x0f * 4) = 60 bytes long, and that is less than
@@ -776,13 +799,19 @@
             short udpLen = packet.getShort();
             short udpChkSum = packet.getShort();
 
-            if ((udpSrcPort != DHCP_SERVER) && (udpSrcPort != DHCP_CLIENT))
+            // Only accept packets to or from the well-known client port (expressly permitting
+            // packets from ports other than the well-known server port; http://b/24687559), and
+            // server-to-server packets, e.g. for relays.
+            if (!isPacketToOrFromClient(udpSrcPort, udpDstPort) &&
+                !isPacketServerToServer(udpSrcPort, udpDstPort)) {
                 return null;
+            }
         }
 
         // We need to check the length even for ENCAP_L3 because the IPv4 header is variable-length.
         if (pktType > ENCAP_BOOTP || packet.remaining() < MIN_PACKET_LENGTH_BOOTP) {
-            return null;
+            throw new ParseException("Invalid type or BOOTP packet too short, %d < %d",
+                        packet.remaining(), MIN_PACKET_LENGTH_BOOTP);
         }
 
         byte type = packet.get();
@@ -805,7 +834,7 @@
             packet.get(ipv4addr);
             relayIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
         } catch (UnknownHostException ex) {
-            return null;
+            throw new ParseException("Invalid IPv4 address: %s", Arrays.toString(ipv4addr));
         }
 
         // Some DHCP servers have been known to announce invalid client hardware address values such
@@ -828,8 +857,10 @@
 
         int dhcpMagicCookie = packet.getInt();
 
-        if (dhcpMagicCookie !=  0x63825363)
-            return null;
+        if (dhcpMagicCookie != DHCP_MAGIC_COOKIE) {
+            throw new ParseException("Bad magic cookie 0x%08x, should be 0x%08x", dhcpMagicCookie,
+                    DHCP_MAGIC_COOKIE);
+        }
 
         // parse options
         boolean notFinishedOptions = true;
@@ -852,8 +883,9 @@
                             expectedLen = 4;
                             break;
                         case DHCP_ROUTER:
-                            gateway = readIpAddress(packet);
-                            expectedLen = 4;
+                            for (expectedLen = 0; expectedLen < optionLen; expectedLen += 4) {
+                                gateways.add(readIpAddress(packet));
+                            }
                             break;
                         case DHCP_DNS_SERVER:
                             for (expectedLen = 0; expectedLen < optionLen; expectedLen += 4) {
@@ -937,18 +969,20 @@
                     }
 
                     if (expectedLen != optionLen) {
-                        return null;
+                        throw new ParseException("Invalid length %d for option %d, expected %d",
+                                optionLen, optionType, expectedLen);
                     }
                 }
             } catch (BufferUnderflowException e) {
-                return null;
+                throw new ParseException("BufferUnderflowException");
             }
         }
 
         DhcpPacket newPacket;
 
         switch(dhcpType) {
-            case -1: return null;
+            case (byte) 0xFF:
+                throw new ParseException("No DHCP message type option");
             case DHCP_MESSAGE_TYPE_DISCOVER:
                 newPacket = new DhcpDiscoverPacket(
                     transactionId, secs, clientMac, broadcast);
@@ -981,14 +1015,13 @@
                     clientMac);
                 break;
             default:
-                System.out.println("Unimplemented type: " + dhcpType);
-                return null;
+                throw new ParseException("Unimplemented DHCP type %d", dhcpType);
         }
 
         newPacket.mBroadcastAddress = bcAddr;
         newPacket.mDnsServers = dnsServers;
         newPacket.mDomainName = domainName;
-        newPacket.mGateway = gateway;
+        newPacket.mGateways = gateways;
         newPacket.mHostName = hostName;
         newPacket.mLeaseTime = leaseTime;
         newPacket.mMessage = message;
@@ -1009,7 +1042,7 @@
      * Parse a packet from an array of bytes, stopping at the given length.
      */
     public static DhcpPacket decodeFullPacket(byte[] packet, int length, int pktType)
-    {
+            throws ParseException {
         ByteBuffer buffer = ByteBuffer.wrap(packet, 0, length).order(ByteOrder.BIG_ENDIAN);
         return decodeFullPacket(buffer, pktType);
     }
@@ -1044,7 +1077,11 @@
         } catch (IllegalArgumentException e) {
             return null;
         }
-        results.gateway = mGateway;
+
+        if (mGateways.size() > 0) {
+            results.gateway = mGateways.get(0);
+        }
+
         results.dnsServers.addAll(mDnsServers);
         results.domains = mDomainName;
         results.serverAddress = mServerIdentifier;
@@ -1086,11 +1123,11 @@
     public static ByteBuffer buildOfferPacket(int encap, int transactionId,
         boolean broadcast, Inet4Address serverIpAddr, Inet4Address clientIpAddr,
         byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr,
-        Inet4Address gateway, List<Inet4Address> dnsServers,
+        List<Inet4Address> gateways, List<Inet4Address> dnsServers,
         Inet4Address dhcpServerIdentifier, String domainName) {
         DhcpPacket pkt = new DhcpOfferPacket(
             transactionId, (short) 0, broadcast, serverIpAddr, INADDR_ANY, clientIpAddr, mac);
-        pkt.mGateway = gateway;
+        pkt.mGateways = gateways;
         pkt.mDnsServers = dnsServers;
         pkt.mLeaseTime = timeout;
         pkt.mDomainName = domainName;
@@ -1106,11 +1143,11 @@
     public static ByteBuffer buildAckPacket(int encap, int transactionId,
         boolean broadcast, Inet4Address serverIpAddr, Inet4Address clientIpAddr,
         byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr,
-        Inet4Address gateway, List<Inet4Address> dnsServers,
+        List<Inet4Address> gateways, List<Inet4Address> dnsServers,
         Inet4Address dhcpServerIdentifier, String domainName) {
         DhcpPacket pkt = new DhcpAckPacket(
             transactionId, (short) 0, broadcast, serverIpAddr, INADDR_ANY, clientIpAddr, mac);
-        pkt.mGateway = gateway;
+        pkt.mGateways = gateways;
         pkt.mDnsServers = dnsServers;
         pkt.mLeaseTime = timeout;
         pkt.mDomainName = domainName;
diff --git a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
index cd3b8bb..7e60bf1 100644
--- a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
+++ b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
@@ -117,7 +117,7 @@
 
     private void assertDomainAndVendorInfoParses(
             String expectedDomain, byte[] domainBytes,
-            String expectedVendorInfo, byte[] vendorInfoBytes) {
+            String expectedVendorInfo, byte[] vendorInfoBytes) throws Exception {
         ByteBuffer packet = new TestDhcpPacket(DHCP_MESSAGE_TYPE_OFFER)
                 .setDomainBytes(domainBytes)
                 .setVendorInfoBytes(vendorInfoBytes)
@@ -158,17 +158,25 @@
     }
 
     private void assertLeaseTimeParses(boolean expectValid, Integer rawLeaseTime,
-                                       long leaseTimeMillis, byte[] leaseTimeBytes) {
+            long leaseTimeMillis, byte[] leaseTimeBytes) throws Exception {
         TestDhcpPacket testPacket = new TestDhcpPacket(DHCP_MESSAGE_TYPE_OFFER);
         if (leaseTimeBytes != null) {
             testPacket.setLeaseTimeBytes(leaseTimeBytes);
         }
         ByteBuffer packet = testPacket.build();
-        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP);
+        DhcpPacket offerPacket = null;
+
         if (!expectValid) {
-            assertNull(offerPacket);
+            try {
+                offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP);
+                fail("Invalid packet parsed successfully: " + offerPacket);
+            } catch (ParseException expected) {
+            }
             return;
         }
+
+        offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP);
+        assertNotNull(offerPacket);
         assertEquals(rawLeaseTime, offerPacket.mLeaseTime);
         DhcpResults dhcpResults = offerPacket.toDhcpResults();  // Just check this doesn't crash.
         assertEquals(leaseTimeMillis, offerPacket.getLeaseTimeMillis());
@@ -200,14 +208,14 @@
     }
 
     private void checkIpAddress(String expected, Inet4Address clientIp, Inet4Address yourIp,
-                                byte[] netmaskBytes) {
+                                byte[] netmaskBytes) throws Exception {
         checkIpAddress(expected, DHCP_MESSAGE_TYPE_OFFER, clientIp, yourIp, netmaskBytes);
         checkIpAddress(expected, DHCP_MESSAGE_TYPE_ACK, clientIp, yourIp, netmaskBytes);
     }
 
     private void checkIpAddress(String expected, byte type,
                                 Inet4Address clientIp, Inet4Address yourIp,
-                                byte[] netmaskBytes) {
+                                byte[] netmaskBytes) throws Exception {
         ByteBuffer packet = new TestDhcpPacket(type, clientIp, yourIp)
                 .setNetmaskBytes(netmaskBytes)
                 .build();
@@ -506,4 +514,74 @@
         assertDhcpResults("10.32.158.205/20", "10.32.144.1", "148.88.65.52,148.88.65.53",
                 "lancs.ac.uk", "10.32.255.128", null, 7200, false, dhcpResults);
     }
+
+    @SmallTest
+    public void testUdpServerAnySourcePort() throws Exception {
+        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+            // Ethernet header.
+            "9cd917000000001c2e0000000800" +
+            // IP header.
+            "45a00148000040003d115087d18194fb0a0f7af2" +
+            // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
+            // NOTE: The server source port is not the canonical port 67.
+            "C29F004401341268" +
+            // BOOTP header.
+            "02010600d628ba8200000000000000000a0f7af2000000000a0fc818" +
+            // MAC address.
+            "9cd91700000000000000000000000000" +
+            // Server name.
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            // File.
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            // Options.
+            "6382536335010236040a0169fc3304000151800104ffff000003040a0fc817060cd1818003d1819403" +
+            "d18180060f0777766d2e6564751c040a0fffffff000000"
+        ).toCharArray(), false));
+
+        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
+        assertTrue(offerPacket instanceof DhcpOfferPacket);
+        assertEquals("9CD917000000", HexDump.toHexString(offerPacket.getClientMac()));
+        DhcpResults dhcpResults = offerPacket.toDhcpResults();
+        assertDhcpResults("10.15.122.242/16", "10.15.200.23",
+                "209.129.128.3,209.129.148.3,209.129.128.6",
+                "wvm.edu", "10.1.105.252", null, 86400, false, dhcpResults);
+    }
+
+    @SmallTest
+    public void testMultipleRouters() throws Exception {
+        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+            // Ethernet header.
+            "fc3d93000000" + "081735000000" + "0800" +
+            // IP header.
+            "45000148c2370000ff117ac2c0a8bd02ffffffff" +
+            // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
+            "0043004401343beb" +
+            // BOOTP header.
+            "0201060027f518e20000800000000000c0a8bd310000000000000000" +
+            // MAC address.
+            "fc3d9300000000000000000000000000" +
+            // Server name.
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            // File.
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            // Options.
+            "638253633501023604c0abbd023304000070803a04000038403b04000062700104ffffff00" +
+            "0308c0a8bd01ffffff0006080808080808080404ff000000000000"
+        ).toCharArray(), false));
+
+        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
+        assertTrue(offerPacket instanceof DhcpOfferPacket);
+        assertEquals("FC3D93000000", HexDump.toHexString(offerPacket.getClientMac()));
+        DhcpResults dhcpResults = offerPacket.toDhcpResults();
+        assertDhcpResults("192.168.189.49/24", "192.168.189.1", "8.8.8.8,8.8.4.4",
+                null, "192.171.189.2", null, 28800, false, dhcpResults);
+    }
 }
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 4146c1c0..5ad796f 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -314,6 +314,8 @@
                 mAppIdleParoled = paroled;
                 if (DEBUG) Slog.d(TAG, "Changing paroled to " + mAppIdleParoled);
                 if (paroled) {
+                    postParoleEndTimeout();
+                } else {
                     mLastAppIdleParoledTime = checkAndGetTimeLocked();
                     postNextParoleTimeout();
                 }
@@ -404,8 +406,6 @@
                 if (timeSinceLastParole > mAppIdleParoleIntervalMillis) {
                     if (DEBUG) Slog.d(TAG, "Crossed default parole interval");
                     setAppIdleParoled(true);
-                    // Make sure it ends at some point
-                    postParoleEndTimeout();
                 } else {
                     if (DEBUG) Slog.d(TAG, "Not long enough to go to parole");
                     postNextParoleTimeout();
@@ -492,7 +492,6 @@
             if (!deviceIdle
                     && timeSinceLastParole >= mAppIdleParoleIntervalMillis) {
                 if (DEBUG) Slog.i(TAG, "Bringing idle apps out of inactive state due to deviceIdleMode=false");
-                postNextParoleTimeout();
                 setAppIdleParoled(true);
             } else if (deviceIdle) {
                 if (DEBUG) Slog.i(TAG, "Device idle, back to prison");
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java
index 3ca0c84..31d859f 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java
@@ -87,6 +87,7 @@
     // This is an indirect indication of the microphone being open in some other application.
     private boolean mServiceDisabled = false;
     private boolean mStarted = false;
+    private boolean mRecognitionAborted = false;
     private PowerSaveModeListener mPowerSaveModeListener;
 
     SoundTriggerHelper(Context context) {
@@ -386,8 +387,9 @@
 
     private void onRecognitionAbortLocked() {
         Slog.w(TAG, "Recognition aborted");
-        // No-op
-        // This is handled via service state changes instead.
+        // If abort has been called, the hardware has already stopped recognition, so we shouldn't
+        // call it again when we process the state change.
+        mRecognitionAborted = true;
     }
 
     private void onRecognitionFailureLocked() {
@@ -490,8 +492,13 @@
             }
             return status;
         } else {
-            // Stop recognition.
-            int status = mModule.stopRecognition(mCurrentSoundModelHandle);
+            // Stop recognition (only if we haven't been aborted).
+            int status = STATUS_OK;
+            if (!mRecognitionAborted) {
+                status = mModule.stopRecognition(mCurrentSoundModelHandle);
+            } else {
+                mRecognitionAborted = false;
+            }
             if (status != SoundTrigger.STATUS_OK) {
                 Slog.w(TAG, "stopRecognition call failed with " + status);
                 if (notify) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index a8874d0..a96c164 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -925,7 +925,7 @@
                 return;
             }
             synchronized (this) {
-                pw.println("VOICE INTERACTION MANAGER (dumpsys voiceinteraction)\n");
+                pw.println("VOICE INTERACTION MANAGER (dumpsys voiceinteraction)");
                 pw.println("  mEnableService: " + mEnableService);
                 if (mImpl == null) {
                     pw.println("  (No active implementation)");
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 28520be..30296e1 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -36,6 +36,7 @@
 import android.service.voice.IVoiceInteractionSession;
 import android.service.voice.VoiceInteractionService;
 import android.service.voice.VoiceInteractionServiceInfo;
+import android.util.PrintWriterPrinter;
 import android.util.Slog;
 import android.view.IWindowManager;
 
@@ -114,9 +115,9 @@
         mAm = ActivityManagerNative.getDefault();
         VoiceInteractionServiceInfo info;
         try {
-            info = new VoiceInteractionServiceInfo(context.getPackageManager(), service);
-        } catch (PackageManager.NameNotFoundException e) {
-            Slog.w(TAG, "Voice interaction service not found: " + service);
+            info = new VoiceInteractionServiceInfo(context.getPackageManager(), service, mUser);
+        } catch (RemoteException|PackageManager.NameNotFoundException e) {
+            Slog.w(TAG, "Voice interaction service not found: " + service, e);
             mInfo = null;
             mSessionComponentName = null;
             mIWindowManager = null;
@@ -260,9 +261,18 @@
             }
             return;
         }
+        pw.print("  mUser="); pw.println(mUser);
         pw.print("  mComponent="); pw.println(mComponent.flattenToShortString());
         pw.print("  Session service="); pw.println(mInfo.getSessionService());
+        pw.println("  Service info:");
+        mInfo.getServiceInfo().dump(new PrintWriterPrinter(pw), "    ");
+        pw.println("  Application info:");
+        mInfo.getServiceInfo().applicationInfo.dump(new PrintWriterPrinter(pw), "    ");
+        pw.print("  Recognition service="); pw.println(mInfo.getRecognitionService());
         pw.print("  Settings activity="); pw.println(mInfo.getSettingsActivity());
+        pw.print("  Supports assist="); pw.println(mInfo.getSupportsAssist());
+        pw.print("  Supports launch from keyguard=");
+        pw.println(mInfo.getSupportsLaunchFromKeyguard());
         if (mDisabledShowContext != 0) {
             pw.print("  mDisabledShowContext=");
             pw.println(Integer.toHexString(mDisabledShowContext));
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index aa4da4b..744028a 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -191,7 +191,7 @@
     public static final String
             KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
 
-   /**
+    /**
      * Override the platform's notion of a network operator being considered roaming.
      * Value is string array of MCCMNCs to be considered roaming for 3GPP RATs.
      */
@@ -428,6 +428,12 @@
      */
     public static final String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool";
 
+    /**
+     * Allow user to add APNs
+     * @hide
+     */
+    public static final String KEY_ALLOW_ADDING_APNS_BOOL = "allow_adding_apns_bool";
+
     // These variables are used by the MMS service and exposed through another API, {@link
     // SmsManager}. The variable names and string values are copied from there.
     public static final String KEY_MMS_ALIAS_ENABLED_BOOL = "aliasEnabled";
@@ -524,6 +530,7 @@
         sDefaults.putString(KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING, "");
         sDefaults.putString(KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING, "");
         sDefaults.putBoolean(KEY_CSP_ENABLED_BOOL, false);
+        sDefaults.putBoolean(KEY_ALLOW_ADDING_APNS_BOOL, true);
         sDefaults.putBoolean(KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL, false);
 
         sDefaults.putStringArray(KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY, null);
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index f535e5d..fced667 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -911,7 +911,7 @@
         else if (tdScdmaDbm >= -49) level = SIGNAL_STRENGTH_GREAT;
         else if (tdScdmaDbm >= -73) level = SIGNAL_STRENGTH_GOOD;
         else if (tdScdmaDbm >= -97) level = SIGNAL_STRENGTH_MODERATE;
-        else if (tdScdmaDbm >= -120) level = SIGNAL_STRENGTH_POOR;
+        else if (tdScdmaDbm >= -110) level = SIGNAL_STRENGTH_POOR;
         else level = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
 
         if (DBG) log("getTdScdmaLevel = " + level);
diff --git a/tools/layoutlib/bridge/src/android/preference/Preference_Delegate.java b/tools/layoutlib/bridge/src/android/preference/Preference_Delegate.java
index 49ee642..2e44a77 100644
--- a/tools/layoutlib/bridge/src/android/preference/Preference_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/preference/Preference_Delegate.java
@@ -29,9 +29,6 @@
 import android.view.ViewGroup;
 import android.widget.ListView;
 
-import java.util.HashMap;
-import java.util.Map;
-
 /**
  * Delegate that provides implementation for native methods in {@link Preference}
  * <p/>
@@ -59,9 +56,9 @@
      */
     public static View inflatePreference(Context context, XmlPullParser parser, ViewGroup root) {
         PreferenceManager pm = new PreferenceManager(context);
-        PreferenceScreen ps = pm.getPreferenceScreen();
         PreferenceInflater inflater = new BridgePreferenceInflater(context, pm);
-        ps = (PreferenceScreen) inflater.inflate(parser, ps, true);
+        PreferenceScreen ps = (PreferenceScreen) inflater.inflate(parser, null, true);
+        pm.setPreferences(ps);
         ListView preferenceView = createContainerView(context, root);
         ps.bind(preferenceView);
         return preferenceView;