Merge "Correctly parse previous PMBA state during backup" into lmp-mr1-dev
diff --git a/Android.mk b/Android.mk
index ba45e6f..1416472 100644
--- a/Android.mk
+++ b/Android.mk
@@ -100,6 +100,7 @@
 	core/java/android/bluetooth/IBluetoothA2dpSink.aidl \
 	core/java/android/bluetooth/IBluetoothAvrcpController.aidl \
 	core/java/android/bluetooth/IBluetoothCallback.aidl \
+	core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl \
 	core/java/android/bluetooth/IBluetoothHeadset.aidl \
 	core/java/android/bluetooth/IBluetoothHeadsetPhone.aidl \
 	core/java/android/bluetooth/IBluetoothHealth.aidl \
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 4753099..ead89b3 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -504,6 +504,22 @@
         }
         return false;
     }
+    /**
+     * Return true if the given administrator component is currently being removed
+     * for the user.
+     * @hide
+     */
+    public boolean isRemovingAdmin(ComponentName who, int userId) {
+        if (mService != null) {
+            try {
+                return mService.isRemovingAdmin(who, userId);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return false;
+    }
+
 
     /**
      * Return a list of all currently active device administrator's component
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index d144ae8..0ca60c0 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -196,4 +196,6 @@
 
     void setAutoTimeRequired(in ComponentName who, int userHandle, boolean required);
     boolean getAutoTimeRequired();
+
+    boolean isRemovingAdmin(in ComponentName adminReceiver, int userHandle);
 }
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 353f0fb..546a50e 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -20,9 +20,10 @@
 import android.annotation.SdkConstant.SdkConstantType;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
+import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
 import android.os.RemoteException;
 import android.util.Log;
 
@@ -221,11 +222,14 @@
      */
     public static final int STATE_AUDIO_CONNECTED = 12;
 
+    private static final int MESSAGE_HEADSET_SERVICE_CONNECTED = 100;
+    private static final int MESSAGE_HEADSET_SERVICE_DISCONNECTED = 101;
 
     private Context mContext;
     private ServiceListener mServiceListener;
     private IBluetoothHeadset mService;
     private BluetoothAdapter mAdapter;
+    private boolean mIsClosed;
 
     final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
             new IBluetoothStateChangeCallback.Stub() {
@@ -233,14 +237,7 @@
                     if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
                     if (!up) {
                         if (VDBG) Log.d(TAG,"Unbinding service...");
-                        synchronized (mConnection) {
-                            try {
-                                mService = null;
-                                mContext.unbindService(mConnection);
-                            } catch (Exception re) {
-                                Log.e(TAG,"",re);
-                            }
-                        }
+                        doUnbind();
                     } else {
                         synchronized (mConnection) {
                             try {
@@ -263,6 +260,7 @@
         mContext = context;
         mServiceListener = l;
         mAdapter = BluetoothAdapter.getDefaultAdapter();
+        mIsClosed = false;
 
         IBluetoothManager mgr = mAdapter.getBluetoothManager();
         if (mgr != null) {
@@ -277,15 +275,26 @@
     }
 
     boolean doBind() {
-        Intent intent = new Intent(IBluetoothHeadset.class.getName());
-        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
-        intent.setComponent(comp);
-        if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
-                android.os.Process.myUserHandle())) {
-            Log.e(TAG, "Could not bind to Bluetooth Headset Service with " + intent);
-            return false;
+        try {
+            return mAdapter.getBluetoothManager().bindBluetoothProfileService(
+                    BluetoothProfile.HEADSET, mConnection);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Unable to bind HeadsetService", e);
         }
-        return true;
+        return false;
+    }
+
+    void doUnbind() {
+        synchronized (mConnection) {
+            if (mService != null) {
+                try {
+                    mAdapter.getBluetoothManager().unbindBluetoothProfileService(
+                            BluetoothProfile.HEADSET, mConnection);
+                } catch (RemoteException e) {
+                    Log.e(TAG,"Unable to unbind HeadsetService", e);
+                }
+            }
+        }
     }
 
     /**
@@ -305,18 +314,8 @@
                 Log.e(TAG,"",e);
             }
         }
-
-        synchronized (mConnection) {
-            if (mService != null) {
-                try {
-                    mService = null;
-                    mContext.unbindService(mConnection);
-                } catch (Exception re) {
-                    Log.e(TAG,"",re);
-                }
-            }
-        }
-        mServiceListener = null;
+        mIsClosed = true;
+        doUnbind();
     }
 
     /**
@@ -930,21 +929,21 @@
         return false;
     }
 
-    private final ServiceConnection mConnection = new ServiceConnection() {
+    private final IBluetoothProfileServiceConnection mConnection
+            = new IBluetoothProfileServiceConnection.Stub()  {
+        @Override
         public void onServiceConnected(ComponentName className, IBinder service) {
             if (DBG) Log.d(TAG, "Proxy object connected");
             mService = IBluetoothHeadset.Stub.asInterface(service);
-
-            if (mServiceListener != null) {
-                mServiceListener.onServiceConnected(BluetoothProfile.HEADSET, BluetoothHeadset.this);
-            }
+            mHandler.sendMessage(mHandler.obtainMessage(
+                    MESSAGE_HEADSET_SERVICE_CONNECTED));
         }
+        @Override
         public void onServiceDisconnected(ComponentName className) {
             if (DBG) Log.d(TAG, "Proxy object disconnected");
             mService = null;
-            if (mServiceListener != null) {
-                mServiceListener.onServiceDisconnected(BluetoothProfile.HEADSET);
-            }
+            mHandler.sendMessage(mHandler.obtainMessage(
+                    MESSAGE_HEADSET_SERVICE_DISCONNECTED));
         }
     };
 
@@ -968,4 +967,28 @@
     private static void log(String msg) {
         Log.d(TAG, msg);
     }
+
+    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MESSAGE_HEADSET_SERVICE_CONNECTED: {
+                    if (mServiceListener != null) {
+                        mServiceListener.onServiceConnected(BluetoothProfile.HEADSET,
+                                BluetoothHeadset.this);
+                    }
+                    break;
+                }
+                case MESSAGE_HEADSET_SERVICE_DISCONNECTED: {
+                    if (mServiceListener != null) {
+                        mServiceListener.onServiceDisconnected(BluetoothProfile.HEADSET);
+                    }
+                    if (mIsClosed){
+                        mServiceListener = null;
+                    }
+                    break;
+                }
+            }
+        }
+    };
 }
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index 1e22eb3..194a53e 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -66,6 +66,8 @@
             ParcelUuid.fromString("00001116-0000-1000-8000-00805F9B34FB");
     public static final ParcelUuid BNEP =
             ParcelUuid.fromString("0000000f-0000-1000-8000-00805F9B34FB");
+    public static final ParcelUuid PBAP_PCE =
+            ParcelUuid.fromString("0000112e-0000-1000-8000-00805F9B34FB");
     public static final ParcelUuid PBAP_PSE =
             ParcelUuid.fromString("0000112f-0000-1000-8000-00805F9B34FB");
     public static final ParcelUuid MAP =
diff --git a/core/java/android/bluetooth/IBluetoothManager.aidl b/core/java/android/bluetooth/IBluetoothManager.aidl
index 493d2f8..7411d3f 100644
--- a/core/java/android/bluetooth/IBluetoothManager.aidl
+++ b/core/java/android/bluetooth/IBluetoothManager.aidl
@@ -19,6 +19,7 @@
 import android.bluetooth.IBluetooth;
 import android.bluetooth.IBluetoothGatt;
 import android.bluetooth.IBluetoothManagerCallback;
+import android.bluetooth.IBluetoothProfileServiceConnection;
 import android.bluetooth.IBluetoothStateChangeCallback;
 
 /**
@@ -38,6 +39,9 @@
     boolean disable(boolean persist);
     IBluetoothGatt getBluetoothGatt();
 
+    boolean bindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy);
+    void unbindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy);
+
     String getAddress();
     String getName();
 }
diff --git a/core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl b/core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl
new file mode 100755
index 0000000..96c59e2
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.content.ComponentName;
+import android.os.IBinder;
+
+/**
+ * Callback for bluetooth profile connections.
+ *
+ * {@hide}
+ */
+interface IBluetoothProfileServiceConnection {
+    void onServiceConnected(in ComponentName comp, in IBinder service);
+    void onServiceDisconnected(in ComponentName comp);
+}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 4fe418a..4215f20 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -100,7 +100,7 @@
 
     /**
      * Identical to {@link #CONNECTIVITY_ACTION} broadcast, but sent without any
-     * historic {@link Settings.Global#CONNECTIVITY_CHANGE_DELAY}.
+     * applicable {@link Settings.Global#CONNECTIVITY_CHANGE_DELAY}.
      *
      * @hide
      */
@@ -428,6 +428,18 @@
     public static final int DEFAULT_NETWORK_PREFERENCE = TYPE_WIFI;
 
     /**
+     * Default value for {@link Settings.Global#CONNECTIVITY_CHANGE_DELAY} in
+     * milliseconds.  This was introduced because IPv6 routes seem to take a
+     * moment to settle - trying network activity before the routes are adjusted
+     * can lead to packets using the wrong interface or having the wrong IP address.
+     * This delay is a bit crude, but in the future hopefully we will have kernel
+     * notifications letting us know when it's safe to use the new network.
+     *
+     * @hide
+     */
+    public static final int CONNECTIVITY_CHANGE_DELAY_DEFAULT = 3000;
+
+    /**
      * @hide
      */
     public final static int REQUEST_ID_UNSET = 0;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 3bc74ae..0c036d51 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6118,7 +6118,7 @@
 
         /**
          * The number of milliseconds to delay before sending out
-         * {@link ConnectivityManager#CONNECTIVITY_ACTION} broadcasts. Ignored.
+         * {@link ConnectivityManager#CONNECTIVITY_ACTION} broadcasts.
          *
          * @hide
          */
diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
index c1341e1..14be269 100644
--- a/core/java/android/text/util/Linkify.java
+++ b/core/java/android/text/util/Linkify.java
@@ -402,7 +402,7 @@
         }
 
         boolean hasPrefix = false;
-        
+
         for (int i = 0; i < prefixes.length; i++) {
             if (url.regionMatches(true, 0, prefixes[i], 0,
                                   prefixes[i].length())) {
@@ -450,7 +450,7 @@
     private static final void gatherTelLinks(ArrayList<LinkSpec> links, Spannable s) {
         PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
         Iterable<PhoneNumberMatch> matches = phoneUtil.findNumbers(s.toString(),
-                Locale.getDefault().getCountry(), Leniency.POSSIBLE, Long.MAX_VALUE);
+                Locale.getDefault().getCountry(), Leniency.VALID, Long.MAX_VALUE);
         for (PhoneNumberMatch match : matches) {
             LinkSpec spec = new LinkSpec();
             spec.url = "tel:" + PhoneNumberUtils.normalizeNumber(match.rawString());
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index f4f047e..094a8a1 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1102,6 +1102,13 @@
         public static final int PRIVATE_FLAG_KEYGUARD = 0x00000400;
 
         /**
+         * Flag that prevents the wallpaper behind the current window from receiving touch events.
+         *
+         * {@hide}
+         */
+        public static final int PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS = 0x00000800;
+
+        /**
          * Control flags that are private to the platform.
          * @hide
          */
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 3dd9770..3fdaaa6 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2914,7 +2914,8 @@
          Any service that filters for this intent must be a carrier privileged app. -->
     <permission android:name="android.permission.BIND_CARRIER_MESSAGING_SERVICE"
         android:label="@string/permlab_bindCarrierMessagingService"
-        android:description="@string/permdesc_bindCarrierMessagingService" />
+        android:description="@string/permdesc_bindCarrierMessagingService"
+        android:protectionLevel="signature|system" />
 
     <!-- The system process is explicitly the only one allowed to launch the
          confirmation UI for full backup/restore -->
diff --git a/data/fonts/fallback_fonts.xml b/data/fonts/fallback_fonts.xml
index 0244891..f94fe66 100644
--- a/data/fonts/fallback_fonts.xml
+++ b/data/fonts/fallback_fonts.xml
@@ -229,6 +229,12 @@
     </family>
     <family>
         <fileset>
+            <file>NotoSansCham-Regular.ttf</file>
+            <file>NotoSansCham-Bold.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
             <file>NotoSansBalinese-Regular.ttf</file>
         </fileset>
     </family>
@@ -259,6 +265,16 @@
     </family>
     <family>
         <fileset>
+            <file>NotoSansCoptic-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>NotoSansGlagolitic-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
             <file>NotoSansHanunoo-Regular.ttf</file>
         </fileset>
     </family>
@@ -269,6 +285,11 @@
     </family>
     <family>
         <fileset>
+            <file>NotoSansKayahLi-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
             <file>NotoSansLepcha-Regular.ttf</file>
         </fileset>
     </family>
@@ -314,6 +335,26 @@
     </family>
     <family>
         <fileset>
+            <file>NotoSansTaiLe-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>NotoSansTaiTham-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>NotoSansTaiViet-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>NotoSansTifinagh-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
             <file>NotoSansYi-Regular.ttf</file>
         </fileset>
     </family>
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index a62e972..02bf877 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -224,6 +224,10 @@
         <font weight="700" style="normal">NotoSansThaana-Bold.ttf</font>
     </family>
     <family>
+        <font weight="400" style="normal">NotoSansCham-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansCham-Bold.ttf</font>
+    </family>
+    <family>
         <font weight="400" style="normal">NotoSansBalinese-Regular.ttf</font>
     </family>
     <family>
@@ -242,12 +246,21 @@
         <font weight="400" style="normal">NotoSansCherokee-Regular.ttf</font>
     </family>
     <family>
+        <font weight="400" style="normal">NotoSansCoptic-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansGlagolitic-Regular.ttf</font>
+    </family>
+    <family>
         <font weight="400" style="normal">NotoSansHanunoo-Regular.ttf</font>
     </family>
     <family>
         <font weight="400" style="normal">NotoSansJavanese-Regular.ttf</font>
     </family>
     <family>
+        <font weight="400" style="normal">NotoSansKayahLi-Regular.ttf</font>
+    </family>
+    <family>
         <font weight="400" style="normal">NotoSansLepcha-Regular.ttf</font>
     </family>
     <family>
@@ -275,6 +288,18 @@
         <font weight="400" style="normal">NotoSansTagbanwa-Regular.ttf</font>
     </family>
     <family>
+        <font weight="400" style="normal">NotoSansTaiLe-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansTaiTham-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansTaiViet-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansTifinagh-Regular.ttf</font>
+    </family>
+    <family>
         <font weight="400" style="normal">NotoSansYi-Regular.ttf</font>
     </family>
     <family>
diff --git a/docs/html/samples/images/ActivitySceneTransitionBasic.png b/docs/html/samples/images/ActivitySceneTransitionBasic.png
index ea58641..a126cf8 100644
--- a/docs/html/samples/images/ActivitySceneTransitionBasic.png
+++ b/docs/html/samples/images/ActivitySceneTransitionBasic.png
Binary files differ
diff --git a/docs/html/samples/images/ActivitySceneTransitionBasic@2x.png b/docs/html/samples/images/ActivitySceneTransitionBasic@2x.png
index cd28ade..44378bb 100644
--- a/docs/html/samples/images/ActivitySceneTransitionBasic@2x.png
+++ b/docs/html/samples/images/ActivitySceneTransitionBasic@2x.png
Binary files differ
diff --git a/docs/html/samples/images/BasicManagedProfile.png b/docs/html/samples/images/BasicManagedProfile.png
index 7354842..5749db3 100644
--- a/docs/html/samples/images/BasicManagedProfile.png
+++ b/docs/html/samples/images/BasicManagedProfile.png
Binary files differ
diff --git a/docs/html/samples/images/BasicManagedProfile@2x.png b/docs/html/samples/images/BasicManagedProfile@2x.png
index c232809..860c954 100644
--- a/docs/html/samples/images/BasicManagedProfile@2x.png
+++ b/docs/html/samples/images/BasicManagedProfile@2x.png
Binary files differ
diff --git a/docs/html/samples/images/JobSchedulerSample.png b/docs/html/samples/images/JobSchedulerSample.png
index ee57bdb..a043f3e 100644
--- a/docs/html/samples/images/JobSchedulerSample.png
+++ b/docs/html/samples/images/JobSchedulerSample.png
Binary files differ
diff --git a/docs/html/samples/images/JobSchedulerSample@2x.png b/docs/html/samples/images/JobSchedulerSample@2x.png
index 3d543db..1ed2cf9 100644
--- a/docs/html/samples/images/JobSchedulerSample@2x.png
+++ b/docs/html/samples/images/JobSchedulerSample@2x.png
Binary files differ
diff --git a/docs/html/training/wearables/ui/exit.jd b/docs/html/training/wearables/ui/exit.jd
index 6b205a57..84e1e45 100644
--- a/docs/html/training/wearables/ui/exit.jd
+++ b/docs/html/training/wearables/ui/exit.jd
@@ -67,7 +67,7 @@
         android:id="@+id/dismiss_overlay"
         android:layout_height="match_parent"
         android:layout_width="match_parent"/>
-&lt;/FrameLayout>
+&lt;FrameLayout>
 </pre>
 
 <p>In your activity, obtain the <code>DismissOverlayView</code> element and set some introductory
@@ -100,8 +100,8 @@
 
     // Capture long presses
     &#64;Override
-    public boolean dispatchTouchEvent(MotionEvent e) {
-        return mDetector.onTouchEvent(e) || super.dispatchTouchEvent(e);
+    public boolean onTouchEvent(MotionEvent ev) {
+        return mDetector.onTouchEvent(ev) || super.onTouchEvent(ev);
     }
 }
 </pre>
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index e9c8c2a..2a17a60 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -146,7 +146,8 @@
     @Override
     public Drawable mutate() {
         if (!mMutated && super.mutate() == this) {
-            mAnimatedVectorState.mVectorDrawable.mutate();
+            mAnimatedVectorState = new AnimatedVectorDrawableState(
+                    mAnimatedVectorState, mCallback, null);
             mMutated = true;
         }
         return this;
diff --git a/media/java/android/media/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java
index da6f3fc..94c9690 100644
--- a/media/java/android/media/tv/ITvInputSessionWrapper.java
+++ b/media/java/android/media/tv/ITvInputSessionWrapper.java
@@ -42,7 +42,7 @@
     private static final String TAG = "TvInputSessionWrapper";
 
     private static final int MESSAGE_HANDLING_DURATION_THRESHOLD_MILLIS = 50;
-    private static final int MESSAGE_TUNE_DURATION_THRESHOLD_MILLIS = 1000;
+    private static final int MESSAGE_TUNE_DURATION_THRESHOLD_MILLIS = 2000;
 
     private static final int DO_RELEASE = 1;
     private static final int DO_SET_MAIN = 2;
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index 779d486..26aedbd 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -323,24 +323,22 @@
      * <p>
      * This should be called as soon as possible during the service's startup.
      * It may only be called once.
-     *
-     * @return The media session token, must not be null.
      */
     public void setSessionToken(final MediaSession.Token token) {
         if (token == null) {
             throw new IllegalArgumentException("Session token may not be null.");
         }
+        if (mSession != null) {
+            throw new IllegalStateException("The session token has already been set.");
+        }
+        mSession = token;
         mHandler.post(new Runnable() {
             @Override
             public void run() {
-                if (mSession != null) {
-                    throw new IllegalStateException("The session token has already been set.");
-                }
-                mSession = token;
                 for (IBinder key : mConnections.keySet()) {
                     ConnectionRecord connection = mConnections.get(key);
                     try {
-                        connection.callbacks.onConnect(connection.root.getRootId(), mSession,
+                        connection.callbacks.onConnect(connection.root.getRootId(), token,
                                 connection.root.getExtras());
                     } catch (RemoteException e) {
                         Log.w(TAG, "Connection for " + connection.pkg + " is no longer valid.");
diff --git a/packages/SystemUI/res/layout/lland.xml b/packages/SystemUI/res/layout/lland.xml
index 053225d..71a16c9 100644
--- a/packages/SystemUI/res/layout/lland.xml
+++ b/packages/SystemUI/res/layout/lland.xml
@@ -31,10 +31,10 @@
             android:textSize="32sp"
             android:textColor="#FFAAAAAA"
             android:layout_marginTop="32dp"
-            android:layout_marginLeft="16dp"
-            android:layout_gravity="top|left"
-            android:paddingLeft="16dp"
-            android:paddingRight="16dp"
+            android:layout_marginStart="16dp"
+            android:layout_gravity="top|start"
+            android:paddingStart="16dp"
+            android:paddingEnd="16dp"
             android:paddingTop="8dp"
             android:paddingBottom="8dp"
             android:background="@drawable/scorecard"
diff --git a/packages/SystemUI/src/com/android/systemui/egg/LLand.java b/packages/SystemUI/src/com/android/systemui/egg/LLand.java
index 5de09a3..fa257b1 100644
--- a/packages/SystemUI/src/com/android/systemui/egg/LLand.java
+++ b/packages/SystemUI/src/com/android/systemui/egg/LLand.java
@@ -178,6 +178,9 @@
         setFocusable(true);
         PARAMS = new Params(getResources());
         mTimeOfDay = irand(0, SKIES.length);
+
+        // we assume everything will be laid out left|top
+        setLayoutDirection(LAYOUT_DIRECTION_LTR);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 206fc43..7ac0daf 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -72,6 +72,7 @@
 import com.android.systemui.statusbar.phone.StatusBarWindowManager;
 
 import java.util.ArrayList;
+import java.util.List;
 
 import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
 
@@ -1217,7 +1218,12 @@
         synchronized (this) {
             if (mBootCompleted) {
                 final UserHandle currentUser = new UserHandle(mLockPatternUtils.getCurrentUser());
-                mContext.sendBroadcastAsUser(USER_PRESENT_INTENT, currentUser);
+                final UserManager um = (UserManager) mContext.getSystemService(
+                        Context.USER_SERVICE);
+                List <UserInfo> userHandles = um.getProfiles(currentUser.getIdentifier());
+                for (UserInfo ui : userHandles) {
+                    mContext.sendBroadcastAsUser(USER_PRESENT_INTENT, ui.getUserHandle());
+                }
             } else {
                 mBootSendUserPresent = true;
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 57ac4b0..2b6ac26 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -683,15 +683,12 @@
             Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d",
                     n, thisUserId, notificationUserId));
         }
-        synchronized (mCurrentProfiles) {
-            return notificationUserId == UserHandle.USER_ALL
-                    || mCurrentProfiles.get(notificationUserId) != null;
-        }
+        return isCurrentProfile(notificationUserId);
     }
 
     protected boolean isCurrentProfile(int userId) {
         synchronized (mCurrentProfiles) {
-            return mCurrentProfiles.get(userId) != null;
+            return userId == UserHandle.USER_ALL || mCurrentProfiles.get(userId) != null;
         }
     }
 
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 7b3e137..47bf188 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -61,6 +61,7 @@
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.Locale;
+import java.util.Random;
 import java.util.TimeZone;
 
 import static android.app.AlarmManager.RTC_WAKEUP;
@@ -114,8 +115,12 @@
     final Object mLock = new Object();
 
     long mNativeData;
-    private long mNextWakeup;
+
+    private final Random mFuzzer = new Random();
+    private long mNextWakeupBatchStart;     // nominal start of next wakeup's delivery window
+    private long mNextWakeup;               // actual scheduled next wakeup within that window
     private long mNextNonWakeup;
+
     int mBroadcastRefCount = 0;
     PowerManager.WakeLock mWakeLock;
     boolean mLastWakeLockUnimportantForLogging;
@@ -367,14 +372,27 @@
 
     static class BatchTimeOrder implements Comparator<Batch> {
         public int compare(Batch b1, Batch b2) {
-            long when1 = b1.start;
-            long when2 = b2.start;
-            if (when1 - when2 > 0) {
+            final long start1 = b1.start;
+            final long start2 = b2.start;
+            if (start1 > start2) {
                 return 1;
             }
-            if (when1 - when2 < 0) {
+            if (start1 < start2) {
                 return -1;
             }
+
+            // Identical trigger times.  As a secondary ordering, require that
+            // the batch with the shorter allowable delivery window sorts first.
+            final long interval1 = b1.end - b1.start;
+            final long interval2 = b2.end - b2.start;
+            if (interval1 > interval2) {
+                return 1;
+            }
+            if (interval2 < interval1) {
+                return -1;
+            }
+
+            // equal start + delivery window => they're identical
             return 0;
         }
     }
@@ -597,7 +615,7 @@
     @Override
     public void onStart() {
         mNativeData = init();
-        mNextWakeup = mNextNonWakeup = 0;
+        mNextWakeup = mNextWakeupBatchStart = mNextNonWakeup = 0;
 
         // We have to set current TimeZone info to kernel
         // because kernel doesn't keep this after reboot
@@ -805,8 +823,9 @@
                         "AlarmManager.set");
             }
 
+            // Exact alarms are standalone; inexact get batched together
             setImpl(type, triggerAtTime, windowLength, interval, operation,
-                    false, workSource, alarmClock);
+                    windowLength == AlarmManager.WINDOW_EXACT, workSource, alarmClock);
         }
 
         @Override
@@ -877,7 +896,7 @@
 
             pw.print("nowRTC="); pw.print(nowRTC);
             pw.print("="); pw.print(sdf.format(new Date(nowRTC)));
-            pw.print(" nowELAPSED="); TimeUtils.formatDuration(nowELAPSED, pw);
+            pw.print(" nowELAPSED="); pw.print(nowELAPSED);
             pw.println();
             if (!mInteractive) {
                 pw.print("Time since non-interactive: ");
@@ -1083,17 +1102,6 @@
         return true;
     }
 
-    private Batch findFirstWakeupBatchLocked() {
-        final int N = mAlarmBatches.size();
-        for (int i = 0; i < N; i++) {
-            Batch b = mAlarmBatches.get(i);
-            if (b.hasWakeups()) {
-                return b;
-            }
-        }
-        return null;
-    }
-
     private AlarmManager.AlarmClockInfo getNextAlarmClockImpl(int userId) {
         synchronized (mLock) {
             return mNextAlarmClockForUser.get(userId);
@@ -1228,16 +1236,48 @@
         // prior to that which contains no wakeups, we schedule that as well.
         long nextNonWakeup = 0;
         if (mAlarmBatches.size() > 0) {
-            final Batch firstWakeup = findFirstWakeupBatchLocked();
+            // Find the first wakeup alarm and note the following batch as well.  We'll be
+            // choosing a fuzzed delivery time within the first's allowable interval but
+            // ensuring that it does not encroach on the second's start time, to minimize
+            // alarm reordering.
+            Batch firstWakeup = null, nextAfterWakeup = null;
+            final int N = mAlarmBatches.size();
+            for (int i = 0; i < N; i++) {
+                Batch b = mAlarmBatches.get(i);
+                if (b.hasWakeups()) {
+                    firstWakeup = b;
+                    if (i < N-1) {
+                        nextAfterWakeup = mAlarmBatches.get(i+1);
+                    }
+                    break;
+                }
+            }
+
+            // There's a subtlety here: we depend on the invariant that if two batches
+            // exist with the same start time, the one with the shorter delivery window
+            // is sorted before the other.  This guarantees us that we need only look
+            // at the first [relevant] batch in the queue in order to schedule an alarm
+            // appropriately.
             final Batch firstBatch = mAlarmBatches.get(0);
-            if (firstWakeup != null && mNextWakeup != firstWakeup.start) {
-                mNextWakeup = firstWakeup.start;
-                setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start);
+            if (firstWakeup != null && mNextWakeupBatchStart != firstWakeup.start) {
+                mNextWakeupBatchStart = mNextWakeup = firstWakeup.start;
+                final long windowEnd = (nextAfterWakeup == null)
+                        ? firstWakeup.end
+                        : Math.min(firstWakeup.end, nextAfterWakeup.start);
+                final long interval = windowEnd - firstWakeup.start;
+                // if the interval is over maxint we're into crazy land anyway, but
+                // just in case we check and don't fuzz if the conversion to int for
+                // random-number purposes would blow up
+                if (interval > 0 && interval < Integer.MAX_VALUE) {
+                    mNextWakeup += mFuzzer.nextInt((int) interval);
+                }
+                setLocked(ELAPSED_REALTIME_WAKEUP, mNextWakeup);
             }
             if (firstBatch != firstWakeup) {
                 nextNonWakeup = firstBatch.start;
             }
         }
+
         if (mPendingNonWakeupAlarms.size() > 0) {
             if (nextNonWakeup == 0 || mNextNonWakeupDeliveryTime < nextNonWakeup) {
                 nextNonWakeup = mNextNonWakeupDeliveryTime;
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index ebdd386..3117a17 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -18,11 +18,14 @@
 
 import android.app.ActivityManager;
 import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothProfile;
 import android.bluetooth.IBluetooth;
 import android.bluetooth.IBluetoothGatt;
 import android.bluetooth.IBluetoothCallback;
+import android.bluetooth.IBluetoothHeadset;
 import android.bluetooth.IBluetoothManager;
 import android.bluetooth.IBluetoothManagerCallback;
+import android.bluetooth.IBluetoothProfileServiceConnection;
 import android.bluetooth.IBluetoothStateChangeCallback;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -32,6 +35,7 @@
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
@@ -42,12 +46,18 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.Settings;
 import android.util.Log;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
+import java.util.HashMap;
+import java.util.Map;
+import java.util.List;
+import java.util.Vector;
+
 class BluetoothManagerService extends IBluetoothManager.Stub {
     private static final String TAG = "BluetoothManagerService";
     private static final boolean DBG = true;
@@ -67,6 +77,8 @@
     private static final int ERROR_RESTART_TIME_MS = 3000;
     //Maximum msec to delay MESSAGE_USER_SWITCHED
     private static final int USER_SWITCHED_TIME_MS = 200;
+    // Delay for the addProxy function in msec
+    private static final int ADD_PROXY_DELAY_MS = 100;
 
     private static final int MESSAGE_ENABLE = 1;
     private static final int MESSAGE_DISABLE = 2;
@@ -83,6 +95,8 @@
     private static final int MESSAGE_GET_NAME_AND_ADDRESS=200;
     private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201;
     private static final int MESSAGE_USER_SWITCHED = 300;
+    private static final int MESSAGE_ADD_PROXY_DELAYED = 400;
+    private static final int MESSAGE_BIND_PROFILE_SERVICE = 401;
     private static final int MAX_SAVE_RETRIES=3;
     private static final int MAX_ERROR_RESTART_RETRIES=6;
 
@@ -127,6 +141,11 @@
     private int mErrorRecoveryRetryCounter;
     private final int mSystemUiUid;
 
+    // Save a ProfileServiceConnections object for each of the bound
+    // bluetooth profile services
+    private final Map <Integer, ProfileServiceConnections> mProfileServices =
+            new HashMap <Integer, ProfileServiceConnections>();
+
     private void registerForAirplaneMode(IntentFilter filter) {
         final ContentResolver resolver = mContext.getContentResolver();
         final String airplaneModeRadios = Settings.Global.getString(resolver,
@@ -499,6 +518,187 @@
         return mBluetoothGatt;
     }
 
+    @Override
+    public boolean bindBluetoothProfileService(int bluetoothProfile,
+            IBluetoothProfileServiceConnection proxy) {
+        if (!mEnable) {
+            if (DBG) {
+                Log.d(TAG, "Trying to bind to profile: " + bluetoothProfile +
+                        ", while Bluetooth was disabled");
+            }
+            return false;
+        }
+        synchronized (mProfileServices) {
+            ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile));
+            if (psc == null) {
+                if (DBG) {
+                    Log.d(TAG, "Creating new ProfileServiceConnections object for"
+                            + " profile: " + bluetoothProfile);
+                }
+                Intent intent = null;
+                if (bluetoothProfile == BluetoothProfile.HEADSET) {
+                    intent = new Intent(IBluetoothHeadset.class.getName());
+                } else {
+                    return false;
+                }
+                psc = new ProfileServiceConnections(intent);
+                mProfileServices.put(new Integer(bluetoothProfile), psc);
+                psc.bindService();
+            }
+        }
+
+        // Introducing a delay to give the client app time to prepare
+        Message addProxyMsg = mHandler.obtainMessage(MESSAGE_ADD_PROXY_DELAYED);
+        addProxyMsg.arg1 = bluetoothProfile;
+        addProxyMsg.obj = proxy;
+        mHandler.sendMessageDelayed(addProxyMsg, ADD_PROXY_DELAY_MS);
+        return true;
+    }
+
+    @Override
+    public void unbindBluetoothProfileService(int bluetoothProfile,
+            IBluetoothProfileServiceConnection proxy) {
+        synchronized (mProfileServices) {
+            ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile));
+            if (psc == null) {
+                return;
+            }
+            psc.removeProxy(proxy);
+        }
+    }
+
+    private void unbindAllBluetoothProfileServices() {
+        synchronized (mProfileServices) {
+            for (Integer i : mProfileServices.keySet()) {
+                ProfileServiceConnections psc = mProfileServices.get(i);
+                mContext.unbindService(psc);
+                psc.removeAllProxies();
+            }
+            mProfileServices.clear();
+        }
+    }
+
+    /**
+     * This class manages the clients connected to a given ProfileService
+     * and maintains the connection with that service.
+     */
+    final private class ProfileServiceConnections implements ServiceConnection,
+            IBinder.DeathRecipient {
+        final RemoteCallbackList<IBluetoothProfileServiceConnection> mProxies =
+                new RemoteCallbackList <IBluetoothProfileServiceConnection>();
+        IBinder mService;
+        ComponentName mClassName;
+        Intent mIntent;
+
+        ProfileServiceConnections(Intent intent) {
+            mService = null;
+            mClassName = null;
+            mIntent = intent;
+        }
+
+        private void bindService() {
+            if (mIntent != null && mService == null) {
+                if (!doBind(mIntent, this, 0, UserHandle.CURRENT_OR_SELF)) {
+                    Log.w(TAG, "Unable to bind with intent: " + mIntent
+                            + ". Triggering retry.");
+                }
+                Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
+                msg.obj = this;
+                mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS);
+            }
+        }
+
+        private void addProxy(IBluetoothProfileServiceConnection proxy) {
+            mProxies.register(proxy);
+            if (mService != null) {
+                try{
+                    proxy.onServiceConnected(mClassName, mService);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Unable to connect to proxy", e);
+                }
+            } else {
+                if (!mHandler.hasMessages(MESSAGE_BIND_PROFILE_SERVICE, this)) {
+                    Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
+                    msg.obj = this;
+                    mHandler.sendMessage(msg);
+                }
+            }
+        }
+
+        private void removeProxy(IBluetoothProfileServiceConnection proxy) {
+            if (proxy != null) {
+                if (mProxies.unregister(proxy)) {
+                    try {
+                        proxy.onServiceDisconnected(mClassName);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Unable to disconnect proxy", e);
+                    }
+                }
+            } else {
+                Log.w(TAG, "Trying to remove a null proxy");
+            }
+        }
+
+        private void removeAllProxies() {
+            onServiceDisconnected(mClassName);
+            mProxies.kill();
+        }
+
+        @Override
+        public void onServiceConnected(ComponentName className, IBinder service) {
+            // remove timeout message
+            mHandler.removeMessages(MESSAGE_BIND_PROFILE_SERVICE, this);
+            mService = service;
+            mClassName = className;
+            try {
+                mService.linkToDeath(this, 0);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Unable to linkToDeath", e);
+            }
+            int n = mProxies.beginBroadcast();
+            for (int i = 0; i < n; i++) {
+                try {
+                    mProxies.getBroadcastItem(i).onServiceConnected(className, service);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Unable to connect to proxy", e);
+                }
+            }
+            mProxies.finishBroadcast();
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName className) {
+            if (mService == null) {
+                return;
+            }
+            mService.unlinkToDeath(this, 0);
+            mService = null;
+            mClassName = null;
+            int n = mProxies.beginBroadcast();
+            for (int i = 0; i < n; i++) {
+                try {
+                    mProxies.getBroadcastItem(i).onServiceDisconnected(className);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Unable to disconnect from proxy", e);
+                }
+            }
+            mProxies.finishBroadcast();
+        }
+
+        @Override
+        public void binderDied() {
+            if (DBG) {
+                Log.w(TAG, "Profile service for profile: " + mClassName
+                        + " died.");
+            }
+            onServiceDisconnected(mClassName);
+            // Trigger rebind
+            Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
+            msg.obj = this;
+            mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS);
+        }
+    }
+
     private void sendBluetoothStateCallback(boolean isUp) {
         int n = mStateChangeCallbacks.beginBroadcast();
         if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
@@ -803,6 +1003,28 @@
                     }
                     break;
                 }
+                case MESSAGE_ADD_PROXY_DELAYED:
+                {
+                    ProfileServiceConnections psc = mProfileServices.get(
+                            new Integer(msg.arg1));
+                    if (psc == null) {
+                        break;
+                    }
+                    IBluetoothProfileServiceConnection proxy =
+                            (IBluetoothProfileServiceConnection) msg.obj;
+                    psc.addProxy(proxy);
+                    break;
+                }
+                case MESSAGE_BIND_PROFILE_SERVICE:
+                {
+                    ProfileServiceConnections psc = (ProfileServiceConnections) msg.obj;
+                    removeMessages(MESSAGE_BIND_PROFILE_SERVICE, msg.obj);
+                    if (psc == null) {
+                        break;
+                    }
+                    psc.bindService();
+                    break;
+                }
                 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
                 {
                     if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
@@ -1005,6 +1227,7 @@
                             bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
                         }
 
+                        unbindAllBluetoothProfileServices();
                         // disable
                         handleDisable();
                         // Pbap service need receive STATE_TURNING_OFF intent to close
@@ -1129,16 +1352,21 @@
         int callingUser = UserHandle.getCallingUserId();
         int callingUid = Binder.getCallingUid();
         long callingIdentity = Binder.clearCallingIdentity();
+        UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        UserInfo ui = um.getProfileParent(callingUser);
+        int parentUser = (ui != null) ? ui.id : UserHandle.USER_NULL;
         int callingAppId = UserHandle.getAppId(callingUid);
         boolean valid = false;
         try {
             foregroundUser = ActivityManager.getCurrentUser();
             valid = (callingUser == foregroundUser) ||
+                    parentUser == foregroundUser    ||
                     callingAppId == Process.NFC_UID ||
                     callingAppId == mSystemUiUid;
             if (DBG) {
                 Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid
                     + " callingUser=" + callingUser
+                    + " parentUser=" + parentUser
                     + " foregroundUser=" + foregroundUser);
             }
         } finally {
@@ -1165,6 +1393,7 @@
                 } else {
                     //If Bluetooth is off, send service down event to proxy objects, and unbind
                     if (!isUp && canUnbindBluetoothService()) {
+                        unbindAllBluetoothProfileServices();
                         sendBluetoothServiceDownCallback();
                         unbindAndFinish();
                     }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 0f1ed0a..348aa1b 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -797,6 +797,17 @@
         throw new IllegalStateException("No free netIds");
     }
 
+    private int getConnectivityChangeDelay() {
+        final ContentResolver cr = mContext.getContentResolver();
+
+        /** Check system properties for the default value then use secure settings value, if any. */
+        int defaultDelay = SystemProperties.getInt(
+                "conn." + Settings.Global.CONNECTIVITY_CHANGE_DELAY,
+                ConnectivityManager.CONNECTIVITY_CHANGE_DELAY_DEFAULT);
+        return Settings.Global.getInt(cr, Settings.Global.CONNECTIVITY_CHANGE_DELAY,
+                defaultDelay);
+    }
+
     private boolean teardown(NetworkStateTracker netTracker) {
         if (netTracker.teardown()) {
             netTracker.setTeardownRequested(true);
@@ -1468,6 +1479,11 @@
         sendGeneralBroadcast(info, CONNECTIVITY_ACTION);
     }
 
+    private void sendConnectedBroadcastDelayed(NetworkInfo info, int delayMs) {
+        sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE);
+        sendGeneralBroadcastDelayed(info, CONNECTIVITY_ACTION, delayMs);
+    }
+
     private void sendInetConditionBroadcast(NetworkInfo info) {
         sendGeneralBroadcast(info, ConnectivityManager.INET_CONDITION_ACTION);
     }
@@ -1499,6 +1515,10 @@
         sendStickyBroadcast(makeGeneralIntent(info, bcastType));
     }
 
+    private void sendGeneralBroadcastDelayed(NetworkInfo info, String bcastType, int delayMs) {
+        sendStickyBroadcastDelayed(makeGeneralIntent(info, bcastType), delayMs);
+    }
+
     private void sendDataActivityBroadcast(int deviceType, boolean active, long tsNanos) {
         Intent intent = new Intent(ConnectivityManager.ACTION_DATA_ACTIVITY_CHANGE);
         intent.putExtra(ConnectivityManager.EXTRA_DEVICE_TYPE, deviceType);
@@ -1532,6 +1552,19 @@
         }
     }
 
+    private void sendStickyBroadcastDelayed(Intent intent, int delayMs) {
+        if (delayMs <= 0) {
+            sendStickyBroadcast(intent);
+        } else {
+            if (VDBG) {
+                log("sendStickyBroadcastDelayed: delayMs=" + delayMs + ", action="
+                        + intent.getAction());
+            }
+            mHandler.sendMessageDelayed(mHandler.obtainMessage(
+                    EVENT_SEND_STICKY_BROADCAST_INTENT, intent), delayMs);
+        }
+    }
+
     void systemReady() {
         // start network sampling ..
         Intent intent = new Intent(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED);
@@ -4268,7 +4301,7 @@
         info.setType(type);
         if (connected) {
             info.setDetailedState(DetailedState.CONNECTED, null, info.getExtraInfo());
-            sendConnectedBroadcast(info);
+            sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay());
         } else {
             info.setDetailedState(DetailedState.DISCONNECTED, null, info.getExtraInfo());
             Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
@@ -4299,9 +4332,10 @@
             final Intent immediateIntent = new Intent(intent);
             immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE);
             sendStickyBroadcast(immediateIntent);
-            sendStickyBroadcast(intent);
+            sendStickyBroadcastDelayed(intent, getConnectivityChangeDelay());
             if (newDefaultAgent != null) {
-                sendConnectedBroadcast(newDefaultAgent.networkInfo);
+                sendConnectedBroadcastDelayed(newDefaultAgent.networkInfo,
+                getConnectivityChangeDelay());
             }
         }
     }
diff --git a/services/core/java/com/android/server/MountServiceIdler.java b/services/core/java/com/android/server/MountServiceIdler.java
index bc851a3..e0b2307 100644
--- a/services/core/java/com/android/server/MountServiceIdler.java
+++ b/services/core/java/com/android/server/MountServiceIdler.java
@@ -18,12 +18,14 @@
 
 import java.util.Calendar;
 
+import android.app.ActivityManagerNative;
 import android.app.job.JobInfo;
 import android.app.job.JobParameters;
 import android.app.job.JobScheduler;
 import android.app.job.JobService;
 import android.content.ComponentName;
 import android.content.Context;
+import android.os.RemoteException;
 import android.util.Slog;
 
 public class MountServiceIdler extends JobService {
@@ -53,6 +55,13 @@
 
     @Override
     public boolean onStartJob(JobParameters params) {
+        // First have the activity manager do its idle maintenance.  (Yes this job
+        // is really more than just mount, some day it should be renamed to be system
+        // idleer).
+        try {
+            ActivityManagerNative.getDefault().performIdleMaintenance();
+        } catch (RemoteException e) {
+        }
         // The mount service will run an fstrim operation asynchronously
         // on a designated separate thread, so we provide it with a callback
         // that lets us cleanly end our idle timeslice.  It's safe to call
@@ -98,7 +107,7 @@
     private static Calendar tomorrowMidnight() {
         Calendar calendar = Calendar.getInstance();
         calendar.setTimeInMillis(System.currentTimeMillis());
-        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.HOUR_OF_DAY, 3);
         calendar.set(Calendar.MINUTE, 0);
         calendar.set(Calendar.SECOND, 0);
         calendar.set(Calendar.MILLISECOND, 0);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8cf1020..221a0a6 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -9293,9 +9293,9 @@
                             "Attempt to launch content provider before system ready");
                 }
 
-                // Make sure that the user who owns this provider is started.  If not,
+                // Make sure that the user who owns this provider is running.  If not,
                 // we don't want to allow it to run.
-                if (mStartedUsers.get(userId) == null) {
+                if (!isUserRunningLocked(userId, false)) {
                     Slog.w(TAG, "Unable to launch app "
                             + cpi.applicationInfo.packageName + "/"
                             + cpi.applicationInfo.uid + " for provider "
@@ -12900,7 +12900,7 @@
                     + PowerManagerInternal.wakefulnessToString(mWakefulness));
             pw.println("  mSleeping=" + mSleeping + " mLockScreenShown="
                     + lockScreenShownToString());
-            pw.print("  mShuttingDown=" + mShuttingDown + " mRunningVoice=" + mRunningVoice);
+            pw.println("  mShuttingDown=" + mShuttingDown + " mRunningVoice=" + mRunningVoice);
         }
         if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
                 || mOrigWaitForDebugger) {
@@ -15660,10 +15660,10 @@
         userId = handleIncomingUser(callingPid, callingUid, userId,
                 true, ALLOW_NON_FULL, "broadcast", callerPackage);
 
-        // Make sure that the user who is receiving this broadcast is started.
+        // Make sure that the user who is receiving this broadcast is running.
         // If not, we will just skip it.
 
-        if (userId != UserHandle.USER_ALL && mStartedUsers.get(userId) == null) {
+        if (userId != UserHandle.USER_ALL && !isUserRunningLocked(userId, false)) {
             if (callingUid != Process.SYSTEM_UID || (intent.getFlags()
                     & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) {
                 Slog.w(TAG, "Skipping broadcast of " + intent
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 5ab3fa1..5375bfc 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -461,7 +461,7 @@
         UserState userState = getUserStateLocked(userId);
         SessionState sessionState = userState.sessionStateMap.get(sessionToken);
         if (sessionState == null) {
-            throw new IllegalArgumentException("Session state not found for token " + sessionToken);
+            throw new SessionNotFoundException("Session state not found for token " + sessionToken);
         }
         // Only the application that requested this session or the system can access it.
         if (callingUid != Process.SYSTEM_UID && callingUid != sessionState.callingUid) {
@@ -589,18 +589,22 @@
     }
 
     private void releaseSessionLocked(IBinder sessionToken, int callingUid, int userId) {
-        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
-        if (sessionState.session != null) {
-            UserState userState = getUserStateLocked(userId);
-            if (sessionToken == userState.mainSessionToken) {
-                setMainLocked(sessionToken, false, callingUid, userId);
-            }
-            try {
+        SessionState sessionState = null;
+        try {
+            sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
+            if (sessionState.session != null) {
+                UserState userState = getUserStateLocked(userId);
+                if (sessionToken == userState.mainSessionToken) {
+                    setMainLocked(sessionToken, false, callingUid, userId);
+                }
                 sessionState.session.release();
-            } catch (RemoteException e) {
-                Slog.e(TAG, "session process has already died", e);
             }
-            sessionState.session = null;
+        } catch (RemoteException | SessionNotFoundException e) {
+            Slog.e(TAG, "error in releaseSession", e);
+        } finally {
+            if (sessionState != null) {
+                sessionState.session = null;
+            }
         }
         removeSessionStateLocked(sessionToken, userId);
     }
@@ -648,19 +652,19 @@
     }
 
     private void setMainLocked(IBinder sessionToken, boolean isMain, int callingUid, int userId) {
-        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
-        if (sessionState.hardwareSessionToken != null) {
-            sessionState = getSessionStateLocked(sessionState.hardwareSessionToken,
-                    Process.SYSTEM_UID, userId);
-        }
-        ServiceState serviceState = getServiceStateLocked(sessionState.info.getComponent(), userId);
-        if (!serviceState.isHardware) {
-            return;
-        }
-        ITvInputSession session = getSessionLocked(sessionState);
         try {
+            SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
+            if (sessionState.hardwareSessionToken != null) {
+                sessionState = getSessionStateLocked(sessionState.hardwareSessionToken,
+                        Process.SYSTEM_UID, userId);
+            }
+            ServiceState serviceState = getServiceStateLocked(sessionState.info.getComponent(), userId);
+            if (!serviceState.isHardware) {
+                return;
+            }
+            ITvInputSession session = getSessionLocked(sessionState);
             session.setMain(isMain);
-        } catch (RemoteException e) {
+        } catch (RemoteException | SessionNotFoundException e) {
             Slog.e(TAG, "error in setMain", e);
         }
     }
@@ -1085,7 +1089,7 @@
                             getSessionLocked(sessionState.hardwareSessionToken,
                                     Process.SYSTEM_UID, resolvedUserId).setSurface(surface);
                         }
-                    } catch (RemoteException e) {
+                    } catch (RemoteException | SessionNotFoundException e) {
                         Slog.e(TAG, "error in setSurface", e);
                     }
                 }
@@ -1116,7 +1120,7 @@
                             getSessionLocked(sessionState.hardwareSessionToken, Process.SYSTEM_UID,
                                     resolvedUserId).dispatchSurfaceChanged(format, width, height);
                         }
-                    } catch (RemoteException e) {
+                    } catch (RemoteException | SessionNotFoundException e) {
                         Slog.e(TAG, "error in dispatchSurfaceChanged", e);
                     }
                 }
@@ -1146,7 +1150,7 @@
                                     Process.SYSTEM_UID, resolvedUserId).setVolume((volume > 0.0f)
                                             ? REMOTE_VOLUME_ON : REMOTE_VOLUME_OFF);
                         }
-                    } catch (RemoteException e) {
+                    } catch (RemoteException | SessionNotFoundException e) {
                         Slog.e(TAG, "error in setVolume", e);
                     }
                 }
@@ -1183,7 +1187,7 @@
                         args.arg5 = sessionToken;
                         mWatchLogHandler.obtainMessage(WatchLogHandler.MSG_LOG_WATCH_START, args)
                                 .sendToTarget();
-                    } catch (RemoteException e) {
+                    } catch (RemoteException | SessionNotFoundException e) {
                         Slog.e(TAG, "error in tune", e);
                         return;
                     }
@@ -1205,7 +1209,7 @@
                     try {
                         getSessionLocked(sessionToken, callingUid, resolvedUserId)
                                 .requestUnblockContent(unblockedRating);
-                    } catch (RemoteException e) {
+                    } catch (RemoteException | SessionNotFoundException e) {
                         Slog.e(TAG, "error in requestUnblockContent", e);
                     }
                 }
@@ -1225,7 +1229,7 @@
                     try {
                         getSessionLocked(sessionToken, callingUid, resolvedUserId)
                                 .setCaptionEnabled(enabled);
-                    } catch (RemoteException e) {
+                    } catch (RemoteException | SessionNotFoundException e) {
                         Slog.e(TAG, "error in setCaptionEnabled", e);
                     }
                 }
