Merge "Initial code for listing/storing sound models"
diff --git a/api/current.txt b/api/current.txt
index 839e95d..95f6461 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3334,6 +3334,7 @@
     method public void onAttachFragment(android.app.Fragment);
     method public void onAttachedToWindow();
     method public void onBackPressed();
+    method public void onBackgroundMediaPlayingChanged(boolean);
     method protected void onChildTitleChanged(android.app.Activity, java.lang.CharSequence);
     method public void onConfigurationChanged(android.content.res.Configuration);
     method public void onContentChanged();
@@ -3389,6 +3390,7 @@
     method public boolean onSearchRequested();
     method protected void onStart();
     method protected void onStop();
+    method public void onStopMediaPlaying();
     method protected void onTitleChanged(java.lang.CharSequence, int);
     method public boolean onTouchEvent(android.view.MotionEvent);
     method public boolean onTrackballEvent(android.view.MotionEvent);
@@ -3423,6 +3425,7 @@
     method public void setFinishOnTouchOutside(boolean);
     method public void setImmersive(boolean);
     method public void setIntent(android.content.Intent);
+    method public boolean setMediaPlaying(boolean);
     method public final void setProgress(int);
     method public final void setProgressBarIndeterminate(boolean);
     method public final void setProgressBarIndeterminateVisibility(boolean);
@@ -27674,7 +27677,6 @@
   }
 
   public final class ConnectionRequest implements android.os.Parcelable {
-    ctor public ConnectionRequest(android.net.Uri, android.os.Bundle);
     ctor public ConnectionRequest(java.lang.String, android.net.Uri, android.os.Bundle);
     ctor public ConnectionRequest(android.telecomm.PhoneAccount, java.lang.String, android.net.Uri, android.os.Bundle);
     method public int describeContents();
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 7934705..f1a2576 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -743,10 +743,13 @@
             return Activity.this.findViewById(id);
         }
     };
-    
+
+    // Most recent call to setMediaPlaying().
+    boolean mMediaPlaying;
+
     ArrayMap<String, LoaderManagerImpl> mAllLoaderManagers;
     LoaderManagerImpl mLoaderManager;
