Merge "Prevent monkey from triggering bugreport" into lmp-dev
diff --git a/core/java/android/app/backup/WallpaperBackupHelper.java b/core/java/android/app/backup/WallpaperBackupHelper.java
index 0567500..b8575d7 100644
--- a/core/java/android/app/backup/WallpaperBackupHelper.java
+++ b/core/java/android/app/backup/WallpaperBackupHelper.java
@@ -80,17 +80,17 @@
         mFiles = files;
         mKeys = keys;
 
-        WallpaperManager wpm;
-        wpm = (WallpaperManager) context.getSystemService(Context.WALLPAPER_SERVICE);
-        mDesiredMinWidth = (double) wpm.getDesiredMinimumWidth();
+        final WindowManager wm =
+                (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+        final WallpaperManager wpm =
+                (WallpaperManager) context.getSystemService(Context.WALLPAPER_SERVICE);
+        final Display d = wm.getDefaultDisplay();
+        final Point size = new Point();
+        d.getSize(size);
+        mDesiredMinWidth = size.x;
         mDesiredMinHeight = (double) wpm.getDesiredMinimumHeight();
 
-        if (mDesiredMinWidth <= 0 || mDesiredMinHeight <= 0) {
-            WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
-            Display d = wm.getDefaultDisplay();
-            Point size = new Point();
-            d.getSize(size);
-            mDesiredMinWidth = size.x;
+        if (mDesiredMinHeight <= 0) {
             mDesiredMinHeight = size.y;
         }
 
@@ -130,15 +130,12 @@
                     if (DEBUG) Slog.d(TAG, "Restoring wallpaper image w=" + options.outWidth
                             + " h=" + options.outHeight);
 
-                    // How much does the image differ from our preference?  The threshold
-                    // here is set to accept any image larger than our target, because
-                    // scaling down is acceptable; but to reject images that are deemed
-                    // "too small" to scale up attractively.  The value 1.33 is just barely
-                    // too low to pass Nexus 1 or Droid wallpapers for use on a Xoom, but
-                    // will pass anything relatively larger.
-                    double widthRatio = mDesiredMinWidth / options.outWidth;
-                    double heightRatio = mDesiredMinHeight / options.outHeight;
-                    if (widthRatio > 0 && widthRatio < 1.33
+                    // We accept any wallpaper that is at least as wide as our preference
+                    // (i.e. wide enough to fill the screen), and is within a comfortable
+                    // factor of the target height, to avoid significant clipping/scaling/
+                    // letterboxing.
+                    final double heightRatio = mDesiredMinHeight / options.outHeight;
+                    if (options.outWidth >= mDesiredMinWidth
                             && heightRatio > 0 && heightRatio < 1.33) {
                         // sufficiently close to our resolution; go ahead and use it
                         Slog.d(TAG, "Applying restored wallpaper image.");
@@ -147,8 +144,11 @@
                         // since it does not exist anywhere other than the private wallpaper
                         // file.
                     } else {
-                        Slog.i(TAG, "Dimensions too far off; using default wallpaper. wr=" + widthRatio
-                                + " hr=" + heightRatio);
+                        Slog.i(TAG, "Restored image dimensions (w="
+                                + options.outWidth + ", h=" + options.outHeight
+                                + ") too far off target (tw="
+                                + mDesiredMinWidth + ", th=" + mDesiredMinHeight
+                                + "); falling back to default wallpaper.");
                         f.delete();
                     }
                 }
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index d19604b..0cafff8 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -78,7 +78,7 @@
  * can use the convenience method {@link Item#coerceToText Item.coerceToText}.
  * In this case there is generally no need to worry about the MIME types
  * reported by {@link ClipDescription#getMimeType(int) getDescription().getMimeType(int)},
- * since any clip item an always be converted to a string.
+ * since any clip item can always be converted to a string.
  *
  * <p>More complicated exchanges will be done through URIs, in particular
  * "content:" URIs.  A content URI allows the recipient of a ClippedData item
diff --git a/core/java/android/content/UriMatcher.java b/core/java/android/content/UriMatcher.java
index 1a8ea47..8487dae 100644
--- a/core/java/android/content/UriMatcher.java
+++ b/core/java/android/content/UriMatcher.java
@@ -150,7 +150,7 @@
      * numbers.
      * <p>
      * Starting from API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2},
-     * this method will accept leading slash in the path.
+     * this method will accept a leading slash in the path.
      *
      * @param authority the authority to match
      * @param path the path to match. * may be used as a wild card for
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 2e24785..9194ca8 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -25,6 +25,7 @@
 import android.net.NetworkUtils;
 import android.os.Binder;
 import android.os.Build.VERSION_CODES;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
@@ -2147,50 +2148,57 @@
             Log.d(TAG, "CM callback handler got msg " + message.what);
             switch (message.what) {
                 case CALLBACK_PRECHECK: {
-                    NetworkRequest request = getNetworkRequest(message);
+                    NetworkRequest request = (NetworkRequest)getObject(message,
+                            NetworkRequest.class);
                     NetworkCallback callbacks = getCallbacks(request);
                     if (callbacks != null) {
-                        callbacks.onPreCheck(getNetwork(message));
+                        callbacks.onPreCheck((Network)getObject(message, Network.class));
                     } else {
                         Log.e(TAG, "callback not found for PRECHECK message");
                     }
                     break;
                 }
                 case CALLBACK_AVAILABLE: {
-                    NetworkRequest request = getNetworkRequest(message);
+                    NetworkRequest request = (NetworkRequest)getObject(message,
+                            NetworkRequest.class);
                     NetworkCallback callbacks = getCallbacks(request);
                     if (callbacks != null) {
-                        callbacks.onAvailable(getNetwork(message));
+                        callbacks.onAvailable((Network)getObject(message, Network.class));
                     } else {
                         Log.e(TAG, "callback not found for AVAILABLE message");
                     }
                     break;
                 }
                 case CALLBACK_LOSING: {
-                    NetworkRequest request = getNetworkRequest(message);
+                    NetworkRequest request = (NetworkRequest)getObject(message,
+                            NetworkRequest.class);
                     NetworkCallback callbacks = getCallbacks(request);
                     if (callbacks != null) {
-                        callbacks.onLosing(getNetwork(message), message.arg1);
+                        callbacks.onLosing((Network)getObject(message, Network.class),
+                                message.arg1);
                     } else {
                         Log.e(TAG, "callback not found for LOSING message");
                     }
                     break;
                 }
                 case CALLBACK_LOST: {
-                    NetworkRequest request = getNetworkRequest(message);
+                    NetworkRequest request = (NetworkRequest)getObject(message,
+                            NetworkRequest.class);
+
                     NetworkCallback callbacks = getCallbacks(request);
                     if (callbacks != null) {
-                        callbacks.onLost(getNetwork(message));
+                        callbacks.onLost((Network)getObject(message, Network.class));
                     } else {
                         Log.e(TAG, "callback not found for LOST message");
                     }
                     break;
                 }
                 case CALLBACK_UNAVAIL: {
-                    NetworkRequest req = (NetworkRequest)message.obj;
+                    NetworkRequest request = (NetworkRequest)getObject(message,
+                            NetworkRequest.class);
                     NetworkCallback callbacks = null;
                     synchronized(mCallbackMap) {
-                        callbacks = mCallbackMap.get(req);
+                        callbacks = mCallbackMap.get(request);
                     }
                     if (callbacks != null) {
                         callbacks.onUnavailable();
@@ -2200,33 +2208,37 @@
                     break;
                 }
                 case CALLBACK_CAP_CHANGED: {
-                    NetworkRequest request = getNetworkRequest(message);
+                    NetworkRequest request = (NetworkRequest)getObject(message,
+                            NetworkRequest.class);
                     NetworkCallback callbacks = getCallbacks(request);
                     if (callbacks != null) {
-                        Network network = getNetwork(message);
-                        NetworkCapabilities cap = mCm.getNetworkCapabilities(network);
+                        Network network = (Network)getObject(message, Network.class);
+                        NetworkCapabilities cap = (NetworkCapabilities)getObject(message,
+                                NetworkCapabilities.class);
 
                         callbacks.onCapabilitiesChanged(network, cap);
                     } else {
-                        Log.e(TAG, "callback not found for CHANGED message");
+                        Log.e(TAG, "callback not found for CAP_CHANGED message");
                     }
                     break;
                 }
                 case CALLBACK_IP_CHANGED: {
-                    NetworkRequest request = getNetworkRequest(message);
+                    NetworkRequest request = (NetworkRequest)getObject(message,
+                            NetworkRequest.class);
                     NetworkCallback callbacks = getCallbacks(request);
                     if (callbacks != null) {
-                        Network network = getNetwork(message);
-                        LinkProperties lp = mCm.getLinkProperties(network);
+                        Network network = (Network)getObject(message, Network.class);
+                        LinkProperties lp = (LinkProperties)getObject(message,
+                                LinkProperties.class);
 
                         callbacks.onLinkPropertiesChanged(network, lp);
                     } else {
-                        Log.e(TAG, "callback not found for CHANGED message");
+                        Log.e(TAG, "callback not found for IP_CHANGED message");
                     }
                     break;
                 }
                 case CALLBACK_RELEASED: {
-                    NetworkRequest req = (NetworkRequest)message.obj;
+                    NetworkRequest req = (NetworkRequest)getObject(message, NetworkRequest.class);
                     NetworkCallback callbacks = null;
                     synchronized(mCallbackMap) {
                         callbacks = mCallbackMap.remove(req);
@@ -2254,23 +2266,14 @@
             }
         }
 
-        private NetworkRequest getNetworkRequest(Message msg) {
-            return (NetworkRequest)(msg.obj);
+        private Object getObject(Message msg, Class c) {
+            return msg.getData().getParcelable(c.getSimpleName());
         }
         private NetworkCallback getCallbacks(NetworkRequest req) {
             synchronized(mCallbackMap) {
                 return mCallbackMap.get(req);
             }
         }
-        private Network getNetwork(Message msg) {
-            return new Network(msg.arg2);
-        }
-        private NetworkCallback removeCallbacks(Message msg) {
-            NetworkRequest req = (NetworkRequest)msg.obj;
-            synchronized(mCallbackMap) {
-                return mCallbackMap.remove(req);
-            }
-        }
     }
 
     private void incCallbackHandlerRefCount() {
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index ce70455..2099c3f 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -151,7 +151,7 @@
     }
 
     /**
-     * Returns true if this URI is relative, i.e. if it doesn't contain an
+     * Returns true if this URI is relative, i.e.&nbsp;if it doesn't contain an
      * explicit scheme.
      *
      * @return true if this URI is relative, false if it's absolute
@@ -159,7 +159,7 @@
     public abstract boolean isRelative();
 
     /**
-     * Returns true if this URI is absolute, i.e. if it contains an
+     * Returns true if this URI is absolute, i.e.&nbsp;if it contains an
      * explicit scheme.
      *
      * @return true if this URI is absolute, false if it's relative
@@ -176,8 +176,8 @@
     public abstract String getScheme();
 
     /**
-     * Gets the scheme-specific part of this URI, i.e. everything between the
-     * scheme separator ':' and the fragment separator '#'. If this is a
+     * Gets the scheme-specific part of this URI, i.e.&nbsp;everything between
+     * the scheme separator ':' and the fragment separator '#'. If this is a
      * relative URI, this method returns the entire URI. Decodes escaped octets.
      *
      * <p>Example: "//www.google.com/search?q=android"
@@ -187,8 +187,8 @@
     public abstract String getSchemeSpecificPart();
 
     /**
-     * Gets the scheme-specific part of this URI, i.e. everything between the
-     * scheme separator ':' and the fragment separator '#'. If this is a
+     * Gets the scheme-specific part of this URI, i.e.&nbsp;everything between
+     * the scheme separator ':' and the fragment separator '#'. If this is a
      * relative URI, this method returns the entire URI. Leaves escaped octets
      * intact.
      *
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index fca15ac..16250c7 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -395,7 +395,7 @@
     void setDefaultNetId(int netId);
     void clearDefaultNetId();
 
-    void setPermission(boolean internal, boolean changeNetState, in int[] uids);
+    void setPermission(String permission, in int[] uids);
     void clearPermission(in int[] uids);
 
     /**
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 0ee8d86f..47ea732 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -1725,7 +1725,7 @@
         for (int i = 0; i < numViolations; ++i) {
             if (LOG_V) Log.d(TAG, "strict mode violation stacks read from binder call.  i=" + i);
             ViolationInfo info = new ViolationInfo(p, !currentlyGathering);
-            if (info.crashInfo.stackTrace.length() > 10000) {
+            if (info.crashInfo.stackTrace != null && info.crashInfo.stackTrace.length() > 10000) {
                 // 10000 characters is way too large for this to be any sane kind of
                 // strict mode collection of stacks.  We've had a problem where we leave
                 // strict mode violations associated with the thread, and it keeps tacking
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 2315c74..37294e7 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -430,10 +430,14 @@
         }
     }
 
-   /**
+    /**
      * Used to determine whether the user making this call is subject to
      * teleportations.
-     * @return whether the user making this call is a goat
+     *
+     * <p>As of {@link android.os.Build.VERSION_CODES#L}, this method can
+     * now automatically identify goats using advanced goat recognition technology.</p>
+     *
+     * @return Returns true if the user making this call is a goat.
      */
     public boolean isUserAGoat() {
         return mContext.getPackageManager()
diff --git a/core/java/android/speech/RecognitionService.java b/core/java/android/speech/RecognitionService.java
index 45eb0bf..dcdbba78 100644
--- a/core/java/android/speech/RecognitionService.java
+++ b/core/java/android/speech/RecognitionService.java
@@ -28,6 +28,8 @@
 import android.os.RemoteException;
 import android.util.Log;
 
+import java.lang.ref.WeakReference;
+
 /**
  * This class provides a base class for recognition service implementations. This class should be
  * extended only in case you wish to implement a new speech recognizer. Please note that the
@@ -315,40 +317,46 @@
     }
 
     /** Binder of the recognition service */
-    private static class RecognitionServiceBinder extends IRecognitionService.Stub {
-        private RecognitionService mInternalService;
+    private static final class RecognitionServiceBinder extends IRecognitionService.Stub {
+        private final WeakReference<RecognitionService> mServiceRef;
 
         public RecognitionServiceBinder(RecognitionService service) {
-            mInternalService = service;
+            mServiceRef = new WeakReference<RecognitionService>(service);
         }
 
+        @Override
         public void startListening(Intent recognizerIntent, IRecognitionListener listener) {
             if (DBG) Log.d(TAG, "startListening called by:" + listener.asBinder());
-            if (mInternalService != null && mInternalService.checkPermissions(listener)) {
-                mInternalService.mHandler.sendMessage(Message.obtain(mInternalService.mHandler,
-                        MSG_START_LISTENING, mInternalService.new StartListeningArgs(
+            final RecognitionService service = mServiceRef.get();
+            if (service != null && service.checkPermissions(listener)) {
+                service.mHandler.sendMessage(Message.obtain(service.mHandler,
+                        MSG_START_LISTENING, service.new StartListeningArgs(
                                 recognizerIntent, listener)));
             }
         }
 
+        @Override
         public void stopListening(IRecognitionListener listener) {
             if (DBG) Log.d(TAG, "stopListening called by:" + listener.asBinder());
-            if (mInternalService != null && mInternalService.checkPermissions(listener)) {
-                mInternalService.mHandler.sendMessage(Message.obtain(mInternalService.mHandler,
+            final RecognitionService service = mServiceRef.get();
+            if (service != null && service.checkPermissions(listener)) {
+                service.mHandler.sendMessage(Message.obtain(service.mHandler,
                         MSG_STOP_LISTENING, listener));
             }
         }
 
+        @Override
         public void cancel(IRecognitionListener listener) {
             if (DBG) Log.d(TAG, "cancel called by:" + listener.asBinder());
-            if (mInternalService != null && mInternalService.checkPermissions(listener)) {
-                mInternalService.mHandler.sendMessage(Message.obtain(mInternalService.mHandler,
+            final RecognitionService service = mServiceRef.get();
+            if (service != null && service.checkPermissions(listener)) {
+                service.mHandler.sendMessage(Message.obtain(service.mHandler,
                         MSG_CANCEL, listener));
             }
         }
 
         public void clearReference() {
-            mInternalService = null;
+            mServiceRef.clear();
         }
     }
 }
diff --git a/core/java/android/text/method/KeyListener.java b/core/java/android/text/method/KeyListener.java
index bb79ecd..ce7054c 100644
--- a/core/java/android/text/method/KeyListener.java
+++ b/core/java/android/text/method/KeyListener.java
@@ -57,7 +57,7 @@
     
     /**
      * If the key listener wants to handle this key, return true,
-     * otherwise return false and the caller (i.e. the widget host)
+     * otherwise return false and the caller (i.e.&nbsp;the widget host)
      * will handle the key.
      */
     public boolean onKeyDown(View view, Editable text,
@@ -65,7 +65,7 @@
 
     /**
      * If the key listener wants to handle this key release, return true,
-     * otherwise return false and the caller (i.e. the widget host)
+     * otherwise return false and the caller (i.e.&nbsp;the widget host)
      * will handle the key.
      */
     public boolean onKeyUp(View view, Editable text,
@@ -73,7 +73,7 @@
     
     /**
      * If the key listener wants to other kinds of key events, return true,
-     * otherwise return false and the caller (i.e. the widget host)
+     * otherwise return false and the caller (i.e.&nbsp;the widget host)
      * will handle the key.
      */
     public boolean onKeyOther(View view, Editable text, KeyEvent event);
diff --git a/core/java/android/transition/ChangeTransform.java b/core/java/android/transition/ChangeTransform.java
index 1b8d57c..3fd28a6 100644
--- a/core/java/android/transition/ChangeTransform.java
+++ b/core/java/android/transition/ChangeTransform.java
@@ -228,7 +228,8 @@
         }
 
         // Next handle the normal matrix transform:
-        ObjectAnimator transformAnimator = createTransformAnimator(startValues, endValues);
+        ObjectAnimator transformAnimator = createTransformAnimator(startValues, endValues,
+                handleParentChange);
 
         if (handleParentChange && transformAnimator != null && mUseOverlay) {
             createGhostView(sceneRoot, startValues, endValues);
@@ -238,7 +239,7 @@
     }
 
     private ObjectAnimator createTransformAnimator(TransitionValues startValues,
-            TransitionValues endValues) {
+            TransitionValues endValues, final boolean handleParentChange) {
         Matrix startMatrix = (Matrix) startValues.values.get(PROPNAME_MATRIX);
         Matrix endMatrix = (Matrix) endValues.values.get(PROPNAME_MATRIX);
 
@@ -277,7 +278,12 @@
             @Override
             public void onAnimationEnd(Animator animation) {
                 if (!mIsCanceled) {
-                    setCurrentMatrix(finalEndMatrix);
+                    if (handleParentChange && mUseOverlay) {
+                        setCurrentMatrix(finalEndMatrix);
+                    } else {
+                        view.setTagInternal(R.id.transitionTransform, null);
+                        view.setTagInternal(R.id.parentMatrix, null);
+                    }
                 }
                 ANIMATION_MATRIX_PROPERTY.set(view, null);
                 transforms.restore(view);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index b454681..1ecc8d9 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -5033,7 +5033,7 @@
      * <strong>Note:</strong> When a View clears focus the framework is trying
      * to give focus to the first focusable View from the top. Hence, if this
      * View is the first from the top that can take focus, then all callbacks
-     * related to clearing focus will be invoked after wich the framework will
+     * related to clearing focus will be invoked after which the framework will
      * give focus to this view.
      * </p>
      */
@@ -6379,7 +6379,7 @@
      * @see #setFitsSystemWindows(boolean)
      * @see #setSystemUiVisibility(int)
      *
-     * @deprecated As of API XX use {@link #dispatchApplyWindowInsets(WindowInsets)} to apply
+     * @deprecated As of API 20 use {@link #dispatchApplyWindowInsets(WindowInsets)} to apply
      * insets to views. Views should override {@link #onApplyWindowInsets(WindowInsets)} or use
      * {@link #setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener)}
      * to implement handling their own insets.
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index c51d8a7..ff992d3 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -75,7 +75,7 @@
  * behavior you should adopt for a particular call, please mimic the
  * default TextView implementation in the latest Android version, and
  * if you decide to drift from it, please consider carefully that
- * inconsistencies in text edition behavior is almost universally felt
+ * inconsistencies in text editor behavior is almost universally felt
  * as a bad thing by users.</p>
  *
  * <h3>Cursors, selections and compositions</h3>
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index 23f911c..5b604cd 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -1403,7 +1403,7 @@
          *        {@link android.widget.RelativeLayout RelativeLayout}, such as
          *         ALIGN_WITH_PARENT_LEFT.
          * @param anchor The id of another view to use as an anchor,
-         *        or a boolean value(represented as {@link RelativeLayout#TRUE})
+         *        or a boolean value (represented as {@link RelativeLayout#TRUE}
          *        for true or 0 for false).  For verbs that don't refer to another sibling
          *        (for example, ALIGN_WITH_PARENT_BOTTOM) just use -1.
          * @see #addRule(int)
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index a80d70a..5cdee53 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -7378,8 +7378,8 @@
      * to turn off ellipsizing.
      *
      * If {@link #setMaxLines} has been used to set two or more lines,
-     * {@link android.text.TextUtils.TruncateAt#END} and
-     * {@link android.text.TextUtils.TruncateAt#MARQUEE}* are only supported
+     * only {@link android.text.TextUtils.TruncateAt#END} and
+     * {@link android.text.TextUtils.TruncateAt#MARQUEE} are supported
      * (other ellipsizing types will not do anything).
      *
      * @attr ref android.R.styleable#TextView_ellipsize
diff --git a/core/res/res/drawable-hdpi/ic_audio_alarm_alpha.png b/core/res/res/drawable-hdpi/ic_audio_alarm_alpha.png
deleted file mode 100644
index 1b41de4..0000000
--- a/core/res/res/drawable-hdpi/ic_audio_alarm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_audio_alarm_mute_alpha.png b/core/res/res/drawable-hdpi/ic_audio_alarm_mute_alpha.png
deleted file mode 100644
index 45ed7b6..0000000
--- a/core/res/res/drawable-hdpi/ic_audio_alarm_mute_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_audio_ring_notif_am_alpha.png b/core/res/res/drawable-hdpi/ic_audio_ring_notif_am_alpha.png
deleted file mode 100644
index a89f45f..0000000
--- a/core/res/res/drawable-hdpi/ic_audio_ring_notif_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_audio_ring_notif_mute_am_alpha.png b/core/res/res/drawable-hdpi/ic_audio_ring_notif_mute_am_alpha.png
deleted file mode 100644
index d03bade..0000000
--- a/core/res/res/drawable-hdpi/ic_audio_ring_notif_mute_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_audio_ring_notif_vibrate_am_alpha.png b/core/res/res/drawable-hdpi/ic_audio_ring_notif_vibrate_am_alpha.png
deleted file mode 100644
index 4199106..0000000
--- a/core/res/res/drawable-hdpi/ic_audio_ring_notif_vibrate_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_audio_vol_am_alpha.png b/core/res/res/drawable-hdpi/ic_audio_vol_am_alpha.png
deleted file mode 100644
index 6ea2693..0000000
--- a/core/res/res/drawable-hdpi/ic_audio_vol_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_audio_vol_mute_am_alpha.png b/core/res/res/drawable-hdpi/ic_audio_vol_mute_am_alpha.png
deleted file mode 100644
index 4256385..0000000
--- a/core/res/res/drawable-hdpi/ic_audio_vol_mute_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_audio_alarm_alpha.png b/core/res/res/drawable-mdpi/ic_audio_alarm_alpha.png
deleted file mode 100644
index fab95aa..0000000
--- a/core/res/res/drawable-mdpi/ic_audio_alarm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_audio_alarm_mute_alpha.png b/core/res/res/drawable-mdpi/ic_audio_alarm_mute_alpha.png
deleted file mode 100644
index 451e932..0000000
--- a/core/res/res/drawable-mdpi/ic_audio_alarm_mute_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_audio_ring_notif_am_alpha.png b/core/res/res/drawable-mdpi/ic_audio_ring_notif_am_alpha.png
deleted file mode 100644
index 1ce4f52..0000000
--- a/core/res/res/drawable-mdpi/ic_audio_ring_notif_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_audio_ring_notif_mute_am_alpha.png b/core/res/res/drawable-mdpi/ic_audio_ring_notif_mute_am_alpha.png
deleted file mode 100644
index cb17415..0000000
--- a/core/res/res/drawable-mdpi/ic_audio_ring_notif_mute_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_audio_ring_notif_vibrate_am_alpha.png b/core/res/res/drawable-mdpi/ic_audio_ring_notif_vibrate_am_alpha.png
deleted file mode 100644
index 2d99b76..0000000
--- a/core/res/res/drawable-mdpi/ic_audio_ring_notif_vibrate_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_audio_vol_am_alpha.png b/core/res/res/drawable-mdpi/ic_audio_vol_am_alpha.png
deleted file mode 100644
index c32fdbc0d..0000000
--- a/core/res/res/drawable-mdpi/ic_audio_vol_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_audio_vol_mute_am_alpha.png b/core/res/res/drawable-mdpi/ic_audio_vol_mute_am_alpha.png
deleted file mode 100644
index 0dfc21f..0000000
--- a/core/res/res/drawable-mdpi/ic_audio_vol_mute_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_audio_alarm_alpha.png b/core/res/res/drawable-xhdpi/ic_audio_alarm_alpha.png
deleted file mode 100644
index c1f56a1..0000000
--- a/core/res/res/drawable-xhdpi/ic_audio_alarm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_audio_alarm_mute_alpha.png b/core/res/res/drawable-xhdpi/ic_audio_alarm_mute_alpha.png
deleted file mode 100644
index 0d7034f..0000000
--- a/core/res/res/drawable-xhdpi/ic_audio_alarm_mute_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_audio_ring_notif_am_alpha.png b/core/res/res/drawable-xhdpi/ic_audio_ring_notif_am_alpha.png
deleted file mode 100644
index 0df1934..0000000
--- a/core/res/res/drawable-xhdpi/ic_audio_ring_notif_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_audio_ring_notif_mute_am_alpha.png b/core/res/res/drawable-xhdpi/ic_audio_ring_notif_mute_am_alpha.png
deleted file mode 100644
index 85acb93..0000000
--- a/core/res/res/drawable-xhdpi/ic_audio_ring_notif_mute_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_audio_ring_notif_vibrate_am_alpha.png b/core/res/res/drawable-xhdpi/ic_audio_ring_notif_vibrate_am_alpha.png
deleted file mode 100644
index 122c708..0000000
--- a/core/res/res/drawable-xhdpi/ic_audio_ring_notif_vibrate_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_audio_vol_am_alpha.png b/core/res/res/drawable-xhdpi/ic_audio_vol_am_alpha.png
deleted file mode 100644
index 4e2e20e..0000000
--- a/core/res/res/drawable-xhdpi/ic_audio_vol_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_audio_vol_mute_am_alpha.png b/core/res/res/drawable-xhdpi/ic_audio_vol_mute_am_alpha.png
deleted file mode 100644
index 64a5215..0000000
--- a/core/res/res/drawable-xhdpi/ic_audio_vol_mute_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_audio_alarm_alpha.png b/core/res/res/drawable-xxhdpi/ic_audio_alarm_alpha.png
deleted file mode 100755
index c1c3d35..0000000
--- a/core/res/res/drawable-xxhdpi/ic_audio_alarm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_audio_alarm_mute_alpha.png b/core/res/res/drawable-xxhdpi/ic_audio_alarm_mute_alpha.png
deleted file mode 100644
index 4bcee68..0000000
--- a/core/res/res/drawable-xxhdpi/ic_audio_alarm_mute_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_audio_ring_notif_am_alpha.png b/core/res/res/drawable-xxhdpi/ic_audio_ring_notif_am_alpha.png
deleted file mode 100644
index 699711c..0000000
--- a/core/res/res/drawable-xxhdpi/ic_audio_ring_notif_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_audio_ring_notif_mute_am_alpha.png b/core/res/res/drawable-xxhdpi/ic_audio_ring_notif_mute_am_alpha.png
deleted file mode 100644
index 19d92ba..0000000
--- a/core/res/res/drawable-xxhdpi/ic_audio_ring_notif_mute_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_audio_ring_notif_vibrate_am_alpha.png b/core/res/res/drawable-xxhdpi/ic_audio_ring_notif_vibrate_am_alpha.png
deleted file mode 100644
index fdcfd56..0000000
--- a/core/res/res/drawable-xxhdpi/ic_audio_ring_notif_vibrate_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_audio_vol_am_alpha.png b/core/res/res/drawable-xxhdpi/ic_audio_vol_am_alpha.png
deleted file mode 100755
index 15b6311..0000000
--- a/core/res/res/drawable-xxhdpi/ic_audio_vol_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_audio_vol_mute_am_alpha.png b/core/res/res/drawable-xxhdpi/ic_audio_vol_mute_am_alpha.png
deleted file mode 100644
index b8f4111..0000000
--- a/core/res/res/drawable-xxhdpi/ic_audio_vol_mute_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/ic_audio_alarm.xml b/core/res/res/drawable/ic_audio_alarm.xml
index d3e5470..fc4bf10 100644
--- a/core/res/res/drawable/ic_audio_alarm.xml
+++ b/core/res/res/drawable/ic_audio_alarm.xml
@@ -1,19 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!--
+Copyright (C) 2014 The Android Open Source Project
 
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
+   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
+         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.
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
 -->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_audio_alarm_alpha"
-    android:tint="?attr/colorControlNormal" />
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="32.0dp"
+        android:height="32.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="?android:attr/colorControlNormal"
+        android:pathData="M44.0,11.44l-9.19,-7.71 -2.57,3.06 9.19,7.71 2.57,-3.06zm-28.24,-4.66l-2.57,-3.06 -9.19,7.71 2.57,3.06 9.19,-7.71zm9.24,9.22l-3.0,0.0l0.0,12.0l9.49,5.71 1.51,-2.47 -8.0,-4.74l0.0,-10.5zm-1.01,-8.0c-9.95,0.0 -17.99,8.06 -17.99,18.0s8.04,18.0 17.99,18.0 18.01,-8.06 18.01,-18.0 -8.06,-18.0 -18.01,-18.0zm0.01,32.0c-7.73,0.0 -14.0,-6.27 -14.0,-14.0s6.27,-14.0 14.0,-14.0 14.0,6.27 14.0,14.0 -6.26,14.0 -14.0,14.0z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_audio_alarm_mute.xml b/core/res/res/drawable/ic_audio_alarm_mute.xml
index 7d85872..1d24081 100644
--- a/core/res/res/drawable/ic_audio_alarm_mute.xml
+++ b/core/res/res/drawable/ic_audio_alarm_mute.xml
@@ -1,19 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!--
+Copyright (C) 2014 The Android Open Source Project
 
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
+   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
+         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.
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
 -->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_audio_alarm_mute_alpha"
-    android:tint="?attr/colorControlNormal" />
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="32.0dp"
+        android:height="32.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="?android:attr/colorControlNormal"
+        android:pathData="M24.0,12.0c7.73,0.0 14.0,6.27 14.0,14.0 0.0,1.69 -0.31,3.3 -0.86,4.8l3.04,3.04c1.16,-2.37 1.82,-5.03 1.82,-7.84 0.0,-9.94 -8.06,-18.0 -18.01,-18.0 -2.81,0.0 -5.46,0.66 -7.84,1.81l3.05,3.05c1.5,-0.55 3.11,-0.86 4.8,-0.86zm20.0,-0.56l-9.19,-7.71 -2.57,3.06 9.19,7.71 2.57,-3.06zm-38.16,-6.85l-2.55,2.54 2.66,2.66 -2.22,1.86 2.84,2.84 2.22,-1.86 1.6,1.6c-2.73,3.16 -4.39,7.27 -4.39,11.77 0.0,9.94 8.04,18.0 17.99,18.0 4.51,0.0 8.62,-1.67 11.77,-4.4l4.4,4.4 2.54,-2.55 -34.91,-34.91 -1.95,-1.95zm27.1,32.19c-2.43,2.01 -5.54,3.22 -8.94,3.22 -7.73,0.0 -14.0,-6.27 -14.0,-14.0 0.0,-3.4 1.21,-6.51 3.22,-8.94l19.72,19.72zm-16.91,-30.23l-2.84,-2.84 -1.7,1.43 2.84,2.84 1.7,-1.43z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_audio_vol.xml b/core/res/res/drawable/ic_audio_vol.xml
index 8d07ded..a55be93 100644
--- a/core/res/res/drawable/ic_audio_vol.xml
+++ b/core/res/res/drawable/ic_audio_vol.xml
@@ -1,23 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
-/*
- * Copyright 2013, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
+Copyright (C) 2014 The Android Open Source Project
 
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_audio_vol_am_alpha"
-    android:autoMirrored="true"
-    android:tint="?attr/colorControlNormal" />
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="32.0dp"
+        android:height="32.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="?android:attr/colorControlNormal"
+        android:pathData="M6.0,18.0l0.0,12.0l8.0,0.0l10.0,10.0L24.0,8.0L14.0,18.0L6.0,18.0zm27.0,6.0c0.0,-3.53 -2.04,-6.58 -5.0,-8.05l0.0,16.11c2.96,-1.48 5.0,-4.53 5.0,-8.06zM28.0,6.46l0.0,4.13c5.78,1.72 10.0,7.07 10.0,13.41s-4.22,11.69 -10.0,13.41l0.0,4.13c8.01,-1.82 14.0,-8.97 14.0,-17.54S36.01,8.28 28.0,6.46z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_audio_vol_mute.xml b/core/res/res/drawable/ic_audio_vol_mute.xml
index edbdb23..ab50a7d 100644
--- a/core/res/res/drawable/ic_audio_vol_mute.xml
+++ b/core/res/res/drawable/ic_audio_vol_mute.xml
@@ -1,23 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
-/*
- * Copyright 2013, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
+Copyright (C) 2014 The Android Open Source Project
 
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_audio_vol_mute_am_alpha"
-    android:autoMirrored="true"
-    android:tint="?attr/colorControlNormal" />
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="32.0dp"
+        android:height="32.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="?android:attr/colorControlNormal"
+        android:pathData="M33.0,24.0c0.0,-3.53 -2.04,-6.58 -5.0,-8.05l0.0,4.42l4.91,4.91c0.06,-0.42 0.09,-0.85 0.09,-1.28zm5.0,0.0c0.0,1.88 -0.41,3.65 -1.08,5.28l3.03,3.03C41.25,29.82 42.0,27.0 42.0,24.0c0.0,-8.56 -5.99,-15.72 -14.0,-17.54l0.0,4.13c5.78,1.72 10.0,7.07 10.0,13.41zM8.55,6.0L6.0,8.55 15.45,18.0L6.0,18.0l0.0,12.0l8.0,0.0l10.0,10.0L24.0,26.55l8.51,8.51c-1.34,1.03 -2.85,1.86 -4.51,2.36l0.0,4.13c2.75,-0.63 5.26,-1.89 7.37,-3.62L39.45,42.0 42.0,39.45l-18.0,-18.0L8.55,6.0zM24.0,8.0l-4.18,4.18L24.0,16.36L24.0,8.0z"/>
+</vector>
diff --git a/docs/html/guide/topics/resources/drawable-resource.jd b/docs/html/guide/topics/resources/drawable-resource.jd
index dee28fe..06bd2d0 100644
--- a/docs/html/guide/topics/resources/drawable-resource.jd
+++ b/docs/html/guide/topics/resources/drawable-resource.jd
@@ -67,7 +67,7 @@
 
 <h2 id="Bitmap">Bitmap</h2>
 
-<p>A bitmap image. Android supports bitmap files in a three formats:
+<p>A bitmap image. Android supports bitmap files in three formats:
 {@code .png} (preferred), {@code .jpg} (acceptable), {@code .gif} (discouraged).</p>
 
 <p>You can reference a bitmap file directly, using the filename as the resource ID, or create an
diff --git a/docs/html/sdk/installing/index.jd b/docs/html/sdk/installing/index.jd
index 304b53d..ec0e2f8 100644
--- a/docs/html/sdk/installing/index.jd
+++ b/docs/html/sdk/installing/index.jd
@@ -112,7 +112,7 @@
       your JDK folder, for example <code>C:\Program Files\Java\jdk1.7.0_21</code>.</p>
     </p>
     </li>
-    
+
   </ol>
 
 
@@ -260,10 +260,10 @@
 
 
 <h5 id="Troubleshooting" style="margin-bottom:15px"><a href='' class="expandable"
-  onclick="toggleExpandable(this,'#ubuntu-trouble');return false;"
+  onclick="toggleExpandable(this,'#UbuntuTrouble');return false;"
   >Troubleshooting Ubuntu</a></h5>
 
-<div id="ubuntu-trouble" style="display:none">
+<div id="UbuntuTrouble" style="display:none">
 <ul>
   <li>If you need help installing and configuring Java on your
     development machine, you might find these resources helpful:
@@ -416,6 +416,9 @@
   }
 }
 
-
-
+/* direct link to ubuntu troubleshooting */
+if ( document.location.href.indexOf('#UbuntuTrouble') > -1 ) {
+  $(".linux.docs").show();
+  toggleExpandable(this,'#UbuntuTrouble');
+}
 </script>
diff --git a/docs/html/sdk/installing/installing-adt.jd b/docs/html/sdk/installing/installing-adt.jd
index 5a433d4..c8200aa 100644
--- a/docs/html/sdk/installing/installing-adt.jd
+++ b/docs/html/sdk/installing/installing-adt.jd
@@ -1,8 +1,8 @@
 page.title=Installing the Eclipse Plugin
-adt.zip.version=23.0.3
-adt.zip.download=ADT-23.0.3.zip
-adt.zip.bytes=103321934
-adt.zip.checksum=ab2f5e2fbbdddeeb7dfd02cd4046538a
+adt.zip.version=23.0.4
+adt.zip.download=ADT-23.0.4.zip
+adt.zip.bytes=103336810
+adt.zip.checksum=91a43dcf686ab73dec2c08b77243492b
 
 @jd:body
 
diff --git a/docs/html/tools/sdk/eclipse-adt.jd b/docs/html/tools/sdk/eclipse-adt.jd
index cf33200..469d11f 100644
--- a/docs/html/tools/sdk/eclipse-adt.jd
+++ b/docs/html/tools/sdk/eclipse-adt.jd
@@ -53,9 +53,44 @@
 <p>For a summary of all known issues in ADT, see <a
 href="http://tools.android.com/knownissues">http://tools.android.com/knownissues</a>.</p>
 
+
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>ADT 23.0.4</a> <em>(October 2014)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+<dl>
+  <dt>Dependencies:</dt>
+
+  <dd>
+    <ul>
+      <li>Java 7 or higher is required if you are targeting the L Developer Preview.</li>
+      <li>Java 1.6 or higher is required if you are targeting other releases.</li>
+      <li>Eclipse Indigo (Version 3.7.2) or higher is required.</li>
+      <li>This version of ADT is designed for use with
+        <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r23.0.4</a>.
+        If you haven't already installed SDK Tools r23.0.4 into your SDK, use the
+        Android SDK Manager to do so.</li>
+    </ul>
+  </dd>
+
+  <dt>General Notes:</dt>
+  <dd>
+    <ul>
+        <li>Fixed duplicate devices in AVD for Wear and TV.</li>
+    </ul>
+  </dd>
+</dl>
+</div>
+</div>
+
+
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>ADT 23.0.3</a> <em>(August 2014)</em>
   </p>
 
diff --git a/docs/html/training/basics/fragments/fragment-ui.jd b/docs/html/training/basics/fragments/fragment-ui.jd
index 14469bf..4fa5b70 100644
--- a/docs/html/training/basics/fragments/fragment-ui.jd
+++ b/docs/html/training/basics/fragments/fragment-ui.jd
@@ -66,9 +66,9 @@
 initial fragment(s) to the activity during the activity's
 {@link android.app.Activity#onCreate onCreate()} method.</p>
 
-<p>An important rule when dealing with fragments&mdash;especially those that you add at
-runtime&mdash;is that the fragment must have a container {@link android.view.View} in the layout in
-which the fragment's layout will reside.</p>
+<p>An important rule when dealing with fragments&mdash;especially when adding fragments at
+runtime&mdash;is that your activity layout must include a container {@link android.view.View}
+in which you can insert the fragment.</p>
 
 <p>The following layout is an alternative to the layout shown in the <a
 href="creating.html">previous lesson</a> that shows only one fragment at a time. In order to replace
diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
index 4c8b4f1..9fb3fb4 100644
--- a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
@@ -257,7 +257,7 @@
     public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
             throws XmlPullParserException, IOException {
 
-        final TypedArray a = r.obtainAttributes(attrs, R.styleable.AnimatedRotateDrawable);
+        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.AnimatedRotateDrawable);
 
         super.inflateWithAttributes(r, parser, a, R.styleable.AnimatedRotateDrawable_visible);
 
diff --git a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
index d78138bc..cb09bbf 100644
--- a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
@@ -357,7 +357,8 @@
     public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
             @NonNull AttributeSet attrs, @Nullable Theme theme)
             throws XmlPullParserException, IOException {
-        final TypedArray a = r.obtainAttributes(attrs, R.styleable.AnimatedStateListDrawable);
+        final TypedArray a = obtainAttributes(
+                r, theme, attrs, R.styleable.AnimatedStateListDrawable);
 
         super.inflateWithAttributes(r, parser, a, R.styleable.AnimatedStateListDrawable_visible);
 
diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java
index d87e8e4..9a9fd82 100644
--- a/graphics/java/android/graphics/drawable/AnimationDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java
@@ -272,7 +272,7 @@
     public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
             throws XmlPullParserException, IOException {
 
-        TypedArray a = r.obtainAttributes(attrs,
+        TypedArray a = obtainAttributes(r, theme, attrs,
                 com.android.internal.R.styleable.AnimationDrawable);
 
         super.inflateWithAttributes(r, parser, a,
@@ -300,7 +300,8 @@
                 continue;
             }
 
-            a = r.obtainAttributes(attrs, com.android.internal.R.styleable.AnimationDrawableItem);
+            a = obtainAttributes(
+                    r, theme, attrs, com.android.internal.R.styleable.AnimationDrawableItem);
             int duration = a.getInt(
                     com.android.internal.R.styleable.AnimationDrawableItem_duration, -1);
             if (duration < 0) {
diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java
index 61ef81b..40711cf 100644
--- a/graphics/java/android/graphics/drawable/ClipDrawable.java
+++ b/graphics/java/android/graphics/drawable/ClipDrawable.java
@@ -81,7 +81,8 @@
 
         int type;
 
-        TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.ClipDrawable);
+        TypedArray a = obtainAttributes(
+                r, theme, attrs, com.android.internal.R.styleable.ClipDrawable);
 
         int orientation = a.getInt(
                 com.android.internal.R.styleable.ClipDrawable_clipOrientation,
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index 384226f..961d1607 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -84,7 +84,7 @@
     @Override
     public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
             throws XmlPullParserException, IOException {
-        final TypedArray a = r.obtainAttributes(attrs, R.styleable.InsetDrawable);
+        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.InsetDrawable);
         super.inflateWithAttributes(r, parser, a, R.styleable.InsetDrawable_visible);
 
         mInsetState.mDrawable = null;
diff --git a/graphics/java/android/graphics/drawable/LevelListDrawable.java b/graphics/java/android/graphics/drawable/LevelListDrawable.java
index 7271b0e..bc1c61d 100644
--- a/graphics/java/android/graphics/drawable/LevelListDrawable.java
+++ b/graphics/java/android/graphics/drawable/LevelListDrawable.java
@@ -105,7 +105,7 @@
                 continue;
             }
 
-            TypedArray a = r.obtainAttributes(attrs,
+            TypedArray a = obtainAttributes(r, theme, attrs,
                     com.android.internal.R.styleable.LevelListDrawableItem);
 
             low = a.getInt(
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index 70482a6..55c9637 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -399,7 +399,7 @@
     @Override
     public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
             throws XmlPullParserException, IOException {
-        final TypedArray a = r.obtainAttributes(attrs,
+        final TypedArray a = obtainAttributes(r, theme, attrs,
                 com.android.internal.R.styleable.RotateDrawable);
 
         super.inflateWithAttributes(r, parser, a,
diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java
index b40038a..b990249 100644
--- a/graphics/java/android/graphics/drawable/ScaleDrawable.java
+++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java
@@ -93,7 +93,8 @@
 
         int type;
 
-        TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.ScaleDrawable);
+        TypedArray a = obtainAttributes(
+                r, theme, attrs, com.android.internal.R.styleable.ScaleDrawable);
 
         float sw = getPercent(a, com.android.internal.R.styleable.ScaleDrawable_scaleWidth);
         float sh = getPercent(a, com.android.internal.R.styleable.ScaleDrawable_scaleHeight);
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
index 4c513e9..2eb8a80 100644
--- a/graphics/java/android/graphics/drawable/StateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -118,7 +118,7 @@
     public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
             throws XmlPullParserException, IOException {
 
-        final TypedArray a = r.obtainAttributes(attrs, R.styleable.StateListDrawable);
+        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.StateListDrawable);
 
         super.inflateWithAttributes(r, parser, a,
                 R.styleable.StateListDrawable_visible);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 8084eda..3453a67 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -694,12 +694,11 @@
         if (Settings.CALL_METHOD_GET_SYSTEM.equals(method)) {
             if (LOCAL_LOGV) Slog.v(TAG, "call(system:" + request + ") for " + callingUser);
             // Check if this request should be (re)directed to the primary user's db
-            if (callingUser == UserHandle.USER_OWNER
-                    || shouldShadowParentProfile(callingUser, sSystemCloneToManagedKeys, request)) {
-                dbHelper = getOrEstablishDatabase(UserHandle.USER_OWNER);
-            } else {
-                dbHelper = getOrEstablishDatabase(callingUser);
+            if (callingUser != UserHandle.USER_OWNER
+                    && shouldShadowParentProfile(callingUser, sSystemCloneToManagedKeys, request)) {
+                callingUser = UserHandle.USER_OWNER;
             }
+            dbHelper = getOrEstablishDatabase(callingUser);
             cache = sSystemCaches.get(callingUser);
             return lookupValue(dbHelper, TABLE_SYSTEM, cache, request);
         }
@@ -713,10 +712,9 @@
                                 UserManager.DISALLOW_SHARE_LOCATION, new UserHandle(callingUser))) {
                     return sSecureCaches.get(callingUser).putIfAbsent(request, "");
                 }
-                dbHelper = getOrEstablishDatabase(UserHandle.USER_OWNER);
-            } else {
-                dbHelper = getOrEstablishDatabase(callingUser);
+                callingUser = UserHandle.USER_OWNER;
             }
+            dbHelper = getOrEstablishDatabase(callingUser);
             cache = sSecureCaches.get(callingUser);
             return lookupValue(dbHelper, TABLE_SECURE, cache, request);
         }
diff --git a/packages/SystemUI/res/drawable/ic_audio_alarm.xml b/packages/SystemUI/res/drawable/ic_audio_alarm.xml
new file mode 100644
index 0000000..5dd158e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_audio_alarm.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="32.0dp"
+        android:height="32.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="#ffffffff"
+        android:pathData="M44.0,11.44l-9.19,-7.71 -2.57,3.06 9.19,7.71 2.57,-3.06zm-28.24,-4.66l-2.57,-3.06 -9.19,7.71 2.57,3.06 9.19,-7.71zm9.24,9.22l-3.0,0.0l0.0,12.0l9.49,5.71 1.51,-2.47 -8.0,-4.74l0.0,-10.5zm-1.01,-8.0c-9.95,0.0 -17.99,8.06 -17.99,18.0s8.04,18.0 17.99,18.0 18.01,-8.06 18.01,-18.0 -8.06,-18.0 -18.01,-18.0zm0.01,32.0c-7.73,0.0 -14.0,-6.27 -14.0,-14.0s6.27,-14.0 14.0,-14.0 14.0,6.27 14.0,14.0 -6.26,14.0 -14.0,14.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_audio_alarm_mute.xml b/packages/SystemUI/res/drawable/ic_audio_alarm_mute.xml
new file mode 100644
index 0000000..af445e3
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_audio_alarm_mute.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="32.0dp"
+        android:height="32.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="#ffffffff"
+        android:pathData="M24.0,12.0c7.73,0.0 14.0,6.27 14.0,14.0 0.0,1.69 -0.31,3.3 -0.86,4.8l3.04,3.04c1.16,-2.37 1.82,-5.03 1.82,-7.84 0.0,-9.94 -8.06,-18.0 -18.01,-18.0 -2.81,0.0 -5.46,0.66 -7.84,1.81l3.05,3.05c1.5,-0.55 3.11,-0.86 4.8,-0.86zm20.0,-0.56l-9.19,-7.71 -2.57,3.06 9.19,7.71 2.57,-3.06zm-38.16,-6.85l-2.55,2.54 2.66,2.66 -2.22,1.86 2.84,2.84 2.22,-1.86 1.6,1.6c-2.73,3.16 -4.39,7.27 -4.39,11.77 0.0,9.94 8.04,18.0 17.99,18.0 4.51,0.0 8.62,-1.67 11.77,-4.4l4.4,4.4 2.54,-2.55 -34.91,-34.91 -1.95,-1.95zm27.1,32.19c-2.43,2.01 -5.54,3.22 -8.94,3.22 -7.73,0.0 -14.0,-6.27 -14.0,-14.0 0.0,-3.4 1.21,-6.51 3.22,-8.94l19.72,19.72zm-16.91,-30.23l-2.84,-2.84 -1.7,1.43 2.84,2.84 1.7,-1.43z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_audio_vol.xml b/packages/SystemUI/res/drawable/ic_audio_vol.xml
new file mode 100644
index 0000000..76c14b1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_audio_vol.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="32.0dp"
+        android:height="32.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="#ffffffff"
+        android:pathData="M6.0,18.0l0.0,12.0l8.0,0.0l10.0,10.0L24.0,8.0L14.0,18.0L6.0,18.0zm27.0,6.0c0.0,-3.53 -2.04,-6.58 -5.0,-8.05l0.0,16.11c2.96,-1.48 5.0,-4.53 5.0,-8.06zM28.0,6.46l0.0,4.13c5.78,1.72 10.0,7.07 10.0,13.41s-4.22,11.69 -10.0,13.41l0.0,4.13c8.01,-1.82 14.0,-8.97 14.0,-17.54S36.01,8.28 28.0,6.46z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_audio_vol_mute.xml b/packages/SystemUI/res/drawable/ic_audio_vol_mute.xml
new file mode 100644
index 0000000..e158f7b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_audio_vol_mute.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="32.0dp"
+        android:height="32.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="#ffffffff"
+        android:pathData="M33.0,24.0c0.0,-3.53 -2.04,-6.58 -5.0,-8.05l0.0,4.42l4.91,4.91c0.06,-0.42 0.09,-0.85 0.09,-1.28zm5.0,0.0c0.0,1.88 -0.41,3.65 -1.08,5.28l3.03,3.03C41.25,29.82 42.0,27.0 42.0,24.0c0.0,-8.56 -5.99,-15.72 -14.0,-17.54l0.0,4.13c5.78,1.72 10.0,7.07 10.0,13.41zM8.55,6.0L6.0,8.55 15.45,18.0L6.0,18.0l0.0,12.0l8.0,0.0l10.0,10.0L24.0,26.55l8.51,8.51c-1.34,1.03 -2.85,1.86 -4.51,2.36l0.0,4.13c2.75,-0.63 5.26,-1.89 7.37,-3.62L39.45,42.0 42.0,39.45l-18.0,-18.0L8.55,6.0zM24.0,8.0l-4.18,4.18L24.0,16.36L24.0,8.0z"/>
+</vector>
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
index 40bdea2..360dee5 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
@@ -127,6 +127,9 @@
             .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
             .build();
 
+    private static final int IC_AUDIO_VOL = com.android.systemui.R.drawable.ic_audio_vol;
+    private static final int IC_AUDIO_VOL_MUTE = com.android.systemui.R.drawable.ic_audio_vol_mute;
+
     private final String mTag;
     protected final Context mContext;
     private final AudioManager mAudioManager;
@@ -182,13 +185,13 @@
                 false),
         AlarmStream(AudioManager.STREAM_ALARM,
                 R.string.volume_alarm,
-                R.drawable.ic_audio_alarm,
-                R.drawable.ic_audio_alarm_mute,
+                com.android.systemui.R.drawable.ic_audio_alarm,
+                com.android.systemui.R.drawable.ic_audio_alarm_mute,
                 false),
         MediaStream(AudioManager.STREAM_MUSIC,
                 R.string.volume_icon_description_media,
-                R.drawable.ic_audio_vol,
-                R.drawable.ic_audio_vol_mute,
+                IC_AUDIO_VOL,
+                IC_AUDIO_VOL_MUTE,
                 true),
         NotificationStream(AudioManager.STREAM_NOTIFICATION,
                 R.string.volume_icon_description_notification,
@@ -198,8 +201,8 @@
         // for now, use media resources for master volume
         MasterStream(STREAM_MASTER,
                 R.string.volume_icon_description_media, //FIXME should have its own description
-                R.drawable.ic_audio_vol,
-                R.drawable.ic_audio_vol_mute,
+                IC_AUDIO_VOL,
+                IC_AUDIO_VOL_MUTE,
                 false),
         RemoteStream(STREAM_REMOTE_MUSIC,
                 R.string.volume_icon_description_media, //FIXME should have its own description
@@ -994,7 +997,7 @@
                         AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) != 0) {
                     setMusicIcon(R.drawable.ic_audio_bt, R.drawable.ic_audio_bt_mute);
                 } else {
-                    setMusicIcon(R.drawable.ic_audio_vol, R.drawable.ic_audio_vol_mute);
+                    setMusicIcon(IC_AUDIO_VOL, IC_AUDIO_VOL_MUTE);
                 }
                 break;
             }
diff --git a/preloaded-classes b/preloaded-classes
index 649255f..7686431 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -804,9 +804,6 @@
 android.hardware.input.InputDeviceIdentifier$1
 android.hardware.input.InputManager
 android.hardware.input.InputManager$InputDevicesChangedListener
-android.hardware.location.ActivityRecognitionHardware
-android.hardware.location.IActivityRecognitionHardware
-android.hardware.location.IActivityRecognitionHardware$Stub
 android.hardware.soundtrigger.SoundTrigger
 android.hardware.soundtrigger.SoundTrigger$ConfidenceLevel
 android.hardware.soundtrigger.SoundTrigger$ConfidenceLevel$1
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 85ab249..3dab17f 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -90,6 +90,7 @@
 import android.os.AsyncTask;
 import android.os.Binder;
 import android.os.Build;
+import android.os.Bundle;
 import android.os.FileUtils;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -137,6 +138,7 @@
 import com.android.server.connectivity.NetworkAgentInfo;
 import com.android.server.connectivity.NetworkMonitor;
 import com.android.server.connectivity.PacManager;
+import com.android.server.connectivity.PermissionMonitor;
 import com.android.server.connectivity.Tethering;
 import com.android.server.connectivity.Vpn;
 import com.android.server.net.BaseNetworkObserver;
@@ -170,6 +172,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Random;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -225,6 +228,8 @@
 
     private Tethering mTethering;
 
+    private final PermissionMonitor mPermissionMonitor;
+
     private KeyStore mKeyStore;
 
     @GuardedBy("mVpns")
@@ -400,7 +405,7 @@
     private ArrayList mInetLog;
 
     // track the current default http proxy - tell the world if we get a new one (real change)
-    private ProxyInfo mDefaultProxy = null;
+    private volatile ProxyInfo mDefaultProxy = null;
     private Object mProxyLock = new Object();
     private boolean mDefaultProxyDisabled = false;
 
@@ -702,6 +707,8 @@
 
         mTethering = new Tethering(mContext, mNetd, statsService, mHandler.getLooper());
 
+        mPermissionMonitor = new PermissionMonitor(mContext, mNetd);
+
         //set up the listener for user state for creating user VPNs
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(Intent.ACTION_USER_STARTING);
@@ -1484,6 +1491,8 @@
         }
 
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_SYSTEM_READY));
+
+        mPermissionMonitor.startMonitoring();
     }
 
     private BroadcastReceiver mUserPresentReceiver = new BroadcastReceiver() {
@@ -1785,6 +1794,10 @@
         return false;
     }
 
+    private boolean isRequest(NetworkRequest request) {
+        return mNetworkRequests.get(request).isRequest;
+    }
+
     // must be stateless - things change under us.
     private class NetworkStateTrackerHandler extends Handler {
         public NetworkStateTrackerHandler(Looper looper) {
@@ -1888,6 +1901,9 @@
                         loge("EVENT_SET_EXPLICITLY_SELECTED from unknown NetworkAgent");
                         break;
                     }
+                    if (nai.created && !nai.networkMisc.explicitlySelected) {
+                        loge("ERROR: created network explicitly selected.");
+                    }
                     nai.networkMisc.explicitlySelected = true;
                     break;
                 }
@@ -1897,8 +1913,14 @@
                         boolean valid = (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID);
                         if (valid) {
                             if (DBG) log("Validated " + nai.name());
+                            final boolean previouslyValidated = nai.validated;
+                            final int previousScore = nai.getCurrentScore();
                             nai.validated = true;
-                            rematchNetworkAndRequests(nai);
+                            rematchNetworkAndRequests(nai, !previouslyValidated);
+                            // If score has changed, rebroadcast to NetworkFactories. b/17726566
+                            if (nai.getCurrentScore() != previousScore) {
+                                sendUpdatedScoreToFactories(nai);
+                            }
                         }
                         updateInetCondition(nai, valid);
                         // Let the NetworkAgent know the state of its network
@@ -2071,6 +2093,7 @@
             }
             // Since we've lost the network, go through all the requests that
             // it was satisfying and see if any other factory can satisfy them.
+            // TODO: This logic may be better replaced with a call to rematchAllNetworksAndRequests
             final ArrayList<NetworkAgentInfo> toActivate = new ArrayList<NetworkAgentInfo>();
             for (int i = 0; i < nai.networkRequests.size(); i++) {
                 NetworkRequest request = nai.networkRequests.valueAt(i);
@@ -2106,7 +2129,9 @@
                 requestNetworkTransitionWakelock(nai.name());
             }
             for (NetworkAgentInfo networkToActivate : toActivate) {
+                networkToActivate.networkLingered.clear();
                 networkToActivate.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED);
+                rematchNetworkAndRequests(networkToActivate, false);
             }
         }
     }
@@ -2144,6 +2169,7 @@
                 bestNetwork.networkLingered.clear();
                 bestNetwork.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED);
             }
+            // TODO: This logic may be better replaced with a call to rematchNetworkAndRequests
             bestNetwork.addRequest(nri.request);
             mNetworkForRequestId.put(nri.request.requestId, bestNetwork);
             notifyNetworkCallback(bestNetwork, nri);
@@ -2188,7 +2214,7 @@
                         boolean keep = nai.isVPN();
                         for (int i = 0; i < nai.networkRequests.size() && !keep; i++) {
                             NetworkRequest r = nai.networkRequests.valueAt(i);
-                            if (mNetworkRequests.get(r).isRequest) keep = true;
+                            if (isRequest(r)) keep = true;
                         }
                         if (!keep) {
                             if (DBG) log("no live requests for " + nai.name() + "; disconnecting");
@@ -2472,6 +2498,10 @@
         if (nai == null) return;
         if (DBG) log("reportBadNetwork(" + nai.name() + ") by " + uid);
         synchronized (nai) {
+            // Validating an uncreated network could result in a call to rematchNetworkAndRequests()
+            // which isn't meant to work on uncreated networks.
+            if (!nai.created) return;
+
             if (isNetworkBlocked(nai, uid)) return;
 
             nai.networkMonitor.sendMessage(NetworkMonitor.CMD_FORCE_REEVALUATION, uid);
@@ -2530,12 +2560,12 @@
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
-        }
 
-        if (mGlobalProxy == null) {
-            proxyProperties = mDefaultProxy;
+            if (mGlobalProxy == null) {
+                proxyProperties = mDefaultProxy;
+            }
+            sendProxyBroadcast(proxyProperties);
         }
-        sendProxyBroadcast(proxyProperties);
     }
 
     private void loadGlobalProxy() {
@@ -3533,6 +3563,10 @@
         updateDnses(newLp, oldLp, netId, flushDns);
         updateClat(newLp, oldLp, networkAgent);
         if (isDefaultNetwork(networkAgent)) handleApplyDefaultProxy(newLp.getHttpProxy());
+        // TODO - move this check to cover the whole function
+        if (!Objects.equals(newLp, oldLp)) {
+            notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED);
+        }
     }
 
     private void updateClat(LinkProperties newLp, LinkProperties oldLp, NetworkAgentInfo na) {
@@ -3670,10 +3704,22 @@
 
     private void updateCapabilities(NetworkAgentInfo networkAgent,
             NetworkCapabilities networkCapabilities) {
-        // TODO - what else here?  Verify still satisfies everybody?
-        // Check if satisfies somebody new?  call callbacks?
-        synchronized (networkAgent) {
-            networkAgent.networkCapabilities = networkCapabilities;
+        //  TODO - turn this on in MR1 when we have more dogfooding time.
+        // rematchAllNetworksAndRequests();
+        if (!Objects.equals(networkAgent.networkCapabilities, networkCapabilities)) {
+            synchronized (networkAgent) {
+                networkAgent.networkCapabilities = networkCapabilities;
+            }
+            notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_CAP_CHANGED);
+        }
+    }
+
+    private void sendUpdatedScoreToFactories(NetworkAgentInfo nai) {
+        for (int i = 0; i < nai.networkRequests.size(); i++) {
+            NetworkRequest nr = nai.networkRequests.valueAt(i);
+            // Don't send listening requests to factories. b/17393458
+            if (!isRequest(nr)) continue;
+            sendUpdatedScoreToFactories(nr, nai.getCurrentScore());
         }
     }
 
@@ -3688,37 +3734,32 @@
     private void callCallbackForRequest(NetworkRequestInfo nri,
             NetworkAgentInfo networkAgent, int notificationType) {
         if (nri.messenger == null) return;  // Default request has no msgr
-        Object o;
-        int a1 = 0;
-        int a2 = 0;
+        Bundle bundle = new Bundle();
+        bundle.putParcelable(NetworkRequest.class.getSimpleName(),
+                new NetworkRequest(nri.request));
+        Message msg = Message.obtain();
+        if (notificationType != ConnectivityManager.CALLBACK_UNAVAIL &&
+                notificationType != ConnectivityManager.CALLBACK_RELEASED) {
+            bundle.putParcelable(Network.class.getSimpleName(), networkAgent.network);
+        }
         switch (notificationType) {
-            case ConnectivityManager.CALLBACK_LOSING:
-                a1 = 30 * 1000; // TODO - read this from NetworkMonitor
-                // fall through
-            case ConnectivityManager.CALLBACK_PRECHECK:
-            case ConnectivityManager.CALLBACK_AVAILABLE:
-            case ConnectivityManager.CALLBACK_LOST:
-            case ConnectivityManager.CALLBACK_CAP_CHANGED:
+            case ConnectivityManager.CALLBACK_LOSING: {
+                msg.arg1 = 30 * 1000; // TODO - read this from NetworkMonitor
+                break;
+            }
+            case ConnectivityManager.CALLBACK_CAP_CHANGED: {
+                bundle.putParcelable(NetworkCapabilities.class.getSimpleName(),
+                        new NetworkCapabilities(networkAgent.networkCapabilities));
+                break;
+            }
             case ConnectivityManager.CALLBACK_IP_CHANGED: {
-                o = new NetworkRequest(nri.request);
-                a2 = networkAgent.network.netId;
+                bundle.putParcelable(LinkProperties.class.getSimpleName(),
+                        new LinkProperties(networkAgent.linkProperties));
                 break;
             }
-            case ConnectivityManager.CALLBACK_UNAVAIL:
-            case ConnectivityManager.CALLBACK_RELEASED: {
-                o = new NetworkRequest(nri.request);
-                break;
-            }
-            default: {
-                loge("Unknown notificationType " + notificationType);
-                return;
-            }
         }
-        Message msg = Message.obtain();
-        msg.arg1 = a1;
-        msg.arg2 = a2;
-        msg.obj = o;
         msg.what = notificationType;
+        msg.setData(bundle);
         try {
             if (VDBG) {
                 log("sending notification " + notifyTypeToName(notificationType) +
@@ -3731,22 +3772,24 @@
         }
     }
 
+    private void teardownUnneededNetwork(NetworkAgentInfo nai) {
+        for (int i = 0; i < nai.networkRequests.size(); i++) {
+            NetworkRequest nr = nai.networkRequests.valueAt(i);
+            // Ignore listening requests.
+            if (!isRequest(nr)) continue;
+            loge("Dead network still had at least " + nr);
+            break;
+        }
+        nai.asyncChannel.disconnect();
+    }
+
     private void handleLingerComplete(NetworkAgentInfo oldNetwork) {
         if (oldNetwork == null) {
             loge("Unknown NetworkAgentInfo in handleLingerComplete");
             return;
         }
-        if (DBG) {
-            log("handleLingerComplete for " + oldNetwork.name());
-            for (int i = 0; i < oldNetwork.networkRequests.size(); i++) {
-                NetworkRequest nr = oldNetwork.networkRequests.valueAt(i);
-                // Ignore listening requests.
-                if (mNetworkRequests.get(nr).isRequest == false) continue;
-                loge("Dead network still had at least " + nr);
-                break;
-            }
-        }
-        oldNetwork.asyncChannel.disconnect();
+        if (DBG) log("handleLingerComplete for " + oldNetwork.name());
+        teardownUnneededNetwork(oldNetwork);
     }
 
     private void makeDefault(NetworkAgentInfo newNetwork) {
@@ -3768,21 +3811,32 @@
     //   satisfied by newNetwork, and reassigns to newNetwork
     //   any such requests for which newNetwork is the best.
     //
-    // - Tears down any Networks that as a result are no longer
+    // - Lingers any Networks that as a result are no longer
     //   needed. A network is needed if it is the best network for
     //   one or more NetworkRequests, or if it is a VPN.
     //
-    // - Tears down newNetwork if it is validated but turns out to be
-    //   unneeded. Does not tear down newNetwork if it is
-    //   unvalidated, because future validation may improve
-    //   newNetwork's score enough that it is needed.
+    // - Tears down newNetwork if it just became validated
+    //   (i.e. nascent==true) but turns out to be unneeded.
+    //   Does not tear down newNetwork if it is unvalidated,
+    //   because future validation may improve newNetwork's
+    //   score enough that it is needed.
     //
     // NOTE: This function only adds NetworkRequests that "newNetwork" could satisfy,
     // it does not remove NetworkRequests that other Networks could better satisfy.
     // If you need to handle decreases in score, use {@link rematchAllNetworksAndRequests}.
     // This function should be used when possible instead of {@code rematchAllNetworksAndRequests}
     // as it performs better by a factor of the number of Networks.
-    private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork) {
+    //
+    // @param nascent indicates if newNetwork just became validated, in which case it should be
+    //               torn down if unneeded.  If nascent is false, no action is taken if newNetwork
+    //               is found to be unneeded by this call.  Presumably, in this case, either:
+    //               - newNetwork is unvalidated (and left alive), or
+    //               - the NetworkRequests keeping newNetwork alive have been transitioned to
+    //                 another higher scoring network by another call to rematchNetworkAndRequests()
+    //                 and this other call also lingered newNetwork.
+    private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork, boolean nascent) {
+        if (!newNetwork.created) loge("ERROR: uncreated network being rematched.");
+        if (nascent && !newNetwork.validated) loge("ERROR: nascent network not validated.");
         boolean keep = newNetwork.isVPN();
         boolean isNewDefault = false;
         if (DBG) log("rematching " + newNetwork.name());
@@ -3868,11 +3922,11 @@
         }
         // Linger any networks that are no longer needed.
         for (NetworkAgentInfo nai : affectedNetworks) {
-            boolean teardown = !nai.isVPN();
+            boolean teardown = !nai.isVPN() && nai.validated;
             for (int i = 0; i < nai.networkRequests.size() && teardown; i++) {
                 NetworkRequest nr = nai.networkRequests.valueAt(i);
                 try {
-                if (mNetworkRequests.get(nr).isRequest) {
+                if (isRequest(nr)) {
                     teardown = false;
                 }
                 } catch (Exception e) {
@@ -3927,20 +3981,16 @@
             }
 
             notifyNetworkCallbacks(newNetwork, ConnectivityManager.CALLBACK_AVAILABLE);
-        } else if (newNetwork.validated) {
-            // Only tear down validated networks here.  Leave unvalidated to either become
+        } else if (nascent) {
+            // Only tear down newly validated networks here.  Leave unvalidated to either become
             // validated (and get evaluated against peers, one losing here) or
             // NetworkMonitor reports a bad network and we tear it down then.
+            // Networks that have been up for a while and are validated should be torn down via
+            // the lingering process so communication on that network is given time to wrap up.
             // TODO: Could teardown unvalidated networks when their NetworkCapabilities
             // satisfy no NetworkRequests.
-            if (DBG && newNetwork.networkRequests.size() != 0) {
-                loge("tearing down network with live requests:");
-                for (int i=0; i < newNetwork.networkRequests.size(); i++) {
-                    loge("  " + newNetwork.networkRequests.valueAt(i));
-                }
-            }
             if (DBG) log("Validated network turns out to be unwanted.  Tear it down.");
-            newNetwork.asyncChannel.disconnect();
+            teardownUnneededNetwork(newNetwork);
         }
     }
 
@@ -3962,10 +4012,10 @@
         // can only add more NetworkRequests satisfied by "changed", and this is exactly what
         // rematchNetworkAndRequests() handles.
         if (changed != null && oldScore < changed.getCurrentScore()) {
-            rematchNetworkAndRequests(changed);
+            rematchNetworkAndRequests(changed, false);
         } else {
             for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
-                rematchNetworkAndRequests(nai);
+                rematchNetworkAndRequests(nai, false);
             }
         }
     }
@@ -4039,14 +4089,7 @@
                 // TODO: support proxy per network.
             }
             // Consider network even though it is not yet validated.
-            // TODO: All the if-statement conditions can be removed now that validation only confers
-            // a score increase.
-            if (mNetworkForRequestId.get(mDefaultRequest.requestId) == null &&
-                    networkAgent.isVPN() == false &&
-                    mDefaultRequest.networkCapabilities.satisfiedByNetworkCapabilities(
-                    networkAgent.networkCapabilities)) {
-                rematchNetworkAndRequests(networkAgent);
-            }
+            rematchNetworkAndRequests(networkAgent, false);
         } else if (state == NetworkInfo.State.DISCONNECTED ||
                 state == NetworkInfo.State.SUSPENDED) {
             networkAgent.asyncChannel.disconnect();
@@ -4076,12 +4119,7 @@
 
         if (nai.created) rematchAllNetworksAndRequests(nai, oldScore);
 
-        for (int i = 0; i < nai.networkRequests.size(); i++) {
-            NetworkRequest nr = nai.networkRequests.valueAt(i);
-            // Don't send listening requests to factories. b/17393458
-            if (mNetworkRequests.get(nr).isRequest == false) continue;
-            sendUpdatedScoreToFactories(nr, score);
-        }
+        sendUpdatedScoreToFactories(nai);
     }
 
     // notify only this one new request of the current state
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 822007a..020c951 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -16,7 +16,6 @@
 
 package com.android.server;
 
-import static android.Manifest.permission.CHANGE_NETWORK_STATE;
 import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
 import static android.Manifest.permission.DUMP;
 import static android.Manifest.permission.SHUTDOWN;
@@ -2059,20 +2058,26 @@
     }
 
     @Override
-    public void setPermission(boolean internal, boolean changeNetState, int[] uids) {
+    public void setPermission(String permission, int[] uids) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
-        final Command cmd = new Command("network", "permission", "user", "set");
-        if (internal) cmd.appendArg(CONNECTIVITY_INTERNAL);
-        if (changeNetState) cmd.appendArg(CHANGE_NETWORK_STATE);
-        for (int i=0; i<uids.length; i++) {
-            cmd.appendArg(uids[i]);
-        }
-
-        try {
-            mConnector.execute(cmd);
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
+        Object[] argv = new Object[4 + MAX_UID_RANGES_PER_COMMAND];
+        argv[0] = "permission";
+        argv[1] = "user";
+        argv[2] = "set";
+        argv[3] = permission;
+        int argc = 4;
+        // Avoid overly long commands by limiting number of UIDs per command.
+        for (int i = 0; i < uids.length; ++i) {
+            argv[argc++] = uids[i];
+            if (i == uids.length - 1 || argc == argv.length) {
+                try {
+                    mConnector.execute("network", Arrays.copyOf(argv, argc));
+                } catch (NativeDaemonConnectorException e) {
+                    throw e.rethrowAsParcelableException();
+                }
+                argc = 4;
+            }
         }
     }
 
@@ -2080,15 +2085,22 @@
     public void clearPermission(int[] uids) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
-        final Command cmd = new Command("network", "permission", "user", "clear");
-        for (int i=0; i<uids.length; i++) {
-            cmd.appendArg(uids[i]);
-        }
-
-        try {
-            mConnector.execute(cmd);
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
+        Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND];
+        argv[0] = "permission";
+        argv[1] = "user";
+        argv[2] = "clear";
+        int argc = 3;
+        // Avoid overly long commands by limiting number of UIDs per command.
+        for (int i = 0; i < uids.length; ++i) {
+            argv[argc++] = uids[i];
+            if (i == uids.length - 1 || argc == argv.length) {
+                try {
+                    mConnector.execute("network", Arrays.copyOf(argv, argc));
+                } catch (NativeDaemonConnectorException e) {
+                    throw e.rethrowAsParcelableException();
+                }
+                argc = 3;
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 5022b28..0ea66b9 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -166,14 +166,14 @@
     // These are the low-end OOM level limits.  This is appropriate for an
     // HVGA or smaller phone with less than 512MB.  Values are in KB.
     private final int[] mOomMinFreeLow = new int[] {
-            8192, 12288, 16384,
-            24576, 28672, 32768
+            12288, 18432, 24576,
+            36864, 43008, 49152
     };
     // These are the high-end OOM level limits.  This is appropriate for a
     // 1280x800 or larger screen with around 1GB RAM.  Values are in KB.
     private final int[] mOomMinFreeHigh = new int[] {
-            49152, 61440, 73728,
-            86016, 98304, 122880
+            73728, 92160, 110592,
+            129024, 147456, 184320
     };
     // The actual OOM killer memory levels we are using.
     private final int[] mOomMinFree = new int[mOomAdj.length];
@@ -231,7 +231,11 @@
             Slog.i("XXXXXX", "minfree_adj=" + minfree_adj + " minfree_abs=" + minfree_abs);
         }
 
-        final boolean is64bit = Build.SUPPORTED_64_BIT_ABIS.length > 0;
+        // We've now baked in the increase to the basic oom values above, since
+        // they seem to be useful more generally for devices that are tight on
+        // memory than just for 64 bit.  This should probably have some more
+        // tuning done, so not deleting it quite yet...
+        final boolean is64bit = false; //Build.SUPPORTED_64_BIT_ABIS.length > 0;
 
         for (int i=0; i<mOomAdj.length; i++) {
             int low = mOomMinFreeLow[i];
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
new file mode 100644
index 0000000..238402f
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity;
+
+import static android.Manifest.permission.CHANGE_NETWORK_STATE;
+import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
+import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
+import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+import static android.content.pm.PackageManager.GET_PERMISSIONS;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.UserInfo;
+import android.net.Uri;
+import android.os.INetworkManagementService;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A utility class to inform Netd of UID permisisons.
+ * Does a mass update at boot and then monitors for app install/remove.
+ *
+ * @hide
+ */
+public class PermissionMonitor {
+    private static final String TAG = "PermissionMonitor";
+    private static final boolean DBG = true;
+    private static final boolean SYSTEM = true;
+    private static final boolean NETWORK = false;
+
+    private final Context mContext;
+    private final PackageManager mPackageManager;
+    private final UserManager mUserManager;
+    private final INetworkManagementService mNetd;
+    private final BroadcastReceiver mIntentReceiver;
+
+    // Values are User IDs.
+    private final Set<Integer> mUsers = new HashSet<Integer>();
+
+    // Keys are App IDs. Values are true for SYSTEM permission and false for NETWORK permission.
+    private final Map<Integer, Boolean> mApps = new HashMap<Integer, Boolean>();
+
+    public PermissionMonitor(Context context, INetworkManagementService netd) {
+        mContext = context;
+        mPackageManager = context.getPackageManager();
+        mUserManager = UserManager.get(context);
+        mNetd = netd;
+        mIntentReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                String action = intent.getAction();
+                int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+                int appUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+                Uri appData = intent.getData();
+                String appName = appData != null ? appData.getSchemeSpecificPart() : null;
+
+                if (Intent.ACTION_USER_ADDED.equals(action)) {
+                    onUserAdded(user);
+                } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
+                    onUserRemoved(user);
+                } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
+                    onAppAdded(appName, appUid);
+                } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+                    onAppRemoved(appUid);
+                }
+            }
+        };
+    }
+
+    // Intended to be called only once at startup, after the system is ready. Installs a broadcast
+    // receiver to monitor ongoing UID changes, so this shouldn't/needn't be called again.
+    public synchronized void startMonitoring() {
+        log("Monitoring");
+
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(Intent.ACTION_USER_ADDED);
+        intentFilter.addAction(Intent.ACTION_USER_REMOVED);
+        mContext.registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, intentFilter, null, null);
+
+        intentFilter = new IntentFilter();
+        intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+        intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        intentFilter.addDataScheme("package");
+        mContext.registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, intentFilter, null, null);
+
+        List<PackageInfo> apps = mPackageManager.getInstalledPackages(GET_PERMISSIONS);
+        if (apps == null) {
+            loge("No apps");
+            return;
+        }
+
+        for (PackageInfo app : apps) {
+            int uid = app.applicationInfo != null ? app.applicationInfo.uid : -1;
+            if (uid < 0) {
+                continue;
+            }
+
+            boolean isNetwork = hasNetworkPermission(app);
+            boolean isSystem = hasSystemPermission(app);
+
+            if (isNetwork || isSystem) {
+                Boolean permission = mApps.get(uid);
+                // If multiple packages share a UID (cf: android:sharedUserId) and ask for different
+                // permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
+                if (permission == null || permission == NETWORK) {
+                    mApps.put(uid, isSystem);
+                }
+            }
+        }
+
+        List<UserInfo> users = mUserManager.getUsers(true);  // exclude dying users
+        if (users != null) {
+            for (UserInfo user : users) {
+                mUsers.add(user.id);
+            }
+        }
+
+        log("Users: " + mUsers.size() + ", Apps: " + mApps.size());
+        update(mUsers, mApps, true);
+    }
+
+    private boolean hasPermission(PackageInfo app, String permission) {
+        if (app.requestedPermissions != null) {
+            for (String p : app.requestedPermissions) {
+                if (permission.equals(p)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private boolean hasNetworkPermission(PackageInfo app) {
+        return hasPermission(app, CHANGE_NETWORK_STATE);
+    }
+
+    private boolean hasSystemPermission(PackageInfo app) {
+        int flags = app.applicationInfo != null ? app.applicationInfo.flags : 0;
+        if ((flags & FLAG_SYSTEM) != 0 || (flags & FLAG_UPDATED_SYSTEM_APP) != 0) {
+            return true;
+        }
+        return hasPermission(app, CONNECTIVITY_INTERNAL);
+    }
+
+    private int[] toIntArray(List<Integer> list) {
+        int[] array = new int[list.size()];
+        for (int i = 0; i < list.size(); i++) {
+            array[i] = list.get(i);
+        }
+        return array;
+    }
+
+    private void update(Set<Integer> users, Map<Integer, Boolean> apps, boolean add) {
+        List<Integer> network = new ArrayList<Integer>();
+        List<Integer> system = new ArrayList<Integer>();
+        for (Entry<Integer, Boolean> app : apps.entrySet()) {
+            List<Integer> list = app.getValue() ? system : network;
+            for (int user : users) {
+                list.add(UserHandle.getUid(user, app.getKey()));
+            }
+        }
+        try {
+            if (add) {
+                mNetd.setPermission(CHANGE_NETWORK_STATE, toIntArray(network));
+                mNetd.setPermission(CONNECTIVITY_INTERNAL, toIntArray(system));
+            } else {
+                mNetd.clearPermission(toIntArray(network));
+                mNetd.clearPermission(toIntArray(system));
+            }
+        } catch (RemoteException e) {
+            loge("Exception when updating permissions: " + e);
+        }
+    }
+
+    private synchronized void onUserAdded(int user) {
+        if (user < 0) {
+            loge("Invalid user in onUserAdded: " + user);
+            return;
+        }
+        mUsers.add(user);
+
+        Set<Integer> users = new HashSet<Integer>();
+        users.add(user);
+        update(users, mApps, true);
+    }
+
+    private synchronized void onUserRemoved(int user) {
+        if (user < 0) {
+            loge("Invalid user in onUserRemoved: " + user);
+            return;
+        }
+        mUsers.remove(user);
+
+        Set<Integer> users = new HashSet<Integer>();
+        users.add(user);
+        update(users, mApps, false);
+    }
+
+    private synchronized void onAppAdded(String appName, int appUid) {
+        if (TextUtils.isEmpty(appName) || appUid < 0) {
+            loge("Invalid app in onAppAdded: " + appName + " | " + appUid);
+            return;
+        }
+
+        try {
+            PackageInfo app = mPackageManager.getPackageInfo(appName, GET_PERMISSIONS);
+            boolean isNetwork = hasNetworkPermission(app);
+            boolean isSystem = hasSystemPermission(app);
+            if (isNetwork || isSystem) {
+                Boolean permission = mApps.get(appUid);
+                // If multiple packages share a UID (cf: android:sharedUserId) and ask for different
+                // permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
+                if (permission == null || permission == NETWORK) {
+                    mApps.put(appUid, isSystem);
+
+                    Map<Integer, Boolean> apps = new HashMap<Integer, Boolean>();
+                    apps.put(appUid, isSystem);
+                    update(mUsers, apps, true);
+                }
+            }
+        } catch (NameNotFoundException e) {
+            loge("NameNotFoundException in onAppAdded: " + e);
+        }
+    }
+
+    private synchronized void onAppRemoved(int appUid) {
+        if (appUid < 0) {
+            loge("Invalid app in onAppRemoved: " + appUid);
+            return;
+        }
+        mApps.remove(appUid);
+
+        Map<Integer, Boolean> apps = new HashMap<Integer, Boolean>();
+        apps.put(appUid, NETWORK);  // doesn't matter which permission we pick here
+        update(mUsers, apps, false);
+    }
+
+    private static void log(String s) {
+        if (DBG) {
+            Log.d(TAG, s);
+        }
+    }
+
+    private static void loge(String s) {
+        Log.e(TAG, s);
+    }
+}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index adc96f7..6dcbc42 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -16,7 +16,6 @@
 
 package com.android.server.content;
 
-import android.Manifest;
 import android.accounts.Account;
 import android.accounts.AccountAndUser;
 import android.accounts.AccountManager;
@@ -481,7 +480,7 @@
             mContext.registerReceiverAsUser(mAccountsUpdatedReceiver,
                     UserHandle.ALL,
                     new IntentFilter(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION),
-                    Manifest.permission.ACCOUNT_MANAGER, null);
+                    null, null);
         }
 
         // Pick a random second in a day to seed all periodic syncs
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index e3a25c0..2d5b99e 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -563,6 +563,12 @@
             state = Display.STATE_OFF;
         }
 
+        // Animate the screen state change unless already animating.
+        // The transition may be deferred, so after this point we will use the
+        // actual state instead of the desired one.
+        animateScreenStateChange(state, performScreenOffTransition);
+        state = mPowerState.getScreenState();
+
         // Use zero brightness when screen is off.
         if (state == Display.STATE_OFF) {
             brightness = PowerManager.BRIGHTNESS_OFF;
@@ -636,13 +642,9 @@
             mAppliedLowPower = true;
         }
 
-        // Animate the screen state change unless already animating.
-        animateScreenStateChange(state, performScreenOffTransition);
-
         // Animate the screen brightness when the screen is on or dozing.
         // Skip the animation when the screen is off or suspended.
-        final int actualState = mPowerState.getScreenState();
-        if (actualState == Display.STATE_ON || actualState == Display.STATE_DOZE) {
+        if (state == Display.STATE_ON || state == Display.STATE_DOZE) {
             animateScreenBrightness(brightness,
                     slowChange ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
         } else {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d8e5a98..22f060f 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -75,6 +75,7 @@
 import android.service.notification.NotificationRankingUpdate;
 import android.service.notification.StatusBarNotification;
 import android.service.notification.ZenModeConfig;
+import android.telephony.PhoneStateListener;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -187,6 +188,7 @@
     boolean mSystemReady;
 
     private boolean mDisableNotificationEffects;
+    private int mCallState;
     NotificationRecord mSoundNotification;
     NotificationRecord mVibrateNotification;
 
@@ -490,7 +492,7 @@
             synchronized (mNotificationList) {
                 mDisableNotificationEffects =
                         (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
-                if (disableNotificationEffects()) {
+                if (disableNotificationEffects(null) != null) {
                     // cancel whatever's going on
                     long identity = Binder.clearCallingIdentity();
                     try {
@@ -875,6 +877,7 @@
         mZenModeHelper.updateZenMode();
 
         mUserProfiles.updateCache(getContext());
+        listenForCallState();
 
         // register for various Intents
         IntentFilter filter = new IntentFilter();
@@ -1510,8 +1513,17 @@
         return keys.toArray(new String[keys.size()]);
     }
 
-    private boolean disableNotificationEffects() {
-        return mDisableNotificationEffects || (mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0;
+    private String disableNotificationEffects(NotificationRecord record) {
+        if (mDisableNotificationEffects) {
+            return "booleanState";
+        }
+        if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
+            return "listenerHints";
+        }
+        if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
+            return "callState";
+        }
+        return null;
     }
 
     void dumpImpl(PrintWriter pw, DumpFilter filter) {
@@ -1563,6 +1575,7 @@
                     pw.println("  mSoundNotification=" + mSoundNotification);
                     pw.println("  mVibrateNotification=" + mVibrateNotification);
                     pw.println("  mDisableNotificationEffects=" + mDisableNotificationEffects);
+                    pw.println("  mCallState=" + callStateToString(mCallState));
                     pw.println("  mSystemReady=" + mSystemReady);
                 }
                 pw.println("  mArchive=" + mArchive.toString());
@@ -1839,7 +1852,11 @@
         }
 
         // If we're not supposed to beep, vibrate, etc. then don't.
-        if (!disableNotificationEffects()
+        final String disableEffects = disableNotificationEffects(record);
+        if (disableEffects != null) {
+            ZenLog.traceDisableEffects(record, disableEffects);
+        }
+        if (disableEffects == null
                 && (!(record.isUpdate
                     && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
                 && (record.getUserId() == UserHandle.USER_ALL ||
@@ -2657,6 +2674,26 @@
         }
     }
 
+    private static String callStateToString(int state) {
+        switch (state) {
+            case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
+            case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
+            case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
+            default: return "CALL_STATE_UNKNOWN_" + state;
+        }
+    }
+
+    private void listenForCallState() {
+        TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
+            @Override
+            public void onCallStateChanged(int state, String incomingNumber) {
+                if (mCallState == state) return;
+                if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
+                mCallState = state;
+            }
+        }, PhoneStateListener.LISTEN_CALL_STATE);
+    }
+
     /**
      * Generates a NotificationRankingUpdate from 'sbns', considering only
      * notifications visible to the given listener.
diff --git a/services/core/java/com/android/server/notification/ZenLog.java b/services/core/java/com/android/server/notification/ZenLog.java
index f84409e..6cc5e0e 100644
--- a/services/core/java/com/android/server/notification/ZenLog.java
+++ b/services/core/java/com/android/server/notification/ZenLog.java
@@ -55,6 +55,7 @@
     private static final int TYPE_CONFIG = 10;
     private static final int TYPE_FOLLOW_RINGER_MODE = 11;
     private static final int TYPE_NOT_INTERCEPTED = 12;
+    private static final int TYPE_DISABLE_EFFECTS = 13;
 
     private static int sNext;
     private static int sSize;
@@ -106,6 +107,10 @@
                 + zenModeToString(oldZen) + " -> " + zenModeToString(newZen));
     }
 
+    public static void traceDisableEffects(NotificationRecord record, String reason) {
+        append(TYPE_DISABLE_EFFECTS, record.getKey() + "," + reason);
+    }
+
     private static String subscribeResult(IConditionProvider provider, RemoteException e) {
         return provider == null ? "no provider" : e != null ? e.getMessage() : "ok";
     }
@@ -124,6 +129,7 @@
             case TYPE_CONFIG: return "config";
             case TYPE_FOLLOW_RINGER_MODE: return "follow_ringer_mode";
             case TYPE_NOT_INTERCEPTED: return "not_intercepted";
+            case TYPE_DISABLE_EFFECTS: return "disable_effects";
             default: return "unknown";
         }
     }
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index e6007bf..5bc1ff9 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -350,9 +350,9 @@
         return record.isCategory(Notification.CATEGORY_EVENT);
     }
 
-    private boolean isCall(NotificationRecord record) {
-        return isDefaultPhoneApp(record.sbn.getPackageName())
-                || record.isCategory(Notification.CATEGORY_CALL);
+    public boolean isCall(NotificationRecord record) {
+        return record != null && (isDefaultPhoneApp(record.sbn.getPackageName())
+                || record.isCategory(Notification.CATEGORY_CALL));
     }
 
     private boolean isDefaultPhoneApp(String pkg) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 851cf17..50cb5fc 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -5960,11 +5960,19 @@
                     if (bp != null && !Objects.equals(bp.sourcePackage, p.info.packageName)) {
                         final boolean currentOwnerIsSystem = (bp.perm != null
                                 && isSystemApp(bp.perm.owner));
-                        if (isSystemApp(p.owner) && !currentOwnerIsSystem) {
-                            String msg = "New decl " + p.owner + " of permission  "
-                                    + p.info.name + " is system; overriding " + bp.sourcePackage;
-                            reportSettingsProblem(Log.WARN, msg);
-                            bp = null;
+                        if (isSystemApp(p.owner)) {
+                            if (bp.type == BasePermission.TYPE_BUILTIN && bp.perm == null) {
+                                // It's a built-in permission and no owner, take ownership now
+                                bp.packageSetting = pkgSetting;
+                                bp.perm = p;
+                                bp.uid = pkg.applicationInfo.uid;
+                                bp.sourcePackage = p.info.packageName;
+                            } else if (!currentOwnerIsSystem) {
+                                String msg = "New decl " + p.owner + " of permission  "
+                                        + p.info.name + " is system; overriding " + bp.sourcePackage;
+                                reportSettingsProblem(Log.WARN, msg);
+                                bp = null;
+                            }
                         }
                     }
 
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 0c51160..30589b1 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -162,7 +162,7 @@
     }
 
     TaskStack getHomeStack() {
-        if (mHomeStack == null) {
+        if (mHomeStack == null && mDisplayId == Display.DEFAULT_DISPLAY) {
             Slog.e(TAG, "getHomeStack: Returning null from this=" + this);
         }
         return mHomeStack;
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 89d2dc0..b4d429a 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -584,6 +584,7 @@
      * @param account The complete {@link PhoneAccount}.
      * @hide
      */
+    @SystemApi
     public void registerPhoneAccount(PhoneAccount account) {
         try {
             if (isServiceConnected()) {
@@ -600,6 +601,7 @@
      * @param accountHandle A {@link PhoneAccountHandle} for the {@link PhoneAccount} to unregister.
      * @hide
      */
+    @SystemApi
     public void unregisterPhoneAccount(PhoneAccountHandle accountHandle) {
         try {
             if (isServiceConnected()) {
@@ -800,6 +802,7 @@
      *            {@link ConnectionService#onCreateIncomingConnection}.
      * @hide
      */
+    @SystemApi
     public void addNewIncomingCall(PhoneAccountHandle phoneAccount, Bundle extras) {
         try {
             if (isServiceConnected()) {
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 1ee390f..8e43772 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -146,6 +146,8 @@
      * @hide
      */
     public static final int RIL_RADIO_TECHNOLOGY_GSM = 16;
+    /** @hide */
+    public static final int RIL_RADIO_TECHNOLOGY_TD_SCDMA = 17;
 
     /**
      * Available registration states for GSM, UMTS and CDMA.
@@ -859,6 +861,7 @@
                 || radioTechnology == RIL_RADIO_TECHNOLOGY_EVDO_0
                 || radioTechnology == RIL_RADIO_TECHNOLOGY_EVDO_A
                 || radioTechnology == RIL_RADIO_TECHNOLOGY_EVDO_B
-                || radioTechnology == RIL_RADIO_TECHNOLOGY_EHRPD;
+                || radioTechnology == RIL_RADIO_TECHNOLOGY_EHRPD
+                || radioTechnology == RIL_RADIO_TECHNOLOGY_TD_SCDMA;
     }
 }
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 4f5f31a..5514798 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -1222,18 +1222,15 @@
         if (allowCached && mCachedConfigKey != null) {
             key = mCachedConfigKey;
         } else {
-            key = this.SSID;
-            if (key == null)
-                key = "";
-            if (this.wepKeys[0] != null) {
-                key = key + "-WEP";
-            }
-            if (this.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
-                key = key + "-" + KeyMgmt.strings[KeyMgmt.WPA_PSK];
-            }
-            if (this.allowedKeyManagement.get(KeyMgmt.WPA_EAP) ||
-                    this.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
-                key = key + "-" + KeyMgmt.strings[KeyMgmt.WPA_EAP];
+            if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
+                key = SSID + KeyMgmt.strings[KeyMgmt.WPA_PSK];
+            } else if (allowedKeyManagement.get(KeyMgmt.WPA_EAP) ||
+                    allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
+                key = SSID + KeyMgmt.strings[KeyMgmt.WPA_EAP];
+            } else if (wepKeys[0] != null) {
+                key = SSID + "WEP";
+            } else {
+                key = SSID + KeyMgmt.strings[KeyMgmt.NONE];
             }
             mCachedConfigKey = key;
         }