@@ -1245,7 +1249,7 @@
                     try {
                         getSessionLocked(sessionToken, callingUid, resolvedUserId).selectTrack(
                                 type, trackId);
-                    } catch (RemoteException e) {
+                    } catch (RemoteException | SessionNotFoundException e) {
                         Slog.e(TAG, "error in selectTrack", e);
                     }
                 }
@@ -1266,7 +1270,7 @@
                     try {
                         getSessionLocked(sessionToken, callingUid, resolvedUserId)
                                 .appPrivateCommand(command, data);
-                    } catch (RemoteException e) {
+                    } catch (RemoteException | SessionNotFoundException e) {
                         Slog.e(TAG, "error in appPrivateCommand", e);
                     }
                 }
@@ -1287,7 +1291,7 @@
                     try {
                         getSessionLocked(sessionToken, callingUid, resolvedUserId)
                                 .createOverlayView(windowToken, frame);
-                    } catch (RemoteException e) {
+                    } catch (RemoteException | SessionNotFoundException e) {
                         Slog.e(TAG, "error in createOverlayView", e);
                     }
                 }
@@ -1307,7 +1311,7 @@
                     try {
                         getSessionLocked(sessionToken, callingUid, resolvedUserId)
                                 .relayoutOverlayView(frame);
-                    } catch (RemoteException e) {
+                    } catch (RemoteException | SessionNotFoundException e) {
                         Slog.e(TAG, "error in relayoutOverlayView", e);
                     }
                 }