-    
+
     private static final class ManagedCursor {
         ManagedCursor(Cursor cursor) {
             mCursor = cursor;
@@ -764,6 +767,7 @@
     // protected by synchronized (this) 
     int mResultCode = RESULT_CANCELED;
     Intent mResultData = null;
+
     private TranslucentConversionListener mTranslucentCallback;
     private boolean mChangeCanvasToTranslucent;
 
@@ -5324,6 +5328,101 @@
     }
 
     /**
+     * Activities that want to show media behind a translucent activity above them must call this
+     * method anytime before a return from {@link #onPause()}. If this call is successful
+     * then the activity should continue to play media when {@link #onPause()} is called, but must
+     * stop playing and release resources prior to or within the call to
+     * {@link #onStopMediaPlaying()}. If this call returns false the activity must stop
+     * playing and release resources immediately.
+     *
+     * <p>Only fullscreen opaque activities may make this call. I.e. this call is a nop
+     * for dialog and translucent activities.
+     *
+     * <p>False will be returned any time this method is call between the return of onPause and
+     *      the next call to onResume.
+     *
+     * @param playing true to notify the system that media is starting or continuing playing,
+     *                false to indicate that media has stopped or is stopping. Resources must
+     *                be released when passing false to this method.
+     * @return the resulting play state. If true the activity may continue playing media beyond
+     *      {@link #onPause()}, if false then the caller must stop playing and immediately
+     *      release all media resources. Returning false may occur in lieu of a call to
+     *      onReleaseMediaResources() so the return value must be checked.
+     *
+     * @see #isBackgroundMediaPlaying()
+     * @see #onStopMediaPlaying()
+     * @see #onBackgroundMediaPlayingChanged(boolean)
+     */
+    public boolean setMediaPlaying(boolean playing) {
+        if (!mResumed) {
+            // Do not permit paused or stopped activities to start playing.
+            playing = false;
+        }
+        try {
+            mMediaPlaying = ActivityManagerNative.getDefault().setMediaPlaying(mToken, playing) &&
+                    playing;
+        } catch (RemoteException e) {
+            mMediaPlaying = false;
+        }
+        return mMediaPlaying;
+    }
+
+    /**
+     * Called when a translucent activity over playing media is becoming opaque or another
+     * activity is being launched. Activities that call {@link #setMediaPlaying(boolean)}
+     * must implement this method to at the minimum call
+     * <code>super.onStopMediaPlayback()</code>.
+     *
+     * <p>When this method is called the activity has 500 msec to release the media resources.
+     * If the activity has not returned from this method in 500 msec the system will destroy
+     * the activity and kill the process in order to recover the media resources for another
+     * process. Otherwise {@link #onStop()} will be called following return.
+     *
+     * @see #setMediaPlaying(boolean)
+     * @see #isBackgroundMediaPlaying()
+     * @see #onBackgroundMediaPlayingChanged(boolean)
+     */
+    public void onStopMediaPlaying() {
+        mCalled = true;
+    }
+
+    /**
+     * Translucent activities may call this to determine if there is an activity below it that
+     * is playing media.
+     *
+     * @return true if media is playing according to the most recent call to
+     * {@link #setMediaPlaying(boolean)}, false otherwise.
+     *
+     * @see #setMediaPlaying(boolean)
+     * @see #onStopMediaPlaying()
+     * @see #onBackgroundMediaPlayingChanged(boolean)
+     * @hide
+     */
+    public boolean isBackgroundMediaPlaying() {
+        try {
+            return ActivityManagerNative.getDefault().isBackgroundMediaPlaying(mToken);
+        } catch (RemoteException e) {
+        }
+        return false;
+    }
+
+    /**
+     * The topmost foreground activity will receive this call when an activity below it either
+     * starts or stops playing media.
+     *
+     * This call may be a consequence of {@link #setMediaPlaying(boolean)} or might be
+     * due to a background activity finishing itself.
+     *
+     * @param playing true if media playback is starting, false if it is stopping.
+     *
+     * @see #setMediaPlaying(boolean)
+     * @see #isBackgroundMediaPlaying()
+     * @see #onStopMediaPlaying()
+     */
+    public void onBackgroundMediaPlayingChanged(boolean playing) {
+    }
+
+    /**
      * Adjust the current immersive mode setting.
      *
      * Note that changing this value will have no effect on the activity's
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index ce36fd8..4a70e15 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2176,6 +2176,33 @@
             reply.writeNoException();
             return true;
         }
+
+        case SET_MEDIA_PLAYING_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder token = data.readStrongBinder();
+            boolean enable = data.readInt() > 0;
+            boolean success = setMediaPlaying(token, enable);
+            reply.writeNoException();
+            reply.writeInt(success ? 1 : 0);
+            return true;
+        }
+
+        case IS_BG_MEDIA_PLAYING_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder token = data.readStrongBinder();
+            final boolean enabled = isBackgroundMediaPlaying(token);
+            reply.writeNoException();
+            reply.writeInt(enabled ? 1 : 0);
+            return true;
+        }
+
+        case MEDIA_RESOURCES_RELEASED: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder token = data.readStrongBinder();
+            mediaResourcesReleased(token);
+            reply.writeNoException();
+            return true;
+        }
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -5007,5 +5034,46 @@
         reply.recycle();
     }
 
+    @Override
+    public boolean setMediaPlaying(IBinder token, boolean playing) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(token);
+        data.writeInt(playing ? 1 : 0);
+        mRemote.transact(SET_MEDIA_PLAYING_TRANSACTION, data, reply, 0);
+        reply.readException();
+        boolean success = reply.readInt() > 0;
+        data.recycle();
+        reply.recycle();
+        return success;
+    }
+
+    @Override
+    public boolean isBackgroundMediaPlaying(IBinder token) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(token);
+        mRemote.transact(IS_BG_MEDIA_PLAYING_TRANSACTION, data, reply, 0);
+        reply.readException();
+        final boolean playing = reply.readInt() > 0;
+        data.recycle();
+        reply.recycle();
+        return playing;
+    }
+
+    @Override
+    public void mediaResourcesReleased(IBinder token) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(token);
+        mRemote.transact(MEDIA_RESOURCES_RELEASED, data, reply, IBinder.FLAG_ONEWAY);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 7b48e1d..184e10c 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1153,6 +1153,16 @@
         public final void updateTimePrefs(boolean is24Hour) {
             DateFormat.set24HourTimePref(is24Hour);
         }
+
+        @Override
+        public void scheduleStopMediaPlaying(IBinder token) {
+            sendMessage(H.STOP_MEDIA_PLAYING, token);
+        }
+
+        @Override
+        public void scheduleBackgroundMediaPlayingChanged(IBinder token, boolean playing) {
+            sendMessage(H.BACKGROUND_MEDIA_PLAYING_CHANGED, token, playing ? 1 : 0);
+        }
     }
 
     private class H extends Handler {
@@ -1203,6 +1213,8 @@
         public static final int TRANSLUCENT_CONVERSION_COMPLETE = 144;
         public static final int INSTALL_PROVIDER        = 145;
         public static final int ON_NEW_ACTIVITY_OPTIONS = 146;
+        public static final int STOP_MEDIA_PLAYING = 147;
+        public static final int BACKGROUND_MEDIA_PLAYING_CHANGED = 148;
 
         String codeToString(int code) {
             if (DEBUG_MESSAGES) {
@@ -1253,6 +1265,8 @@
                     case TRANSLUCENT_CONVERSION_COMPLETE: return "TRANSLUCENT_CONVERSION_COMPLETE";
                     case INSTALL_PROVIDER: return "INSTALL_PROVIDER";
                     case ON_NEW_ACTIVITY_OPTIONS: return "ON_NEW_ACTIVITY_OPTIONS";
+                    case STOP_MEDIA_PLAYING: return "STOP_MEDIA_PLAYING";
+                    case BACKGROUND_MEDIA_PLAYING_CHANGED: return "BACKGROUND_MEDIA_PLAYING_CHANGED";
                 }
             }
             return Integer.toString(code);
@@ -1470,6 +1484,11 @@
                 case ON_NEW_ACTIVITY_OPTIONS:
                     Pair<IBinder, ActivityOptions> pair = (Pair<IBinder, ActivityOptions>) msg.obj;
                     onNewActivityOptions(pair.first, pair.second);
+                case STOP_MEDIA_PLAYING:
+                    handleStopMediaPlaying((IBinder) msg.obj);
+                    break;
+                case BACKGROUND_MEDIA_PLAYING_CHANGED:
+                    handleOnBackgroundMediaPlayingChanged((IBinder) msg.obj, msg.arg1 > 0);
                     break;
             }
             if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));
@@ -2454,6 +2473,34 @@
         }
     }
 
+    public void handleStopMediaPlaying(IBinder token) {
+        ActivityClientRecord r = mActivities.get(token);
+        if (r != null) {
+            final Activity activity = r.activity;
+            if (activity.mMediaPlaying) {
+                activity.mCalled = false;
+                activity.onStopMediaPlaying();
+                // Tick, tick, tick. The activity has 500 msec to return or it will be destroyed.
+                if (!activity.mCalled) {
+                    throw new SuperNotCalledException("Activity " + activity.getLocalClassName() +
+                            " did not call through to super.onStopMediaPlayback()");
+                }
+                activity.mMediaPlaying = false;
+            }
+        }
+        try {
+            ActivityManagerNative.getDefault().mediaResourcesReleased(token);
+        } catch (RemoteException e) {
+        }
+    }
+
+    public void handleOnBackgroundMediaPlayingChanged(IBinder token, boolean playing) {
+        ActivityClientRecord r = mActivities.get(token);
+        if (r != null) {
+            r.activity.onBackgroundMediaPlayingChanged(playing);
+        }
+    }
+
     public void handleInstallProvider(ProviderInfo info) {
         installContentProviders(mInitialApplication, Lists.newArrayList(info));
     }
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 6c5c98b..1a03fe9 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -274,8 +274,8 @@
         return names;
     }
 
-    public ArrayList<View> getMappedViews() {
-        return mSharedElements;
+    public ArrayList<View> copyMappedViews() {
+        return new ArrayList<View>(mSharedElements);
     }
 
     public ArrayList<String> getAllSharedElementNames() { return mAllSharedElementNames; }
@@ -521,9 +521,7 @@
     protected void clearState() {
         // Clear the state so that we can't hold any references accidentally and leak memory.
         mWindow = null;
-        mAllSharedElementNames.clear();
         mSharedElements.clear();
-        mSharedElementNames.clear();
         mTransitioningViews.clear();
         mResultReceiver = null;
         mPendingTransition = null;
diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java
index 0304246..0d2af8c 100644
--- a/core/java/android/app/ActivityTransitionState.java
+++ b/core/java/android/app/ActivityTransitionState.java
@@ -240,7 +240,7 @@
             if (!mHasExited) {
                 mHasExited = true;
                 if (mEnterTransitionCoordinator != null) {
-                    mEnterTransitionCoordinator.stop();
+                    mEnterTransitionCoordinator.cancelEnter();
                     mEnterTransitionCoordinator = null;
                 }
                 ArrayMap<String, View> sharedElements = new ArrayMap<String, View>();
@@ -268,7 +268,7 @@
                 if (mCalledExitCoordinator != null) {
                     mExitingFrom = mCalledExitCoordinator.getAcceptedNames();
                     mExitingTo = mCalledExitCoordinator.getMappedNames();
-                    mExitingToView = mCalledExitCoordinator.getMappedViews();
+                    mExitingToView = mCalledExitCoordinator.copyMappedViews();
                     mCalledExitCoordinator.startExit();
                 }
             }
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 6dead08..0b4510fe 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -647,6 +647,25 @@
             reply.writeNoException();
             return true;
         }
+
+        case STOP_MEDIA_PLAYING_TRANSACTION:
+        {
+            data.enforceInterface(IApplicationThread.descriptor);
+            IBinder token = data.readStrongBinder();
+            scheduleStopMediaPlaying(token);
+            reply.writeNoException();
+            return true;
+        }
+
+        case BACKGROUND_MEDIA_PLAYING_CHANGED_TRANSACTION:
+        {
+            data.enforceInterface(IApplicationThread.descriptor);
+            IBinder token = data.readStrongBinder();
+            boolean enabled = data.readInt() > 0;
+            scheduleBackgroundMediaPlayingChanged(token, enabled);
+            reply.writeNoException();
+            return true;
+        }
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -1304,4 +1323,23 @@
         mRemote.transact(UPDATE_TIME_PREFS_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
         data.recycle();
     }
+
+    @Override
+    public void scheduleStopMediaPlaying(IBinder token) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        data.writeInterfaceToken(IApplicationThread.descriptor);
+        data.writeStrongBinder(token);
+        mRemote.transact(STOP_MEDIA_PLAYING_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
+        data.recycle();
+    }
+
+    @Override
+    public void scheduleBackgroundMediaPlayingChanged(IBinder token, boolean enabled) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        data.writeInterfaceToken(IApplicationThread.descriptor);
+        data.writeStrongBinder(token);
+        data.writeInt(enabled ? 1 : 0);
+        mRemote.transact(BACKGROUND_MEDIA_PLAYING_CHANGED_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
+        data.recycle();
+    }
 }
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index 5e18d0f..90f36b8 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -58,6 +58,7 @@
     private Bundle mSharedElementsBundle;
     private boolean mWasOpaque;
     private boolean mAreViewsReady;
+    private boolean mIsViewsTransitionStarted;
 
     public EnterTransitionCoordinator(Activity activity, ResultReceiver resultReceiver,
             ArrayList<String> sharedElementNames, boolean isReturning) {
@@ -219,7 +220,7 @@
     private void cancel() {
         if (!mIsCanceled) {
             mIsCanceled = true;
-            if (getViewsTransition() == null) {
+            if (getViewsTransition() == null || mIsViewsTransitionStarted) {
                 setViewVisibility(mSharedElements, View.VISIBLE);
             } else {
                 mTransitioningViews.addAll(mSharedElements);
@@ -363,6 +364,7 @@
                 stripOffscreenViews();
             }
         }
+        mIsViewsTransitionStarted = mIsViewsTransitionStarted || startEnterTransition;
 
         Transition transition = mergeTransitions(sharedElementTransition, viewsTransition);
         if (startSharedElementTransition) {
@@ -433,6 +435,17 @@
 
     public void stop() {
         makeOpaque();
+        mIsCanceled = true;
+        mResultReceiver = null;
+        if (mBackgroundAnimator != null) {
+            mBackgroundAnimator.end();
+            mBackgroundAnimator = null;
+        }
+        mActivity = null;
+        clearState();
+    }
+
+    public void cancelEnter() {
         mHasStopped = true;
         mIsCanceled = true;
         mResultReceiver = null;
@@ -440,6 +453,8 @@
             mBackgroundAnimator.cancel();
             mBackgroundAnimator = null;
         }
+        mActivity = null;
+        clearState();
     }
 
     private void makeOpaque() {
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index 93cba0d..0fbd685 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -66,6 +66,8 @@
 
     private Bundle mExitSharedElementBundle;
 
+    private boolean mIsExitStarted;
+
     public ExitTransitionCoordinator(Activity activity, ArrayList<String> names,
             ArrayList<String> accepted, ArrayList<View> mapped, boolean isReturning) {
         super(activity.getWindow(), names, getListener(activity, isReturning),
@@ -114,6 +116,7 @@
         setViewVisibility(mTransitioningViews, View.VISIBLE);
         setViewVisibility(mSharedElements, View.VISIBLE);
         mIsHidden = true;
+        clearState();
     }
 
     private void sharedElementExitBack() {
@@ -164,46 +167,52 @@
     }
 
     public void startExit() {
-        startTransition(new Runnable() {
-            @Override
-            public void run() {
-                beginTransitions();
-            }
-        });
-        setViewVisibility(mTransitioningViews, View.INVISIBLE);
+        if (!mIsExitStarted) {
+            mIsExitStarted = true;
+            startTransition(new Runnable() {
+                @Override
+                public void run() {
+                    beginTransitions();
+                }
+            });
+            setViewVisibility(mTransitioningViews, View.INVISIBLE);
+        }
     }
 
     public void startExit(int resultCode, Intent data) {
-        mHandler = new Handler() {
-            @Override
-            public void handleMessage(Message msg) {
-                mIsCanceled = true;
-                finish();
-            }
-        };
-        mHandler.sendEmptyMessageDelayed(MSG_CANCEL, MAX_WAIT_MS);
-        if (getDecor().getBackground() == null) {
-            ColorDrawable black = new ColorDrawable(0xFF000000);
-            black.setAlpha(0);
-            getWindow().setBackgroundDrawable(black);
-            black.setAlpha(255);
-        }
-        ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(mActivity, this,
-                mAllSharedElementNames, resultCode, data);
-        mActivity.convertToTranslucent(new Activity.TranslucentConversionListener() {
-            @Override
-            public void onTranslucentConversionComplete(boolean drawComplete) {
-                if (!mIsCanceled) {
-                    fadeOutBackground();
+        if (!mIsExitStarted) {
+            mIsExitStarted = true;
+            mHandler = new Handler() {
+                @Override
+                public void handleMessage(Message msg) {
+                    mIsCanceled = true;
+                    finish();
                 }
+            };
+            mHandler.sendEmptyMessageDelayed(MSG_CANCEL, MAX_WAIT_MS);
+            if (getDecor().getBackground() == null) {
+                ColorDrawable black = new ColorDrawable(0xFF000000);
+                black.setAlpha(0);
+                getWindow().setBackgroundDrawable(black);
+                black.setAlpha(255);
             }
-        }, options);
-        startTransition(new Runnable() {
-            @Override
-            public void run() {
-                startExitTransition();
-            }
-        });
+            ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(mActivity, this,
+                    mAllSharedElementNames, resultCode, data);
+            mActivity.convertToTranslucent(new Activity.TranslucentConversionListener() {
+                @Override
+                public void onTranslucentConversionComplete(boolean drawComplete) {
+                    if (!mIsCanceled) {
+                        fadeOutBackground();
+                    }
+                }
+            }, options);
+            startTransition(new Runnable() {
+                @Override
+                public void run() {
+                    startExitTransition();
+                }
+            });
+        }
     }
 
     private void startExitTransition() {
@@ -216,20 +225,23 @@
 
     private void fadeOutBackground() {
         if (mBackgroundAnimator == null) {
-            Drawable background = getDecor().getBackground();
-            mBackgroundAnimator = ObjectAnimator.ofInt(background, "alpha", 0);
-            mBackgroundAnimator.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    mBackgroundAnimator = null;
-                    if (!mIsCanceled) {
-                        mIsBackgroundReady = true;
-                        notifyComplete();
+            ViewGroup decor = getDecor();
+            Drawable background;
+            if (decor != null && (background = decor.getBackground()) != null) {
+                mBackgroundAnimator = ObjectAnimator.ofInt(background, "alpha", 0);
+                mBackgroundAnimator.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        mBackgroundAnimator = null;
+                        if (!mIsCanceled) {
+                            mIsBackgroundReady = true;
+                            notifyComplete();
+                        }
                     }
-                }
-            });
-            mBackgroundAnimator.setDuration(getFadeDuration());
-            mBackgroundAnimator.start();
+                });
+                mBackgroundAnimator.setDuration(getFadeDuration());
+                mBackgroundAnimator.start();
+            }
         }
     }
 
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 6e4192b..b3a8a8a 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -415,11 +415,9 @@
 
     public void performIdleMaintenance() throws RemoteException;
 
-    /** @hide */
     public IActivityContainer createActivityContainer(IBinder parentActivityToken,
             IActivityContainerCallback callback) throws RemoteException;
 
-    /** @hide */
     public void deleteActivityContainer(IActivityContainer container) throws RemoteException;
 
     public IActivityContainer getEnclosingActivityContainer(IBinder activityToken)
@@ -427,28 +425,25 @@
 
     public IBinder getHomeActivityToken() throws RemoteException;
 
-    /** @hide */
     public void startLockTaskModeOnCurrent() throws RemoteException;
 
-    /** @hide */
     public void startLockTaskMode(int taskId) throws RemoteException;
 
-    /** @hide */
     public void startLockTaskMode(IBinder token) throws RemoteException;
 
-    /** @hide */
     public void stopLockTaskMode() throws RemoteException;
 
-    /** @hide */
     public void stopLockTaskModeOnCurrent() throws RemoteException;
 
-    /** @hide */
     public boolean isInLockTaskMode() throws RemoteException;
 
-    /** @hide */
     public void setTaskDescription(IBinder token, ActivityManager.TaskDescription values)
             throws RemoteException;
 
+    public boolean setMediaPlaying(IBinder token, boolean playing) throws RemoteException;
+    public boolean isBackgroundMediaPlaying(IBinder token) throws RemoteException;
+    public void mediaResourcesReleased(IBinder token) throws RemoteException;
+
     /*
      * Private non-Binder interfaces
      */
@@ -753,4 +748,7 @@
     int STOP_LOCK_TASK_BY_CURRENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+222;
     int FINISH_VOICE_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+223;
     int IS_TOP_OF_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+224;
+    int SET_MEDIA_PLAYING_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+225;
+    int IS_BG_MEDIA_PLAYING_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+226;
+    int MEDIA_RESOURCES_RELEASED = IBinder.FIRST_CALL_TRANSACTION+227;
 }
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index d3c4854..18faf0e 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -145,6 +145,8 @@
     void setProcessState(int state) throws RemoteException;
     void scheduleInstallProvider(ProviderInfo provider) throws RemoteException;
     void updateTimePrefs(boolean is24Hour) throws RemoteException;