@@ -1327,7 +1331,7 @@
                     try {
                         getSessionLocked(sessionToken, callingUid, resolvedUserId)
                                 .removeOverlayView();
-                    } catch (RemoteException e) {
+                    } catch (RemoteException | SessionNotFoundException e) {
                         Slog.e(TAG, "error in removeOverlayView", e);
                     }
                 }
@@ -2340,4 +2344,13 @@
             }
         }
     }
+
+    private static class SessionNotFoundException extends IllegalArgumentException {
+        public SessionNotFoundException() {
+        }
+
+        public SessionNotFoundException(String name) {
+            super(name);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 0327cb3..27ac32a 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -242,6 +242,7 @@
         final WindowStateAnimator universeBackground = mService.mAnimator.mUniverseBackground;
         final int aboveUniverseLayer = mService.mAnimator.mAboveUniverseLayer;
         boolean addedUniverse = false;
+        boolean disableWallpaperTouchEvents = false;
 
         // If there's a drag in flight, provide a pseudowindow to catch drag input
         final boolean inDrag = (mService.mDragState != null);
@@ -282,8 +283,14 @@
 
                 final boolean hasFocus = (child == mInputFocus);
                 final boolean isVisible = child.isVisibleLw();
+                if ((privateFlags
+                        & WindowManager.LayoutParams.PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS)
+                            != 0) {
+                    disableWallpaperTouchEvents = true;
+                }
                 final boolean hasWallpaper = (child == mService.mWallpaperTarget)
-                        && (privateFlags & WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD) == 0;
+                        && (privateFlags & WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD) == 0
+                        && !disableWallpaperTouchEvents;
                 final boolean onDefaultDisplay = (child.getDisplayId() == Display.DEFAULT_DISPLAY);
 
                 // If there's a drag in progress and 'child' is a potential drop target,
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 2201d2b..72a3337 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -120,7 +120,6 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.security.cert.CertificateEncodingException;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
@@ -265,6 +264,8 @@
                 = new HashMap<ComponentName, ActiveAdmin>();
         final ArrayList<ActiveAdmin> mAdminList
                 = new ArrayList<ActiveAdmin>();
+        final ArrayList<ComponentName> mRemovingAdmins
+                = new ArrayList<ComponentName>();
 
         // This is the list of component allowed to start lock task mode.
         final List<String> mLockTaskPackages = new ArrayList<String>();
@@ -303,8 +304,6 @@
             if (Intent.ACTION_USER_REMOVED.equals(action)) {
                 removeUserData(userHandle);
             } else if (Intent.ACTION_USER_STARTED.equals(action)
-                    || Intent.ACTION_PACKAGE_CHANGED.equals(action)
-                    || Intent.ACTION_PACKAGE_REMOVED.equals(action)
                     || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
 
                 if (Intent.ACTION_USER_STARTED.equals(action)) {
@@ -313,8 +312,14 @@
                         mUserData.remove(userHandle);
                     }
                 }
-
-                handlePackagesChanged(userHandle);
+                handlePackagesChanged(null /* check all admins */, userHandle);
+            } else if (Intent.ACTION_PACKAGE_CHANGED.equals(action)
+                    || (Intent.ACTION_PACKAGE_ADDED.equals(action)
+                            && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false))) {
+                handlePackagesChanged(intent.getData().getSchemeSpecificPart(), userHandle);
+            } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)
+                    && !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+                handlePackagesChanged(intent.getData().getSchemeSpecificPart(), userHandle);
             }
         }
     };