+    void scheduleStopMediaPlaying(IBinder token) throws RemoteException;
+    void scheduleBackgroundMediaPlayingChanged(IBinder token, boolean enabled) throws RemoteException;
 
     String descriptor = "android.app.IApplicationThread";
 
@@ -199,4 +201,6 @@
     int SET_PROCESS_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+49;
     int SCHEDULE_INSTALL_PROVIDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+50;
     int UPDATE_TIME_PREFS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+51;
+    int STOP_MEDIA_PLAYING_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+52;
+    int BACKGROUND_MEDIA_PLAYING_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+53;
 }
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index d75304f..35e5050 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -20,6 +20,7 @@
 import android.annotation.SdkConstant.SdkConstantType;
 import android.bluetooth.le.BluetoothLeAdvertiser;
 import android.bluetooth.le.BluetoothLeScanner;
+import android.bluetooth.le.ScanResult;
 import android.content.Context;
 import android.os.Handler;
 import android.os.IBinder;
@@ -37,6 +38,7 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
@@ -504,13 +506,7 @@
      */
     public BluetoothLeAdvertiser getBluetoothLeAdvertiser() {
         // TODO: Return null if this feature is not supported by hardware.
-        try {
-            IBluetoothGatt iGatt = mManagerService.getBluetoothGatt();
-            return new BluetoothLeAdvertiser(iGatt);
-        } catch (RemoteException e) {
-            Log.e(TAG, "failed to get BluetoothLeAdvertiser, error: " + e);
-            return null;
-        }
+        return new BluetoothLeAdvertiser(mManagerService);
     }
 
     /**
@@ -518,13 +514,7 @@
      */
     public BluetoothLeScanner getBluetoothLeScanner() {
         // TODO: Return null if BLE scan is not supported by hardware.
-        try {
-            IBluetoothGatt iGatt = mManagerService.getBluetoothGatt();
-            return new BluetoothLeScanner(iGatt);
-        } catch (RemoteException e) {
-            Log.e(TAG, "failed to get BluetoothLeScanner, error: " + e);
-            return null;
-        }
+        return new BluetoothLeScanner(mManagerService);
     }
 
     /**
@@ -2137,5 +2127,10 @@
         public void onConnectionCongested(String address, boolean congested) {
             // no op
         }
+
+        @Override
+        public void onBatchScanResults(List<ScanResult> results) {
+            // no op
+        }
     }
 }
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 6c1a45e..4255cd4 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -16,6 +16,7 @@
 
 package android.bluetooth;
 
+import android.bluetooth.le.ScanResult;
 import android.content.Context;
 import android.os.ParcelUuid;
 import android.os.RemoteException;
@@ -627,6 +628,11 @@
                     Log.w(TAG, "Unhandled exception in callback", ex);
                 }
             }
+
+            @Override
+            public void onBatchScanResults(List<ScanResult> results) {
+                // no op
+            }
         };
 
     /*package*/ BluetoothGatt(Context context, IBluetoothGatt iGatt, BluetoothDevice device,
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index 273d76d..5ed10a6 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -38,6 +38,7 @@
     void startScanWithFilters(in int appIf, in boolean isServer,
                               in ScanSettings settings, in List<ScanFilter> filters);
     void stopScan(in int appIf, in boolean isServer);
+    void flushPendingBatchResults(in int appIf, in boolean isServer);
     void startMultiAdvertising(in int appIf,
                                in AdvertisementData advertiseData,
                                in AdvertisementData scanResponse,
diff --git a/core/java/android/bluetooth/IBluetoothGattCallback.aidl b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
index 946a6f6..c18d357 100644
--- a/core/java/android/bluetooth/IBluetoothGattCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
@@ -16,7 +16,7 @@
 package android.bluetooth;
 
 import android.os.ParcelUuid;
-
+import android.bluetooth.le.ScanResult;
 
 /**
  * Callback definitions for interacting with BLE / GATT
@@ -27,6 +27,7 @@
     void onClientConnectionState(in int status, in int clientIf,
                                  in boolean connected, in String address);
     void onScanResult(in String address, in int rssi, in byte[] advData);
+    void onBatchScanResults(in List<ScanResult> batchResults);
     void onGetService(in String address, in int srvcType, in int srvcInstId,
                       in ParcelUuid srvcUuid);
     void onGetIncludedService(in String address, in int srvcType, in int srvcInstId,
diff --git a/core/java/android/bluetooth/le/AdvertiseCallback.java b/core/java/android/bluetooth/le/AdvertiseCallback.java
index f1334c2..59f8cdc 100644
--- a/core/java/android/bluetooth/le/AdvertiseCallback.java
+++ b/core/java/android/bluetooth/le/AdvertiseCallback.java
@@ -52,6 +52,12 @@
     public static final int ADVERTISE_FAILED_CONTROLLER_FAILURE = 5;
 
     /**
+     * Operation fails due to GATT service failure.
+     * @hide
+     */
+    public static final int ADVERTISE_FAILED_GATT_SERVICE_FAILURE = 6;
+
+    /**
      * Callback when advertising operation succeeds.
      *
      * @param settingsInEffect The actual settings used for advertising, which may be different from
diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index c20b81b..a83d875 100644
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -20,6 +20,7 @@
 import android.bluetooth.BluetoothGatt;
 import android.bluetooth.IBluetoothGatt;
 import android.bluetooth.IBluetoothGattCallback;
+import android.bluetooth.IBluetoothManager;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.ParcelUuid;
@@ -27,6 +28,7 @@
 import android.util.Log;
 
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 
@@ -47,7 +49,7 @@
 
     private static final String TAG = "BluetoothLeAdvertiser";
 
-    private final IBluetoothGatt mBluetoothGatt;
+    private final IBluetoothManager mBluetoothManager;
     private final Handler mHandler;
     private final Map<AdvertiseCallback, AdvertiseCallbackWrapper>
             mLeAdvertisers = new HashMap<AdvertiseCallback, AdvertiseCallbackWrapper>();
@@ -55,11 +57,11 @@
     /**
      * Use BluetoothAdapter.getLeAdvertiser() instead.
      *
-     * @param bluetoothGatt
+     * @param bluetoothManager
      * @hide
      */
-    public BluetoothLeAdvertiser(IBluetoothGatt bluetoothGatt) {
-        mBluetoothGatt = bluetoothGatt;
+    public BluetoothLeAdvertiser(IBluetoothManager bluetoothManager) {
+        mBluetoothManager = bluetoothManager;
         mHandler = new Handler(Looper.getMainLooper());
     }
 
@@ -102,11 +104,19 @@
             postCallbackFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_ALREADY_STARTED);
             return;
         }
+        IBluetoothGatt gatt;
+        try {
+            gatt = mBluetoothManager.getBluetoothGatt();
+        } catch (RemoteException e) {
+            Log.e(TAG, "failed to get bluetooth gatt - ", e);
+            postCallbackFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_CONTROLLER_FAILURE);
+            return;
+        }
         AdvertiseCallbackWrapper wrapper = new AdvertiseCallbackWrapper(callback, advertiseData,
-                scanResponse, settings, mBluetoothGatt);
+                scanResponse, settings, gatt);
         UUID uuid = UUID.randomUUID();
         try {
-            mBluetoothGatt.registerClient(new ParcelUuid(uuid), wrapper);
+            gatt.registerClient(new ParcelUuid(uuid), wrapper);
             if (wrapper.advertiseStarted()) {
                 mLeAdvertisers.put(callback, wrapper);
             }
@@ -133,12 +143,19 @@
             return;
         }
         try {
-            mBluetoothGatt.stopMultiAdvertising(wrapper.mLeHandle);
+            IBluetoothGatt gatt = mBluetoothManager.getBluetoothGatt();
+            if (gatt == null) {
+                postCallbackFailure(callback,
+                        AdvertiseCallback.ADVERTISE_FAILED_GATT_SERVICE_FAILURE);
+            }
+            gatt.stopMultiAdvertising(wrapper.mLeHandle);
             if (wrapper.advertiseStopped()) {
                 mLeAdvertisers.remove(callback);
             }
         } catch (RemoteException e) {
             Log.e(TAG, "failed to stop advertising", e);
+            postCallbackFailure(callback,
+                    AdvertiseCallback.ADVERTISE_FAILED_GATT_SERVICE_FAILURE);
         }
     }
 