@@ -899,7 +904,7 @@
         }
     }
 
-    private void handlePackagesChanged(int userHandle) {
+    private void handlePackagesChanged(String packageName, int userHandle) {
         boolean removed = false;
         if (DBG) Slog.d(LOG_TAG, "Handling package changes for user " + userHandle);
         DevicePolicyData policy = getUserData(userHandle);
@@ -908,11 +913,17 @@
             for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
                 ActiveAdmin aa = policy.mAdminList.get(i);
                 try {
-                    if (pm.getPackageInfo(aa.info.getPackageName(), 0, userHandle) == null
-                            || pm.getReceiverInfo(aa.info.getComponent(), 0, userHandle) == null) {
-                        removed = true;
-                        policy.mAdminList.remove(i);
-                        policy.mAdminMap.remove(aa.info.getComponent());
+                    // If we're checking all packages or if the specific one we're checking matches,
+                    // then check if the package and receiver still exist.
+                    final String adminPackage = aa.info.getPackageName();
+                    if (packageName == null || packageName.equals(adminPackage)) {
+                        if (pm.getPackageInfo(adminPackage, 0, userHandle) == null
+                                || pm.getReceiverInfo(aa.info.getComponent(), 0, userHandle)
+                                    == null) {
+                            removed = true;
+                            policy.mAdminList.remove(i);
+                            policy.mAdminMap.remove(aa.info.getComponent());
+                        }
                     }
                 } catch (RemoteException re) {
                     // Shouldn't happen
@@ -1202,6 +1213,9 @@
     void removeActiveAdminLocked(final ComponentName adminReceiver, int userHandle) {
         final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
         if (admin != null) {
+            synchronized (this) {
+                getUserData(userHandle).mRemovingAdmins.add(adminReceiver);
+            }
             sendAdminCommandLocked(admin,
                     DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED,
                     new BroadcastReceiver() {
@@ -1221,9 +1235,10 @@
                                 }
                                 saveSettingsLocked(userHandle);
                                 updateMaximumTimeToLockLocked(policy);
+                                policy.mRemovingAdmins.remove(adminReceiver);
                             }
                         }
-            });
+                    });
         }
     }
 
@@ -1788,6 +1803,18 @@
         }
     }
 
+    @Override
+    public boolean isRemovingAdmin(ComponentName adminReceiver, int userHandle) {
+        if (!mHasFeature) {
+            return false;
+        }
+        enforceCrossUserPermission(userHandle);
+        synchronized (this) {
+            DevicePolicyData policyData = getUserData(userHandle);
+            return policyData.mRemovingAdmins.contains(adminReceiver);
+        }
+    }
+
     public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId, int userHandle) {
         if (!mHasFeature) {
             return false;
@@ -4091,6 +4118,10 @@
                         ap.dump("    ", pw);
                     }
                 }
+                if (!policy.mRemovingAdmins.isEmpty()) {
+                    p.println("  Removing Device Admins (User " + policy.mUserHandle + "): "
+                            + policy.mRemovingAdmins);
+                }
 
                 pw.println(" ");
                 pw.print("  mPasswordOwner="); pw.println(policy.mPasswordOwner);
diff --git a/telecomm/java/android/telecom/AudioState.java b/telecomm/java/android/telecom/AudioState.java
index 3271ebf..9c03319 100644
--- a/telecomm/java/android/telecom/AudioState.java
+++ b/telecomm/java/android/telecom/AudioState.java
@@ -54,14 +54,14 @@
     public static final int ROUTE_ALL = ROUTE_EARPIECE | ROUTE_BLUETOOTH | ROUTE_WIRED_HEADSET |
             ROUTE_SPEAKER;
 