@@ -214,8 +231,6 @@
                         Log.e(TAG, "fail to start le advertise: " + e);
                         mLeHandle = -1;
                         notifyAll();
-                    } catch (Exception e) {
-                        Log.e(TAG, "fail to start advertise: " + e.getStackTrace());
                     }
                 } else {
                     // registration failed
@@ -360,6 +375,11 @@
         public void onConnectionCongested(String address, boolean congested) {
             // no op
         }
+
+        @Override
+        public void onBatchScanResults(List<ScanResult> results) {
+            // no op
+        }
     }
 
     private void postCallbackFailure(final AdvertiseCallback callback, final int error) {
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index fbaf5d2..44aa117 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -21,6 +21,7 @@
 import android.bluetooth.BluetoothGatt;
 import android.bluetooth.IBluetoothGatt;
 import android.bluetooth.IBluetoothGattCallback;
+import android.bluetooth.IBluetoothManager;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.ParcelUuid;
@@ -51,15 +52,15 @@
     private static final String TAG = "BluetoothLeScanner";
     private static final boolean DBG = true;
 
-    private final IBluetoothGatt mBluetoothGatt;
+    private final IBluetoothManager mBluetoothManager;
     private final Handler mHandler;
     private final Map<ScanCallback, BleScanCallbackWrapper> mLeScanClients;
 
     /**
      * @hide
      */
-    public BluetoothLeScanner(IBluetoothGatt bluetoothGatt) {
-        mBluetoothGatt = bluetoothGatt;
+    public BluetoothLeScanner(IBluetoothManager bluetoothManager) {
+        mBluetoothManager = bluetoothManager;
         mHandler = new Handler(Looper.getMainLooper());
         mLeScanClients = new HashMap<ScanCallback, BleScanCallbackWrapper>();
     }
@@ -84,11 +85,21 @@
                 postCallbackError(callback, ScanCallback.SCAN_FAILED_ALREADY_STARTED);
                 return;
             }
-            BleScanCallbackWrapper wrapper = new BleScanCallbackWrapper(mBluetoothGatt, filters,
+            IBluetoothGatt gatt;
+            try {
+                gatt = mBluetoothManager.getBluetoothGatt();
+            } catch (RemoteException e) {
+                gatt = null;
+            }
+            if (gatt == null) {
+                postCallbackError(callback, ScanCallback.SCAN_FAILED_GATT_SERVICE_FAILURE);
+                return;
+            }
+            BleScanCallbackWrapper wrapper = new BleScanCallbackWrapper(gatt, filters,
                     settings, callback);
             try {
                 UUID uuid = UUID.randomUUID();
-                mBluetoothGatt.registerClient(new ParcelUuid(uuid), wrapper);
+                gatt.registerClient(new ParcelUuid(uuid), wrapper);
                 if (wrapper.scanStarted()) {
                     mLeScanClients.put(callback, wrapper);
                 } else {
@@ -131,18 +142,26 @@
     }
 
     /**
-     * Poll scan results from bluetooth controller. This will return Bluetooth LE scan results
-     * batched on bluetooth controller.
+     * Flush pending batch scan results stored in Bluetooth controller. This will return Bluetooth
+     * LE scan results batched on bluetooth controller. Returns immediately, batch scan results data
+     * will be delivered through the {@code callback}.
      *
      * @param callback Callback of the Bluetooth LE Scan, it has to be the same instance as the one
      *            used to start scan.
-     * @param flush Whether to flush the batch scan buffer. Note the other batch scan clients will
-     *            get batch scan callback if the batch scan buffer is flushed.
-     * @return Batch Scan results.
-     * @hide TODO: unhide when batching is supported in stack.
+     *
+     * @hide
      */
-    public List<ScanResult> getBatchScanResults(ScanCallback callback, boolean flush) {
-        throw new UnsupportedOperationException("not impelemented");
+    public void flushPendingScanResults(ScanCallback callback) {
+        if (callback == null) {
+            throw new IllegalArgumentException("callback cannot be null!");
+        }
+        synchronized (mLeScanClients) {
+            BleScanCallbackWrapper wrapper = mLeScanClients.get(callback);
+            if (wrapper == null) {
+                return;
+            }
+            wrapper.flushPendingBatchResults();
+        }
     }
 
     /**
@@ -195,13 +214,27 @@
                     mBluetoothGatt.stopScan(mLeHandle, false);
                     mBluetoothGatt.unregisterClient(mLeHandle);
                 } catch (RemoteException e) {
-                    Log.e(TAG, "Failed to stop scan and unregister" + e);
+                    Log.e(TAG, "Failed to stop scan and unregister", e);
                 }
                 mLeHandle = -1;
                 notifyAll();
             }
         }
 
+        void flushPendingBatchResults() {
+            synchronized (this) {
+                if (mLeHandle <= 0) {
+                    Log.e(TAG, "Error state, mLeHandle: " + mLeHandle);
+                    return;
+                }
+                try {
+                    mBluetoothGatt.flushPendingBatchResults(mLeHandle, false);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Failed to get pending scan results", e);
+                }
+            }
+        }
+
         /**
          * Application interface registered - app is ready to go
          */
@@ -256,9 +289,27 @@
             BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(
                     address);
             long scanNanos = SystemClock.elapsedRealtimeNanos();
-            ScanResult result = new ScanResult(device, advData, rssi,
+            final ScanResult result = new ScanResult(device, advData, rssi,
                     scanNanos);
-            mScanCallback.onAdvertisementUpdate(result);
+            Handler handler = new Handler(Looper.getMainLooper());
+            handler.post(new Runnable() {
+                    @Override
+                public void run() {
+                    mScanCallback.onAdvertisementUpdate(result);
+                }
+            });
+
+        }
+
+        @Override
+        public void onBatchScanResults(final List<ScanResult> results) {
+            Handler handler = new Handler(Looper.getMainLooper());
+            handler.post(new Runnable() {
+                    @Override
+                public void run() {
+                    mScanCallback.onBatchScanResults(results);
+                }
+            });
         }
 
         @Override
diff --git a/core/java/android/bluetooth/le/ScanSettings.java b/core/java/android/bluetooth/le/ScanSettings.java
index 0a85675..3bb39b3 100644
--- a/core/java/android/bluetooth/le/ScanSettings.java
+++ b/core/java/android/bluetooth/le/ScanSettings.java
@@ -44,7 +44,6 @@
     public static final int CALLBACK_TYPE_ON_UPDATE = 0;
     /**
      * Callback when a bluetooth advertisement is found for the first time.
-     *
      * @hide
      */
     public static final int CALLBACK_TYPE_ON_FOUND = 1;
@@ -190,6 +189,7 @@
          *            {@link ScanSettings#SCAN_RESULT_TYPE_FULL} or
          *            {@link ScanSettings#SCAN_RESULT_TYPE_TRUNCATED}.
          * @throws IllegalArgumentException If the {@code scanResultType} is invalid.
+         *
          * @hide
          */
         public Builder setScanResultType(int scanResultType) {
diff --git a/core/res/res/values-mcc214-mnc07/config.xml b/core/res/res/values-mcc214-mnc07/config.xml
new file mode 100644
index 0000000..ce7526c
--- /dev/null
+++ b/core/res/res/values-mcc214-mnc07/config.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Array of ConnectivityManager.TYPE_xxxx values allowable for tethering -->
+    <!-- Common options are [1, 4] for TYPE_WIFI and TYPE_MOBILE_DUN or
+    <!== [0,1,5,7] for TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI and TYPE_BLUETOOTH -->
+    <integer-array translatable="false" name="config_tether_upstream_types">
+      <item>1</item>
+      <item>4</item>
+      <item>7</item>
+      <item>9</item>
+    </integer-array>
+
+    <!-- String containing the apn value for tethering.  May be overriden by secure settings
+         TETHER_DUN_APN.  Value is a comma separated series of strings:
+         "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type"
+         note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
+    <string translatable="false" name="config_tether_apndata">Conexion Compartida,movistar.es,,,MOVISTAR,MOVISTAR,,,,,214,07,1,DUN</string>
+
+</resources>
diff --git a/docs/html/preview/api-overview.jd b/docs/html/preview/api-overview.jd
index 2e99194..16bc444 100644
--- a/docs/html/preview/api-overview.jd
+++ b/docs/html/preview/api-overview.jd
@@ -781,7 +781,7 @@
 $ rm /tmp/device_owner.xml
 $ echo "&lt;?xml version='1.0' encoding='utf-8' standalone='yes' ?&gt;"
 &gt;&gt; /tmp/device_owner.xml
-$ echo "&device-owner package=\"&lt;your_device_owner_package&gt;\"
+$ echo "&lt;device-owner package=\"&lt;your_device_owner_package&gt;\"
 name=\"*&lt;your_organization_name&gt;\" /&gt;" &gt;&gt; /tmp/device_owner.xml
 $ adb push /tmp/device_owner.xml /data/system/device_owner.xml
 $ adb reboot
diff --git a/docs/html/tools/support-library/index.jd b/docs/html/tools/support-library/index.jd
index e905285..68eca49 100644
--- a/docs/html/tools/support-library/index.jd
+++ b/docs/html/tools/support-library/index.jd
@@ -61,6 +61,33 @@
 <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=""
+/>Android Support Library, revision 20</a> <em>(July 2014)</em>
+  </p>
+  <div class="toggle-content-toggleme">
+    <dl>
+      <dt>Changes for v4 support library:</dt>
+      <dd>
+        <ul>
+          <li>Added extended notification support for Android Wear in
+            {@link android.support.v4.app.NotificationCompat.WearableExtender}, which allows you
+            to specify wearable-specific features in your notifications.</li>
+          <li>Added {@link android.support.v4.app.NotificationCompat.Action.WearableExtender},
+            which allows actions to be added on wearable notifications.</li>
+          <li>Added {@link android.support.v4.app.NotificationManagerCompat}, which allows you
+            to issue notifications that properly support wearable features.</li>
+          <li>Added {@link android.support.v4.app.RemoteInput}, which allows a handheld device
+            to receive voice input from a notification that appears on a wearable device.</li>
+          <li>Improved the handling of touch feedback in
+            {@link android.support.v4.widget.SwipeRefreshLayout}.</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=""
 />Android Support Library, revision 19.1.0</a> <em>(March 2014)</em>
   </p>
   <div class="toggle-content-toggleme">
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1da8123..dd7775d 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5608,7 +5608,22 @@
             }
         }
     }
-    
+
+    @Override
+    public final void mediaResourcesReleased(IBinder token) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (this) {
+                ActivityStack stack = ActivityRecord.getStackLocked(token);
+                if (stack != null) {
+                    stack.mediaResourcesReleased(token);
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
     @Override
     public String getCallingPackage(IBinder token) {
         synchronized (this) {
@@ -9347,6 +9362,7 @@
                 }
                 if (r.changeWindowTranslucency(true)) {
                     mWindowManager.setAppFullscreen(token, true);
+                    r.task.stack.releaseMediaResources();
                     mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
                     return true;
                 }
@@ -9383,6 +9399,38 @@
     }
 
     @Override
+    public boolean setMediaPlaying(IBinder token, boolean playing) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (this) {
+                final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+                if (r != null) {
+                    return mStackSupervisor.setMediaPlayingLocked(r, playing);
+                }
+            }
+            return false;
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    @Override
+    public boolean isBackgroundMediaPlaying(IBinder token) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (this) {
+                final ActivityStack stack = ActivityRecord.getStackLocked(token);
+                final boolean playing = stack == null ? false : stack.isMediaPlaying();
+                if (ActivityStackSupervisor.DEBUG_MEDIA_VISIBILITY) Slog.d(TAG,
+                        "isBackgroundMediaPlaying: stack=" + stack + " playing=" + playing);
+                return playing;
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    @Override
     public ActivityOptions getActivityOptions(IBinder token) {
         final long origId = Binder.clearCallingIdentity();
         try {
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index fd2a0b1..d70e8b7 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -203,6 +203,14 @@
                     pw.print(" resultWho="); pw.print(resultWho);
                     pw.print(" resultCode="); pw.println(requestCode);
         }
+        if (taskDescription.getIcon() != null || taskDescription.getLabel() != null ||
+                taskDescription.getPrimaryColor() != 0) {
+            pw.print(prefix); pw.print("taskDescription:");
+                    pw.print(" icon="); pw.print(taskDescription.getIcon());
+                    pw.print(" label=\""); pw.print(taskDescription.getLabel()); pw.print("\"");
+                    pw.print(" color=");
+                    pw.println(Integer.toHexString(taskDescription.getPrimaryColor()));
+        }
         if (results != null) {
             pw.print(prefix); pw.print("results="); pw.println(results);
         }
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index ca518f3..c6bba22 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -32,7 +32,6 @@
 
 import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
 
 import static com.android.server.am.ActivityStackSupervisor.DEBUG_ADD_REMOVE;
 import static com.android.server.am.ActivityStackSupervisor.DEBUG_APP;
@@ -47,6 +46,7 @@
 import com.android.server.Watchdog;
 import com.android.server.am.ActivityManagerService.ItemMatcher;
 import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
+import com.android.server.am.ActivityStackSupervisor.ActivityDisplay;
 import com.android.server.wm.AppTransition;
 import com.android.server.wm.TaskGroup;
 import com.android.server.wm.WindowManagerService;
@@ -252,14 +252,14 @@
     static final int STOP_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 4;
     static final int DESTROY_ACTIVITIES_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 5;
     static final int TRANSLUCENT_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 6;
+    static final int STOP_MEDIA_PLAYING_TIMEOUT_MSG =
+            ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 7;
 
     static class ScheduleDestroyArgs {
         final ProcessRecord mOwner;
-        final boolean mOomAdj;
         final String mReason;
-        ScheduleDestroyArgs(ProcessRecord owner, boolean oomAdj, String reason) {
+        ScheduleDestroyArgs(ProcessRecord owner, String reason) {
             mOwner = owner;
-            mOomAdj = oomAdj;
             mReason = reason;
         }
     }
@@ -320,7 +320,7 @@
                 case DESTROY_ACTIVITIES_MSG: {
                     ScheduleDestroyArgs args = (ScheduleDestroyArgs)msg.obj;
                     synchronized (mService) {
-                        destroyActivitiesLocked(args.mOwner, args.mOomAdj, args.mReason);
+                        destroyActivitiesLocked(args.mOwner, args.mReason);
                     }
                 } break;
                 case TRANSLUCENT_TIMEOUT_MSG: {
@@ -328,6 +328,15 @@
                         notifyActivityDrawnLocked(null);
                     }
                 } break;
+                case STOP_MEDIA_PLAYING_TIMEOUT_MSG: {
+                    synchronized (mService) {
+                        final ActivityRecord r = getMediaPlayer();
+                        Slog.e(TAG, "Timeout waiting for stopMediaPlaying player=" + r);
+                        if (r != null) {
+                            mService.killAppAtUsersRequest(r.app, null);
+                        }
+                    }
+                } break;
             }
         }
     }
@@ -930,11 +939,14 @@
             mHandler.removeMessages(STOP_TIMEOUT_MSG, r);
             r.stopped = true;
             r.state = ActivityState.STOPPED;
+            if (mActivityContainer.mActivityDisplay.mMediaPlayingActivity == r) {
+                mStackSupervisor.setMediaPlayingLocked(r, false);
+            }
             if (r.finishing) {
                 r.clearOptionsLocked();
             } else {
                 if (r.configDestroy) {
-                    destroyActivityLocked(r, true, false, "stop-config");
+                    destroyActivityLocked(r, true, "stop-config");
                     mStackSupervisor.resumeTopActivitiesLocked();
                 } else {
                     mStackSupervisor.updatePreviousProcessLocked(r);
@@ -966,8 +978,10 @@
                     // instance right now, we need to first completely stop
                     // the current instance before starting the new one.
                     if (DEBUG_PAUSE) Slog.v(TAG, "Destroying after pause: " + prev);
-                    destroyActivityLocked(prev, true, false, "pause-config");
-                } else {
+                    destroyActivityLocked(prev, true, "pause-config");
+                } else if (!isMediaPlaying()) {
+                    // If we were playing then resumeTopActivities will release resources before
+                    // stopping.
                     mStackSupervisor.mStoppingActivities.add(prev);
                     if (mStackSupervisor.mStoppingActivities.size() > 3 ||
                             prev.frontOfTask && mTaskHistory.size() <= 1) {
@@ -1280,10 +1294,14 @@
                                 case PAUSED:
                                     // This case created for transitioning activities from
                                     // translucent to opaque {@link Activity#convertToOpaque}.
-                                    if (!mStackSupervisor.mStoppingActivities.contains(r)) {
-                                        mStackSupervisor.mStoppingActivities.add(r);
+                                    if (getMediaPlayer() == r) {
+                                        releaseMediaResources();
+                                    } else {
+                                        if (!mStackSupervisor.mStoppingActivities.contains(r)) {
+                                            mStackSupervisor.mStoppingActivities.add(r);
+                                        }
+                                        mStackSupervisor.scheduleIdleLocked();
                                     }
-                                    mStackSupervisor.scheduleIdleLocked();
                                     break;
 
                                 default:
@@ -1548,8 +1566,6 @@
             // very soon and it would be a waste to let it get killed if it
             // happens to be sitting towards the end.
             if (next.app != null && next.app.thread != null) {
-                // No reason to do full oom adj update here; we'll let that
-                // happen whenever it needs to later.
                 mService.updateLruProcessLocked(next.app, true, null);
             }
             if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
@@ -2433,7 +2449,7 @@
                 if (DEBUG_STATES) Slog.v(TAG, "Stop failed; moving to STOPPED: " + r);
                 r.state = ActivityState.STOPPED;
                 if (r.configDestroy) {
-                    destroyActivityLocked(r, true, false, "stop-except");
+                    destroyActivityLocked(r, true, "stop-except");
                 }
             }
         }
@@ -2693,7 +2709,7 @@
             // If this activity is already stopped, we can just finish
             // it right now.
             r.makeFinishing();
-            boolean activityRemoved = destroyActivityLocked(r, true, oomAdj, "finish-imm");
+            boolean activityRemoved = destroyActivityLocked(r, true, "finish-imm");
             if (activityRemoved) {
                 mStackSupervisor.resumeTopActivitiesLocked();
             }
@@ -2856,6 +2872,9 @@
 
         // Get rid of any pending idle timeouts.
         removeTimeoutsForActivityLocked(r);
+        if (getMediaPlayer() == r) {
+            mStackSupervisor.setMediaPlayingLocked(r, false);
+        }
     }
 
     private void removeTimeoutsForActivityLocked(ActivityRecord r) {
@@ -2914,13 +2933,13 @@
         }
     }
 
-    final void scheduleDestroyActivities(ProcessRecord owner, boolean oomAdj, String reason) {
+    final void scheduleDestroyActivities(ProcessRecord owner, String reason) {
         Message msg = mHandler.obtainMessage(DESTROY_ACTIVITIES_MSG);
-        msg.obj = new ScheduleDestroyArgs(owner, oomAdj, reason);
+        msg.obj = new ScheduleDestroyArgs(owner, reason);
         mHandler.sendMessage(msg);
     }
 
-    final void destroyActivitiesLocked(ProcessRecord owner, boolean oomAdj, String reason) {
+    final void destroyActivitiesLocked(ProcessRecord owner, String reason) {
         boolean lastIsOpaque = false;
         boolean activityRemoved = false;
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
@@ -2948,7 +2967,7 @@
                     if (DEBUG_SWITCH) Slog.v(TAG, "Destroying " + r + " in state " + r.state
                             + " resumed=" + mResumedActivity
                             + " pausing=" + mPausingActivity);
-                    if (destroyActivityLocked(r, true, oomAdj, reason)) {
+                    if (destroyActivityLocked(r, true, reason)) {
                         activityRemoved = true;
                     }
                 }
@@ -2965,8 +2984,7 @@
      * a configuration switch where we destroy the current client-side object
      * but then create a new client-side object for this same HistoryRecord.
      */
-    final boolean destroyActivityLocked(ActivityRecord r,
-            boolean removeFromApp, boolean oomAdj, String reason) {
+    final boolean destroyActivityLocked(ActivityRecord r, boolean removeFromApp, String reason) {
         if (DEBUG_SWITCH || DEBUG_CLEANUP) Slog.v(
             TAG, "Removing activity from " + reason + ": token=" + r
               + ", app=" + (r.app != null ? r.app.processName : "(null)"));
@@ -3077,6 +3095,49 @@
         }
     }
 
+    void releaseMediaResources() {
+        if (isMediaPlaying() && !mHandler.hasMessages(STOP_MEDIA_PLAYING_TIMEOUT_MSG)) {
+            final ActivityRecord r = getMediaPlayer();
+            if (DEBUG_STATES) Slog.d(TAG, "releaseMediaResources activtyDisplay=" +
+                    mActivityContainer.mActivityDisplay + " mediaPlayer=" + r + " app=" + r.app +
+                    " thread=" + r.app.thread);
+            if (r != null && r.app != null && r.app.thread != null) {
+                try {
+                    r.app.thread.scheduleStopMediaPlaying(r.appToken);
+                } catch (RemoteException e) {
+                }
+                mHandler.sendEmptyMessageDelayed(STOP_MEDIA_PLAYING_TIMEOUT_MSG, 500);
+            } else {
+                Slog.e(TAG, "releaseMediaResources: activity " + r + " no longer running");
+                mediaResourcesReleased(r.appToken);
+            }
+        }
+    }
+
+    final void mediaResourcesReleased(IBinder token) {
+        mHandler.removeMessages(STOP_MEDIA_PLAYING_TIMEOUT_MSG);
+        final ActivityRecord r = getMediaPlayer();
+        if (r != null) {
+            mStackSupervisor.mStoppingActivities.add(r);
+            setMediaPlayer(null);
+        }
+        mStackSupervisor.resumeTopActivitiesLocked();
+    }
+
+    boolean isMediaPlaying() {
+        return isAttached() && mActivityContainer.mActivityDisplay.isMediaPlaying();
+    }
+
+    void setMediaPlayer(ActivityRecord r) {
+        if (isAttached()) {
+            mActivityContainer.mActivityDisplay.setMediaPlaying(r);
+        }
+    }
+
+    ActivityRecord getMediaPlayer() {
+        return isAttached() ? mActivityContainer.mActivityDisplay.mMediaPlayingActivity : null;
+    }
+
     private void removeHistoryRecordsForAppLocked(ArrayList<ActivityRecord> list,
             ProcessRecord app, String listName) {
         int i = list.size();
@@ -3448,7 +3509,7 @@
             if (r.app == null || r.app.thread == null) {
                 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
                         "Config is destroying non-running " + r);
-                destroyActivityLocked(r, true, false, "config");
+                destroyActivityLocked(r, true, "config");
             } else if (r.state == ActivityState.PAUSING) {
                 // A little annoying: we are waiting for this activity to
                 // finish pausing.  Let's not do anything now, but just
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index c4423de..65afd71 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -49,7 +49,6 @@
 import android.app.IActivityManager.WaitResult;
 import android.app.ResultInfo;
 import android.app.StatusBarManager;
-import android.app.admin.DevicePolicyManager;
 import android.app.admin.IDevicePolicyManager;
 import android.content.ComponentName;
 import android.content.Context;
@@ -116,6 +115,7 @@
     static final boolean DEBUG_APP = DEBUG || false;
     static final boolean DEBUG_CONTAINERS = DEBUG || false;
     static final boolean DEBUG_IDLE = DEBUG || false;
+    static final boolean DEBUG_MEDIA_VISIBILITY = DEBUG || false;
     static final boolean DEBUG_SAVED_STATE = DEBUG || false;
     static final boolean DEBUG_SCREENSHOTS = DEBUG || false;
     static final boolean DEBUG_STATES = DEBUG || false;
@@ -2102,7 +2102,7 @@
         // waiting for the next one to start.
         for (int i = 0; i < NF; i++) {
             r = finishes.get(i);
-            activityRemoved |= r.task.stack.destroyActivityLocked(r, true, false, "finish-idle");
+            activityRemoved |= r.task.stack.destroyActivityLocked(r, true, "finish-idle");
         }
 
         if (booting) {
@@ -2298,6 +2298,14 @@
     }
 
     IBinder getHomeActivityToken() {
+        ActivityRecord homeActivity = getHomeActivity();
+        if (homeActivity != null) {
+            return homeActivity.appToken;
+        }
+        return null;
+    }
+
+    ActivityRecord getHomeActivity() {
         final ArrayList<TaskRecord> tasks = mHomeStack.getAllTasks();
         for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
             final TaskRecord task = tasks.get(taskNdx);
@@ -2306,7 +2314,7 @@
                 for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                     final ActivityRecord r = activities.get(activityNdx);
                     if (r.isHomeActivity()) {
-                        return r.appToken;
+                        return r;
                     }
                 }
             }
@@ -2594,6 +2602,42 @@
         }
     }
 
+    boolean setMediaPlayingLocked(ActivityRecord r, boolean playing) {
+        final ActivityStack stack = r.task.stack;
+        if (stack == null) {
+            if (DEBUG_MEDIA_VISIBILITY) Slog.d(TAG, "setMediaPlaying: r=" + r + " playing=" +
+                    playing + " stack is null");
+            return false;
+        }
+        final boolean isPlaying = stack.isMediaPlaying();
+        if (DEBUG_MEDIA_VISIBILITY) Slog.d(TAG, "setMediaPlayer: r=" + r + " playing=" +
+                playing + " isPlaying=" + isPlaying);
+
+        final ActivityRecord top = topRunningActivityLocked();
+        if (top == null || top == r || (playing == isPlaying)) {
+            if (DEBUG_MEDIA_VISIBILITY) Slog.d(TAG, "setMediaPlaying: quick return");
+            stack.setMediaPlayer(playing ? r : null);
+            return true;
+        }
+
+        // A non-top activity is reporting a visibility change.
+        if (top.fullscreen || top.state != ActivityState.RESUMED || top.app == null ||
+                top.app.thread == null) {
+            // Can't carry out this request.
+            if (DEBUG_MEDIA_VISIBILITY) Slog.d(TAG, "setMediaPlaying: returning top.fullscreen=" +
+                    top.fullscreen+ " top.state=" + top.state + " top.app=" + top.app +
+                    " top.app.thread=" + top.app.thread);
+            return false;
+        }
+
+        stack.setMediaPlayer(playing ? r : null);
+        try {
+            top.app.thread.scheduleBackgroundMediaPlayingChanged(top.appToken, playing);
+        } catch (RemoteException e) {
+        }
+        return true;
+    }
+
     void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges) {
         // First the front stacks. In case any are not fullscreen and are in front of home.
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
@@ -2612,7 +2656,7 @@
             final int numStacks = stacks.size();
             for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
                 final ActivityStack stack = stacks.get(stackNdx);
-                stack.scheduleDestroyActivities(app, false, reason);
+                stack.scheduleDestroyActivities(app, reason);
             }
         }
     }
@@ -2774,7 +2818,8 @@
         boolean needSep = false;
         for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) {
             ActivityDisplay activityDisplay = mActivityDisplays.valueAt(displayNdx);
-            pw.print("Display #"); pw.println(activityDisplay.mDisplayId);
+            pw.print("Display #"); pw.print(activityDisplay.mDisplayId);
+                    pw.println(" (activities from bottom to top):");
             ArrayList<ActivityStack> stacks = activityDisplay.mStacks;
             final int numStacks = stacks.size();
             for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
@@ -3584,6 +3629,8 @@
          * stacks, bottommost behind. Accessed directly by ActivityManager package classes */
         final ArrayList<ActivityStack> mStacks = new ArrayList<ActivityStack>();
 
+        ActivityRecord mMediaPlayingActivity;
+
         ActivityDisplay() {
         }
 
@@ -3615,6 +3662,14 @@
             bounds.y = mDisplayInfo.appHeight;
         }
 
+        void setMediaPlaying(ActivityRecord r) {
+            mMediaPlayingActivity = r;
+        }
+
+        boolean isMediaPlaying() {
+            return mMediaPlayingActivity != null;
+        }
+
         @Override
         public String toString() {
             return "ActivityDisplay={" + mDisplayId + " numStacks=" + mStacks.size() + "}";
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 6b60ea4..0e6265c 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -25,6 +25,7 @@
 import java.io.PrintWriter;
 import java.lang.reflect.Array;
 import java.util.Arrays;
+import java.util.Objects;
 
 /**
  * Holds data about notifications that should not be shared with the
@@ -201,6 +202,10 @@
         return mIntercept;
     }
 
+    public boolean isCategory(String category) {
+        return Objects.equals(category, getNotification().category);
+    }
+
     /**
      * Returns the timestamp to use for time-based sorting in the ranker.
      */
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 92bec14..f74e371 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -21,6 +21,7 @@
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
@@ -34,6 +35,7 @@
 import android.os.IBinder;
 import android.provider.Settings.Global;
 import android.service.notification.ZenModeConfig;
+import android.telecomm.TelecommManager;
 import android.util.Slog;
 
 import com.android.internal.R;
@@ -72,17 +74,13 @@
     private final ZenModeConfig mDefaultConfig;
     private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
 
+    private ComponentName mDefaultPhoneApp;
     private int mZenMode;
     private ZenModeConfig mConfig;
     private AudioManager mAudioManager;
     private int mPreviousRingerMode = -1;
 
     // temporary, until we update apps to provide metadata
-    private static final Set<String> CALL_PACKAGES = new HashSet<String>(Arrays.asList(
-            "com.google.android.dialer",
-            "com.android.phone",
-            "com.android.example.notificationshowcase"
-            ));
     private static final Set<String> MESSAGE_PACKAGES = new HashSet<String>(Arrays.asList(
             "com.google.android.talk",
             "com.android.mms",
@@ -224,7 +222,7 @@
 
     public boolean allowDisable(int what, IBinder token, String pkg) {
         // TODO(cwren): delete this API before the next release. Bug:15344099
-        if (CALL_PACKAGES.contains(pkg)) {
+        if (isDefaultPhoneApp(pkg)) {
             return mZenMode == Global.ZEN_MODE_OFF || mConfig.allowCalls;
         }
         return true;
@@ -236,6 +234,7 @@
         pw.print(prefix); pw.print("mConfig="); pw.println(mConfig);
         pw.print(prefix); pw.print("mDefaultConfig="); pw.println(mDefaultConfig);
         pw.print(prefix); pw.print("mPreviousRingerMode="); pw.println(mPreviousRingerMode);
+        pw.print(prefix); pw.print("mDefaultPhoneApp="); pw.println(mDefaultPhoneApp);
     }
 
     public void readXml(XmlPullParser parser) throws XmlPullParserException, IOException {
@@ -280,7 +279,7 @@
 
     private boolean isSystem(NotificationRecord record) {
         return SYSTEM_PACKAGES.contains(record.sbn.getPackageName())
-                && Notification.CATEGORY_SYSTEM.equals(record.getNotification().category);
+                && record.isCategory(Notification.CATEGORY_SYSTEM);
     }
 
     private boolean isAlarm(NotificationRecord record) {
@@ -288,7 +287,19 @@
     }
 
     private boolean isCall(NotificationRecord record) {
-        return CALL_PACKAGES.contains(record.sbn.getPackageName());
+        return isDefaultPhoneApp(record.sbn.getPackageName())
+                || record.isCategory(Notification.CATEGORY_CALL);
+    }
+
+    private boolean isDefaultPhoneApp(String pkg) {
+        if (mDefaultPhoneApp == null) {
+            final TelecommManager telecomm =
+                    (TelecommManager) mContext.getSystemService(Context.TELECOMM_SERVICE);
+            mDefaultPhoneApp = telecomm != null ? telecomm.getDefaultPhoneApp() : null;
+            Slog.d(TAG, "Default phone app: " + mDefaultPhoneApp);
+        }
+        return pkg != null && mDefaultPhoneApp != null
+                && pkg.equals(mDefaultPhoneApp.getPackageName());
     }
 
     private boolean isMessage(NotificationRecord record) {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 194e85d..64288a5 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -394,16 +394,21 @@
     @Override
     public void setUserIcon(int userId, Bitmap bitmap) {
         checkManageUsersPermission("update users");
-        synchronized (mPackagesLock) {
-            UserInfo info = mUsers.get(userId);
-            if (info == null || info.partial) {
-                Slog.w(LOG_TAG, "setUserIcon: unknown user #" + userId);
-                return;
+        long ident = Binder.clearCallingIdentity();
+        try {
+            synchronized (mPackagesLock) {
+                UserInfo info = mUsers.get(userId);
+                if (info == null || info.partial) {
+                    Slog.w(LOG_TAG, "setUserIcon: unknown user #" + userId);
+                    return;
+                }
+                writeBitmapLocked(info, bitmap);
+                writeUserLocked(info);
             }
-            writeBitmapLocked(info, bitmap);
-            writeUserLocked(info);
+            sendUserInfoChangedBroadcast(userId);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
         }
-        sendUserInfoChangedBroadcast(userId);
     }
 
     private void sendUserInfoChangedBroadcast(int userId) {
diff --git a/telecomm/java/android/telecomm/ConnectionRequest.java b/telecomm/java/android/telecomm/ConnectionRequest.java
index ed61622..939ac8d 100644
--- a/telecomm/java/android/telecomm/ConnectionRequest.java
+++ b/telecomm/java/android/telecomm/ConnectionRequest.java
@@ -35,10 +35,6 @@
     private final Bundle mExtras;
     private final PhoneAccount mAccount;
 
-    public ConnectionRequest(Uri handle, Bundle extras) {
-        this(null, handle, extras);
-    }
-
     public ConnectionRequest(String callId, Uri handle, Bundle extras) {
         this(null, callId, handle, extras);
     }
diff --git a/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl b/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl
index 61c2b8a..50bec33 100644
--- a/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl
+++ b/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl
@@ -18,6 +18,7 @@
 
 import android.net.wifi.ScanResult;
 import android.net.wifi.passpoint.WifiPasspointPolicy;
+import android.net.wifi.passpoint.WifiPasspointCredential;
 import android.os.Messenger;
 
 /**
@@ -28,7 +29,17 @@
 interface IWifiPasspointManager
 {
     Messenger getMessenger();
+
     int getPasspointState();
+
     List<WifiPasspointPolicy> requestCredentialMatch(in List<ScanResult> requested);
+
+    List<WifiPasspointCredential> getCredentials();
+
+    boolean addCredential(in WifiPasspointCredential cred);
+
+    boolean updateCredential(in WifiPasspointCredential cred);
+
+    boolean removeCredential(in WifiPasspointCredential cred);
 }
 
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java
index 33ccad5..0a7230f 100644
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java
@@ -333,7 +333,7 @@
      * Set the fully qualified domain name (FQDN) of this Passpoint credential.
      * @param fqdn FQDN
      */
-    public void setFqdn(String fqdn) {
+    public void setHomeFqdn(String fqdn) {
         mHomeSpFqdn = fqdn;
     }
 
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
index ddca85e..b9b17eb 100644
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
@@ -496,7 +496,11 @@
      * @return The list of credentials
      */
     public List<WifiPasspointCredential> getCredentials() {
-        return null;
+        try {
+            return mService.getCredentials();
+        } catch (RemoteException e) {
+            return null;
+        }
     }
 
     /**
@@ -506,7 +510,11 @@
      * @return {@code true} if the operation succeeds, {@code false} otherwise
      */
     public boolean addCredential(WifiPasspointCredential cred) {
-        return true;
+        try {
+            return mService.addCredential(cred);
+        } catch (RemoteException e) {
+            return false;
+        }
     }
 
     /**
@@ -517,7 +525,11 @@
      * @return {@code true} if the operation succeeds, {@code false} otherwise
      */
     public boolean updateCredential(WifiPasspointCredential cred) {
-        return true;
+        try {
+            return mService.updateCredential(cred);
+        } catch (RemoteException e) {
+            return false;
+        }
     }
 
     /**
@@ -528,7 +540,11 @@
      * @return {@code true} if the operation succeeds, {@code false} otherwise
      */
     public boolean removeCredential(WifiPasspointCredential cred) {
-        return true;
+        try {
+            return mService.removeCredential(cred);
+        } catch (RemoteException e) {
+            return false;
+        }
     }
 
     public void startOsu(Channel c, WifiPasspointOsuProvider osu, OsuRemListener listener) {