-    /** @hide */
-    @Deprecated public final boolean isMuted;
+    /** Note: Deprecated, please do not use if possible. */
+    @SystemApi public final boolean isMuted;
 
-    /** @hide */
-    @Deprecated public final int route;
+    /** Note: Deprecated, please do not use if possible. */
+    @SystemApi public final int route;
 
-    /** @hide */
-    @Deprecated public final int supportedRouteMask;
+    /** Note: Deprecated, please do not use if possible. */
+    @SystemApi public final int supportedRouteMask;
 
     public AudioState(boolean muted, int route, int supportedRouteMask) {
         this.isMuted = muted;
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 2a3d7ab8..6621726 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -732,6 +732,26 @@
     }
 
     /**
+     * Return whether a given phone account has a voicemail number configured.
+     *
+     * @param accountHandle The handle for the account to check for a voicemail number.
+     * @return {@code true} If the given phone account has a voicemail number.
+     *
+     * @hide
+     */
+    @SystemApi
+    public boolean hasVoiceMailNumber(PhoneAccountHandle accountHandle) {
+        try {
+            if (isServiceConnected()) {
+                return getTelecomService().hasVoiceMailNumber(accountHandle);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException calling isInCall().", e);
+        }
+        return false;
+    }
+
+    /**
      * Returns whether there is an ongoing phone call (can be in dialing, ringing, active or holding
      * states).
      * <p>
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index cbd9d69..f8d7539 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -121,6 +121,11 @@
     boolean isVoiceMailNumber(in PhoneAccountHandle accountHandle, String number);
 
     /**
+     * @see TelecomServiceImpl#hasVoiceMailNumber
+     */
+    boolean hasVoiceMailNumber(in PhoneAccountHandle accountHandle);
+
+    /**
      * @see TelecomServiceImpl#getDefaultPhoneApp
      */
     ComponentName getDefaultPhoneApp();