Merge "Change carrier text to 'airplane mode' when on"
diff --git a/Android.mk b/Android.mk
index 70e965b..f7f3652 100644
--- a/Android.mk
+++ b/Android.mk
@@ -152,6 +152,8 @@
 	core/java/android/hardware/display/IDisplayManager.aidl \
 	core/java/android/hardware/display/IDisplayManagerCallback.aidl \
 	core/java/android/hardware/display/IVirtualDisplayCallback.aidl \
+	core/java/android/hardware/fingerprint/IFingerprintService.aidl \
+	core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl \
 	core/java/android/hardware/hdmi/IHdmiControlCallback.aidl \
 	core/java/android/hardware/hdmi/IHdmiControlService.aidl \
 	core/java/android/hardware/hdmi/IHdmiDeviceEventListener.aidl \
@@ -227,8 +229,6 @@
 	core/java/android/service/dreams/IDreamManager.aidl \
 	core/java/android/service/dreams/IDreamService.aidl \
 	core/java/android/service/persistentdata/IPersistentDataBlockService.aidl \
-	core/java/android/service/fingerprint/IFingerprintService.aidl \
-	core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl \
 	core/java/android/service/trust/ITrustAgentService.aidl \
 	core/java/android/service/trust/ITrustAgentServiceCallback.aidl \
 	core/java/android/service/voice/IVoiceInteractionService.aidl \
diff --git a/api/current.txt b/api/current.txt
index b3d5fd0..fb487ee 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -354,6 +354,7 @@
     field public static final int bottomRightRadius = 16843180; // 0x10101ac
     field public static final int breadCrumbShortTitle = 16843524; // 0x1010304
     field public static final int breadCrumbTitle = 16843523; // 0x1010303
+    field public static final int breakStrategy = 16844011; // 0x10104eb
     field public static final int bufferType = 16843086; // 0x101014e
     field public static final int button = 16843015; // 0x1010107
     field public static final int buttonBarButtonStyle = 16843567; // 0x101032f
@@ -18801,6 +18802,7 @@
 
   public static final class WifiEnterpriseConfig.Eap {
     field public static final int AKA = 5; // 0x5
+    field public static final int AKA_PRIME = 6; // 0x6
     field public static final int NONE = -1; // 0xffffffff
     field public static final int PEAP = 0; // 0x0
     field public static final int PWD = 3; // 0x3
@@ -30920,6 +30922,9 @@
     method public final void increaseWidthTo(int);
     method public boolean isRtlCharAt(int);
     method protected final boolean isSpanned();
+    field public static final int BREAK_STRATEGY_BALANCED = 2; // 0x2
+    field public static final int BREAK_STRATEGY_HIGH_QUALITY = 1; // 0x1
+    field public static final int BREAK_STRATEGY_SIMPLE = 0; // 0x0
     field public static final int DIR_LEFT_TO_RIGHT = 1; // 0x1
     field public static final int DIR_RIGHT_TO_LEFT = -1; // 0xffffffff
   }
@@ -40082,6 +40087,7 @@
     method public void endBatchEdit();
     method public boolean extractText(android.view.inputmethod.ExtractedTextRequest, android.view.inputmethod.ExtractedText);
     method public final int getAutoLinkMask();
+    method public int getBreakStrategy();
     method public int getCompoundDrawablePadding();
     method public android.content.res.ColorStateList getCompoundDrawableTintList();
     method public android.graphics.PorterDuff.Mode getCompoundDrawableTintMode();
@@ -40183,6 +40189,7 @@
     method public void removeTextChangedListener(android.text.TextWatcher);
     method public void setAllCaps(boolean);
     method public final void setAutoLinkMask(int);
+    method public void setBreakStrategy(int);
     method public void setCompoundDrawablePadding(int);
     method public void setCompoundDrawableTintList(android.content.res.ColorStateList);
     method public void setCompoundDrawableTintMode(android.graphics.PorterDuff.Mode);
diff --git a/api/system-current.txt b/api/system-current.txt
index 9462054..84f9dbf 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -135,6 +135,7 @@
     field public static final java.lang.String PACKAGE_USAGE_STATS = "android.permission.PACKAGE_USAGE_STATS";
     field public static final java.lang.String PACKAGE_VERIFICATION_AGENT = "android.permission.PACKAGE_VERIFICATION_AGENT";
     field public static final java.lang.String PERFORM_CDMA_PROVISIONING = "android.permission.PERFORM_CDMA_PROVISIONING";
+    field public static final java.lang.String PERFORM_SIM_ACTIVATION = "android.permission.PERFORM_SIM_ACTIVATION";
     field public static final deprecated java.lang.String PERSISTENT_ACTIVITY = "android.permission.PERSISTENT_ACTIVITY";
     field public static final java.lang.String PROCESS_OUTGOING_CALLS = "android.permission.PROCESS_OUTGOING_CALLS";
     field public static final java.lang.String PROVIDE_TRUST_AGENT = "android.permission.PROVIDE_TRUST_AGENT";
@@ -426,6 +427,7 @@
     field public static final int bottomRightRadius = 16843180; // 0x10101ac
     field public static final int breadCrumbShortTitle = 16843524; // 0x1010304
     field public static final int breadCrumbTitle = 16843523; // 0x1010303
+    field public static final int breakStrategy = 16844011; // 0x10104eb
     field public static final int bufferType = 16843086; // 0x101014e
     field public static final int button = 16843015; // 0x1010107
     field public static final int buttonBarButtonStyle = 16843567; // 0x101032f
@@ -6331,6 +6333,7 @@
     method public android.bluetooth.BluetoothDevice getRemoteDevice(byte[]);
     method public int getScanMode();
     method public int getState();
+    method public boolean isBleScanAlwaysAvailable();
     method public boolean isDiscovering();
     method public boolean isEnabled();
     method public boolean isMultipleAdvertisementSupported();
@@ -6347,6 +6350,7 @@
     field public static final java.lang.String ACTION_DISCOVERY_FINISHED = "android.bluetooth.adapter.action.DISCOVERY_FINISHED";
     field public static final java.lang.String ACTION_DISCOVERY_STARTED = "android.bluetooth.adapter.action.DISCOVERY_STARTED";
     field public static final java.lang.String ACTION_LOCAL_NAME_CHANGED = "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED";
+    field public static final java.lang.String ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE = "android.bluetooth.adapter.action.REQUEST_BLE_SCAN_ALWAYS_AVAILABLE";
     field public static final java.lang.String ACTION_REQUEST_DISCOVERABLE = "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";
     field public static final java.lang.String ACTION_REQUEST_ENABLE = "android.bluetooth.adapter.action.REQUEST_ENABLE";
     field public static final java.lang.String ACTION_SCAN_MODE_CHANGED = "android.bluetooth.adapter.action.SCAN_MODE_CHANGED";
@@ -20497,6 +20501,7 @@
 
   public static final class WifiEnterpriseConfig.Eap {
     field public static final int AKA = 5; // 0x5
+    field public static final int AKA_PRIME = 6; // 0x6
     field public static final int NONE = -1; // 0xffffffff
     field public static final int PEAP = 0; // 0x0
     field public static final int PWD = 3; // 0x3
@@ -33462,6 +33467,9 @@
     method public final void increaseWidthTo(int);
     method public boolean isRtlCharAt(int);
     method protected final boolean isSpanned();
+    field public static final int BREAK_STRATEGY_BALANCED = 2; // 0x2
+    field public static final int BREAK_STRATEGY_HIGH_QUALITY = 1; // 0x1
+    field public static final int BREAK_STRATEGY_SIMPLE = 0; // 0x0
     field public static final int DIR_LEFT_TO_RIGHT = 1; // 0x1
     field public static final int DIR_RIGHT_TO_LEFT = -1; // 0xffffffff
   }
@@ -42925,6 +42933,7 @@
     method public void endBatchEdit();
     method public boolean extractText(android.view.inputmethod.ExtractedTextRequest, android.view.inputmethod.ExtractedText);
     method public final int getAutoLinkMask();
+    method public int getBreakStrategy();
     method public int getCompoundDrawablePadding();
     method public android.content.res.ColorStateList getCompoundDrawableTintList();
     method public android.graphics.PorterDuff.Mode getCompoundDrawableTintMode();
@@ -43026,6 +43035,7 @@
     method public void removeTextChangedListener(android.text.TextWatcher);
     method public void setAllCaps(boolean);
     method public final void setAutoLinkMask(int);
+    method public void setBreakStrategy(int);
     method public void setCompoundDrawablePadding(int);
     method public void setCompoundDrawableTintList(android.content.res.ColorStateList);
     method public void setCompoundDrawableTintMode(android.graphics.PorterDuff.Mode);
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index c86fd53..c5af992 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -7,6 +7,12 @@
 
 #define LOG_TAG "appproc"
 
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
 #include <binder/IPCThreadState.h>
 #include <binder/ProcessState.h>
 #include <utils/Log.h>
@@ -17,11 +23,6 @@
 #include <android_runtime/AndroidRuntime.h>
 #include <private/android_filesystem_config.h>  // for AID_SYSTEM
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/prctl.h>
-
 namespace android {
 
 static void app_usage()
diff --git a/cmds/idmap/scan.cpp b/cmds/idmap/scan.cpp
index 197e36b..84158d3 100644
--- a/cmds/idmap/scan.cpp
+++ b/cmds/idmap/scan.cpp
@@ -1,3 +1,6 @@
+#include <dirent.h>
+#include <sys/stat.h>
+
 #include "idmap.h"
 
 #include <UniquePtr.h>
@@ -9,8 +12,6 @@
 #include <utils/String16.h>
 #include <utils/String8.h>
 
-#include <dirent.h>
-
 #define NO_OVERLAY_TAG (-1000)
 
 using namespace android;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 4880db1..81b1583 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -254,18 +254,21 @@
         }
     }
 
+    static final class AcquiringProviderRecord {
+        IActivityManager.ContentProviderHolder holder;
+        boolean acquiring = true;
+        int requests = 1;
+    }
+
     // The lock of mProviderMap protects the following variables.
-    final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap
-        = new ArrayMap<ProviderKey, ProviderClientRecord>();
-    final ArrayMap<IBinder, ProviderRefCount> mProviderRefCountMap
-        = new ArrayMap<IBinder, ProviderRefCount>();
-    final ArrayMap<IBinder, ProviderClientRecord> mLocalProviders
-        = new ArrayMap<IBinder, ProviderClientRecord>();
-    final ArrayMap<ComponentName, ProviderClientRecord> mLocalProvidersByName
-            = new ArrayMap<ComponentName, ProviderClientRecord>();
+    final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap = new ArrayMap<>();
+    final ArrayMap<ProviderKey, AcquiringProviderRecord> mAcquiringProviderMap = new ArrayMap<>();
+    final ArrayMap<IBinder, ProviderRefCount> mProviderRefCountMap = new ArrayMap<>();
+    final ArrayMap<IBinder, ProviderClientRecord> mLocalProviders = new ArrayMap<>();
+    final ArrayMap<ComponentName, ProviderClientRecord> mLocalProvidersByName = new ArrayMap<>();
 
     final ArrayMap<Activity, ArrayList<OnActivityPausedListener>> mOnPauseListeners
-        = new ArrayMap<Activity, ArrayList<OnActivityPausedListener>>();
+            = new ArrayMap<>();
 
     final GcIdler mGcIdler = new GcIdler();
     boolean mGcIdlerScheduled = false;
@@ -345,7 +348,7 @@
         }
     }
 
-    final class ProviderClientRecord {
+    static final class ProviderClientRecord {
         final String[] mNames;
         final IContentProvider mProvider;
         final ContentProvider mLocalProvider;
@@ -4693,22 +4696,57 @@
 
     public final IContentProvider acquireProvider(
             Context c, String auth, int userId, boolean stable) {
-        final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
+        final ProviderKey key = new ProviderKey(auth, userId);
+        final IContentProvider provider = acquireExistingProvider(c, key, stable);
         if (provider != null) {
             return provider;
         }
+        AcquiringProviderRecord r;
+        boolean first = false;
+        synchronized (mAcquiringProviderMap) {
+            r = mAcquiringProviderMap.get(key);
+            if (r == null) {
+                r = new AcquiringProviderRecord();
+                mAcquiringProviderMap.put(key, r);
+                first = true;
+            } else {
+                r.requests++;
+            }
+        }
 
-        // There is a possible race here.  Another thread may try to acquire
-        // the same provider at the same time.  When this happens, we want to ensure
-        // that the first one wins.
-        // Note that we cannot hold the lock while acquiring and installing the
-        // provider since it might take a long time to run and it could also potentially
-        // be re-entrant in the case where the provider is in the same process.
         IActivityManager.ContentProviderHolder holder = null;
-        try {
-            holder = ActivityManagerNative.getDefault().getContentProvider(
-                    getApplicationThread(), auth, userId, stable);
-        } catch (RemoteException ex) {
+        if (first) {
+            // Multiple threads may try to acquire the same provider at the same time.
+            // When this happens, we only let the first one really gets provider.
+            // Other threads just wait for its result.
+            // Note that we cannot hold the lock while acquiring and installing the
+            // provider since it might take a long time to run and it could also potentially
+            // be re-entrant in the case where the provider is in the same process.
+            try {
+                holder = ActivityManagerNative.getDefault().getContentProvider(
+                        getApplicationThread(), auth, userId, stable);
+            } catch (RemoteException ex) {
+            }
+            synchronized (r) {
+                r.holder = holder;
+                r.acquiring = false;
+                r.notifyAll();
+            }
+        } else {
+            synchronized (r) {
+                while (r.acquiring) {
+                    try {
+                        r.wait();
+                    } catch (InterruptedException e) {
+                    }
+                }
+                holder = r.holder;
+            }
+        }
+        synchronized (mAcquiringProviderMap) {
+            if (--r.requests == 0) {
+                mAcquiringProviderMap.remove(key);
+            }
         }
         if (holder == null) {
             Slog.e(TAG, "Failed to find provider info for " + auth);
@@ -4792,8 +4830,12 @@
 
     public final IContentProvider acquireExistingProvider(
             Context c, String auth, int userId, boolean stable) {
+        return acquireExistingProvider(c, new ProviderKey(auth, userId), stable);
+    }
+
+    final IContentProvider acquireExistingProvider(
+            Context c, ProviderKey key, boolean stable) {
         synchronized (mProviderMap) {
-            final ProviderKey key = new ProviderKey(auth, userId);
             final ProviderClientRecord pr = mProviderMap.get(key);
             if (pr == null) {
                 return null;
@@ -4804,7 +4846,7 @@
             if (!jBinder.isBinderAlive()) {
                 // The hosting process of the provider has died; we can't
                 // use this one.
-                Log.i(TAG, "Acquiring provider " + auth + " for user " + userId
+                Log.i(TAG, "Acquiring provider " + key.authority + " for user " +  key.userId
                         + ": existing object's process dead");
                 handleUnstableProviderDiedLocked(jBinder, true);
                 return null;
@@ -5126,18 +5168,12 @@
                     if (DEBUG_PROVIDER) {
                         Slog.v(TAG, "installProvider: lost the race, updating ref count");
                     }
-                    // We need to transfer our new reference to the existing
-                    // ref count, releasing the old one...  but only if
-                    // release is needed (that is, it is not running in the
-                    // system process).
+                    // The provider has already been installed, so we need
+                    // to increase reference count to the existing one, but
+                    // only if release is needed (that is, it is not running
+                    // in the system process or local to the process).
                     if (!noReleaseNeeded) {
                         incProviderRefLocked(prc, stable);
-                        try {
-                            ActivityManagerNative.getDefault().removeContentProvider(
-                                    holder.connection, stable);
-                        } catch (RemoteException e) {
-                            //do nothing content provider object is dead any way
-                        }
                     }
                 } else {
                     ProviderClientRecord client = installProviderAuthoritiesLocked(
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index a0f40f6..b3aa6be 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -99,8 +99,8 @@
 import android.os.storage.StorageManager;
 import android.print.IPrintManager;
 import android.print.PrintManager;
-import android.service.fingerprint.FingerprintManager;
-import android.service.fingerprint.IFingerprintService;
+import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.IFingerprintService;
 import android.service.persistentdata.IPersistentDataBlockService;
 import android.service.persistentdata.PersistentDataBlockManager;
 import android.telecom.TelecomManager;
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index be26eac..edb768d0 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -18,6 +18,7 @@
 
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
 import android.bluetooth.le.BluetoothLeAdvertiser;
 import android.bluetooth.le.BluetoothLeScanner;
 import android.bluetooth.le.ScanCallback;
@@ -206,6 +207,23 @@
             "android.bluetooth.adapter.action.REQUEST_ENABLE";
 
     /**
+     * Activity Action: Show a system activity that allows user to enable BLE scans even when
+     * Bluetooth is turned off.<p>
+     *
+     * Notification of result of this activity is posted using
+     * {@link android.app.Activity#onActivityResult}. The <code>resultCode</code> will be
+     * {@link android.app.Activity#RESULT_OK} if BLE scan always available setting is turned on or
+     * {@link android.app.Activity#RESULT_CANCELED} if the user has rejected the request or an
+     * error occurred.
+     *
+     * @hide
+     */
+    @SystemApi
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE =
+            "android.bluetooth.adapter.action.REQUEST_BLE_SCAN_ALWAYS_AVAILABLE";
+
+    /**
      * Broadcast Action: Indicates the Bluetooth scan mode of the local Adapter
      * has changed.
      * <p>Always contains the extra fields {@link #EXTRA_SCAN_MODE} and {@link
@@ -916,6 +934,22 @@
     }
 
     /**
+     * Returns {@code true} if BLE scan is always available, {@code false} otherwise. <p>
+     *
+     * If this returns {@code true}, application can issue {@link BluetoothLeScanner#startScan} and
+     * fetch scan results even when Bluetooth is turned off.<p>
+     *
+     * To change this setting, use {@link #ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE}.
+     *
+     * @hide
+     */
+    @SystemApi
+    public boolean isBleScanAlwaysAvailable() {
+        // TODO: implement after Settings UI change.
+        return false;
+    }
+
+    /**
      * Returns whether peripheral mode is supported.
      *
      * @hide
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 7a99a79..514802e9 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1041,6 +1041,18 @@
      */
     public static final String ACTION_CALL_PRIVILEGED = "android.intent.action.CALL_PRIVILEGED";
     /**
+     * Activity action: Activate the current SIM card.  If SIM cards do not require activation,
+     * sending this intent is a no-op.
+     * <p>Input: No data should be specified.  get*Extra may have an optional
+     * {@link #EXTRA_SIM_ACTIVATION_RESPONSE} field containing a PendingIntent through which to
+     * send the activation result.
+     * <p>Output: nothing.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_SIM_ACTIVATION_REQUEST =
+            "android.intent.action.SIM_ACTIVATION_REQUEST";
+    /**
      * Activity Action: Send a message to someone specified by the data.
      * <p>Input: {@link #getData} is URI describing the target.
      * <p>Output: nothing.
@@ -3620,6 +3632,15 @@
     /** {@hide} */
     public static final String EXTRA_REASON = "android.intent.extra.REASON";
 
+    /**
+     * Optional {@link android.app.PendingIntent} extra used to deliver the result of the SIM
+     * activation request.
+     * TODO: Add information about the structure and response data used with the pending intent.
+     * @hide
+     */
+    public static final String EXTRA_SIM_ACTIVATION_RESPONSE =
+            "android.intent.extra.SIM_ACTIVATION_RESPONSE";
+
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Intent flags (see mFlags variable).
diff --git a/core/java/android/service/fingerprint/Fingerprint.aidl b/core/java/android/hardware/fingerprint/Fingerprint.aidl
similarity index 94%
rename from core/java/android/service/fingerprint/Fingerprint.aidl
rename to core/java/android/hardware/fingerprint/Fingerprint.aidl
index c9fd989..4743354 100644
--- a/core/java/android/service/fingerprint/Fingerprint.aidl
+++ b/core/java/android/hardware/fingerprint/Fingerprint.aidl
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.service.fingerprint;
+package android.hardware.fingerprint;
 
 // @hide
 parcelable Fingerprint;
diff --git a/core/java/android/service/fingerprint/Fingerprint.java b/core/java/android/hardware/fingerprint/Fingerprint.java
similarity index 98%
rename from core/java/android/service/fingerprint/Fingerprint.java
rename to core/java/android/hardware/fingerprint/Fingerprint.java
index 37552eb..c307634 100644
--- a/core/java/android/service/fingerprint/Fingerprint.java
+++ b/core/java/android/hardware/fingerprint/Fingerprint.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.service.fingerprint;
+package android.hardware.fingerprint;
 
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/core/java/android/service/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
similarity index 99%
rename from core/java/android/service/fingerprint/FingerprintManager.java
rename to core/java/android/hardware/fingerprint/FingerprintManager.java
index bb90e40..e3572a2 100644
--- a/core/java/android/service/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.service.fingerprint;
+package android.hardware.fingerprint;
 
 import android.app.ActivityManagerNative;
 import android.content.ContentResolver;
@@ -28,7 +28,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.Settings;
-import android.service.fingerprint.FingerprintManager.EnrollmentCallback;
+import android.hardware.fingerprint.FingerprintManager.EnrollmentCallback;
 import android.util.Log;
 import android.util.Slog;
 
diff --git a/core/java/android/service/fingerprint/FingerprintUtils.java b/core/java/android/hardware/fingerprint/FingerprintUtils.java
similarity index 98%
rename from core/java/android/service/fingerprint/FingerprintUtils.java
rename to core/java/android/hardware/fingerprint/FingerprintUtils.java
index 62acbb9..ae3d4a4 100644
--- a/core/java/android/service/fingerprint/FingerprintUtils.java
+++ b/core/java/android/hardware/fingerprint/FingerprintUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.service.fingerprint;
+package android.hardware.fingerprint;
 
 import android.content.ContentResolver;
 import android.provider.Settings;
diff --git a/core/java/android/service/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
similarity index 92%
rename from core/java/android/service/fingerprint/IFingerprintService.aidl
rename to core/java/android/hardware/fingerprint/IFingerprintService.aidl
index e5d3ad4..c5a45e2 100644
--- a/core/java/android/service/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -13,11 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.service.fingerprint;
+package android.hardware.fingerprint;
 
 import android.os.Bundle;
-import android.service.fingerprint.IFingerprintServiceReceiver;
-import android.service.fingerprint.Fingerprint;
+import android.hardware.fingerprint.IFingerprintServiceReceiver;
+import android.hardware.fingerprint.Fingerprint;
 import java.util.List;
 
 /**
diff --git a/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl b/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
similarity index 96%
rename from core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
rename to core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
index f025064..e82395f 100644
--- a/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.service.fingerprint;
+package android.hardware.fingerprint;
 
 import android.os.Bundle;
 import android.os.UserHandle;
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index bf3d9aa..f305b2a 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -366,7 +366,6 @@
     public String toSafeString() {
         String scheme = getScheme();
         String ssp = getSchemeSpecificPart();
-        String authority = null;
         if (scheme != null) {
             if (scheme.equalsIgnoreCase("tel") || scheme.equalsIgnoreCase("sip")
                     || scheme.equalsIgnoreCase("sms") || scheme.equalsIgnoreCase("smsto")
@@ -385,9 +384,11 @@
                     }
                 }
                 return builder.toString();
-            } else if (scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("https")) {
-                ssp = null;
-                authority = "//" + getAuthority() + "/...";
+            } else if (scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("https")
+                    || scheme.equalsIgnoreCase("ftp")) {
+                ssp = "//" + ((getHost() != null) ? getHost() : "")
+                        + ((getPort() != -1) ? (":" + getPort()) : "")
+                        + "/...";
             }
         }
         // Not a sensitive scheme, but let's still be conservative about
@@ -401,9 +402,6 @@
         if (ssp != null) {
             builder.append(ssp);
         }
-        if (authority != null) {
-            builder.append(authority);
-        }
         return builder.toString();
     }
 
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 8b3ecae..508fdee 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -4415,7 +4415,7 @@
         if (!checkin) {
             pw.println(header);
         }
-        String[] lineArgs = new String[4];
+        String[] lineArgs = new String[5];
         for (int i=0; i<count; i++) {
             long duration = steps.getDurationAt(i);
             int level = steps.getLevelAt(i);
@@ -4430,7 +4430,7 @@
                         case Display.STATE_ON: lineArgs[2] = "s+"; break;
                         case Display.STATE_DOZE: lineArgs[2] = "sd"; break;
                         case Display.STATE_DOZE_SUSPEND: lineArgs[2] = "sds"; break;
-                        default: lineArgs[1] = "?"; break;
+                        default: lineArgs[2] = "?"; break;
                     }
                 } else {
                     lineArgs[2] = "";
@@ -4441,9 +4441,9 @@
                     lineArgs[3] = "";
                 }
                 if ((modMode&STEP_LEVEL_MODE_DEVICE_IDLE) == 0) {
-                    lineArgs[3] = (initMode&STEP_LEVEL_MODE_DEVICE_IDLE) != 0 ? "i+" : "i-";
+                    lineArgs[4] = (initMode&STEP_LEVEL_MODE_DEVICE_IDLE) != 0 ? "i+" : "i-";
                 } else {
-                    lineArgs[3] = "";
+                    lineArgs[4] = "";
                 }
                 dumpLine(pw, 0 /* uid */, "i" /* category */, header, (Object[])lineArgs);
             } else {
@@ -4459,7 +4459,7 @@
                         case Display.STATE_ON: pw.print("screen-on"); break;
                         case Display.STATE_DOZE: pw.print("screen-doze"); break;
                         case Display.STATE_DOZE_SUSPEND: pw.print("screen-doze-suspend"); break;
-                        default: lineArgs[1] = "screen-?"; break;
+                        default: pw.print("screen-?"); break;
                     }
                     haveModes = true;
                 }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 8e5d245..f79ef35 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6375,6 +6375,14 @@
                 "wifi_scan_always_enabled";
 
        /**
+        * Settings to allow BLE scans to be enabled even when Bluetooth is turned off for
+        * connectivity.
+        * @hide
+        */
+       public static final String BLE_SCAN_ALWAYS_AVAILABLE =
+               "ble_scan_always_enabled";
+
+       /**
         * Used to save the Wifi_ON state prior to tethering.
         * This state will be checked to restore Wifi after
         * the user turns off tethering.
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index 7d2e1ef..239b386 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -79,7 +79,8 @@
                          boolean includepad,
                          TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
         this(base, display, paint, width, align, TextDirectionHeuristics.FIRSTSTRONG_LTR,
-                spacingmult, spacingadd, includepad, ellipsize, ellipsizedWidth);
+                spacingmult, spacingadd, includepad, StaticLayout.BREAK_STRATEGY_SIMPLE,
+                ellipsize, ellipsizedWidth);
     }
 
     /**
@@ -95,7 +96,7 @@
                          TextPaint paint,
                          int width, Alignment align, TextDirectionHeuristic textDir,
                          float spacingmult, float spacingadd,
-                         boolean includepad,
+                         boolean includepad, int breakStrategy,
                          TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
         super((ellipsize == null)
                 ? display
@@ -120,6 +121,7 @@
         mObjects = new PackedObjectVector<Directions>(1);
 
         mIncludePad = includepad;
+        mBreakStrategy = breakStrategy;
 
         /*
          * This is annoying, but we can't refer to the layout until
@@ -279,10 +281,9 @@
             sBuilder = null;
         }
 
-        // TODO: make sure reflowed is properly initialized
         if (reflowed == null) {
             reflowed = new StaticLayout(null);
-            b = StaticLayout.Builder.obtain();
+            b = StaticLayout.Builder.obtain(text, where, where + after, getWidth());
         }
 
         b.setText(text, where, where + after)
@@ -292,7 +293,8 @@
                 .setSpacingMult(getSpacingMultiplier())
                 .setSpacingAdd(getSpacingAdd())
                 .setEllipsizedWidth(mEllipsizedWidth)
-                .setEllipsize(mEllipsizeAt);
+                .setEllipsize(mEllipsizeAt)
+                .setBreakStrategy(mBreakStrategy);
         reflowed.generate(b, false, true);
         int n = reflowed.getLineCount();
 
@@ -717,6 +719,7 @@
     private boolean mEllipsize;
     private int mEllipsizedWidth;
     private TextUtils.TruncateAt mEllipsizeAt;
+    private int mBreakStrategy;
 
     private PackedIntVector mInts;
     private PackedObjectVector<Directions> mObjects;
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 22abb18..16ae5e2 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -16,6 +16,7 @@
 
 package android.text;
 
+import android.annotation.IntDef;
 import android.emoji.EmojiFactory;
 import android.graphics.Canvas;
 import android.graphics.Paint;
@@ -33,6 +34,8 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.GrowingArrayUtils;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
 
 /**
@@ -43,6 +46,31 @@
  * For text that will not change, use a {@link StaticLayout}.
  */
 public abstract class Layout {
+    /** @hide */
+    @IntDef({BREAK_STRATEGY_SIMPLE, BREAK_STRATEGY_HIGH_QUALITY, BREAK_STRATEGY_BALANCED})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface BreakStrategy {}
+
+    /**
+     * Value for break strategy indicating simple line breaking. Automatic hyphens are not added
+     * (though soft hyphens are respected), and modifying text generally doesn't affect the layout
+     * before it (which yields a more consistent user experience when editing), but layout may not
+     * be the highest quality.
+     */
+    public static final int BREAK_STRATEGY_SIMPLE = 0;
+
+    /**
+     * Value for break strategy indicating high quality line breaking, including automatic
+     * hyphenation and doing whole-paragraph optimization of line breaks.
+     */
+    public static final int BREAK_STRATEGY_HIGH_QUALITY = 1;
+
+    /**
+     * Value for break strategy indicating balanced line breaking. The breaks are chosen to
+     * make all lines as close to the same length as possible, including automatic hyphenation.
+     */
+    public static final int BREAK_STRATEGY_BALANCED = 2;
+
     private static final ParagraphStyle[] NO_PARA_SPANS =
         ArrayUtils.emptyArray(ParagraphStyle.class);
 
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 4174df0..2bcb352 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -23,6 +23,7 @@
 import android.text.style.MetricAffectingSpan;
 import android.text.style.TabStopSpan;
 import android.util.Log;
+import android.util.Pools.SynchronizedPool;
 
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.GrowingArrayUtils;
@@ -56,28 +57,23 @@
             mNativePtr = nNewBuilder();
         }
 
-        static Builder obtain() {
-            Builder b = null;
-            synchronized (sLock) {
-                for (int i = 0; i < sCached.length; i++) {
-                    if (sCached[i] != null) {
-                        b = sCached[i];
-                        sCached[i] = null;
-                        break;
-                    }
-                }
-            }
+        public static Builder obtain(CharSequence source, int start, int end, int width) {
+            Builder b = sPool.acquire();
             if (b == null) {
                 b = new Builder();
             }
 
             // set default initial values
-            b.mWidth = 0;
+            b.mText = source;
+            b.mStart = start;
+            b.mEnd = end;
+            b.mWidth = width;
+            b.mAlignment = Alignment.ALIGN_NORMAL;
             b.mTextDir = TextDirectionHeuristics.FIRSTSTRONG_LTR;
             b.mSpacingMult = 1.0f;
             b.mSpacingAdd = 0.0f;
             b.mIncludePad = true;
-            b.mEllipsizedWidth = 0;
+            b.mEllipsizedWidth = width;
             b.mEllipsize = null;
             b.mMaxLines = Integer.MAX_VALUE;
 
@@ -85,18 +81,11 @@
             return b;
         }
 
-        static void recycle(Builder b) {
+        private static void recycle(Builder b) {
             b.mPaint = null;
             b.mText = null;
             MeasuredText.recycle(b.mMeasuredText);
-            synchronized (sLock) {
-                for (int i = 0; i < sCached.length; i++) {
-                    if (sCached[i] == null) {
-                        sCached[i] = b;
-                        break;
-                    }
-                }
-            }
+            sPool.release(b);
         }
 
         // release any expensive state
@@ -129,6 +118,11 @@
             return this;
         }
 
+        public Builder setAlignment(Alignment alignment) {
+            mAlignment = alignment;
+            return this;
+        }
+
         public Builder setTextDir(TextDirectionHeuristic textDir) {
             mTextDir = textDir;
             return this;
@@ -166,6 +160,11 @@
             return this;
         }
 
+        public Builder setBreakStrategy(@BreakStrategy int breakStrategy) {
+            mBreakStrategy = breakStrategy;
+            return this;
+        }
+
         /**
          * Measurement and break iteration is done in native code. The protocol for using
          * the native code is as follows.
@@ -207,10 +206,8 @@
         }
 
         public StaticLayout build() {
-            // TODO: can optimize based on whether ellipsis is needed
-            StaticLayout result = new StaticLayout(mText);
-            result.generate(this, this.mIncludePad, this.mIncludePad);
-            recycle(this);
+            StaticLayout result = new StaticLayout(this);
+            Builder.recycle(this);
             return result;
         }
 
@@ -230,6 +227,7 @@
         int mEnd;
         TextPaint mPaint;
         int mWidth;
+        Alignment mAlignment;
         TextDirectionHeuristic mTextDir;
         float mSpacingMult;
         float mSpacingAdd;
@@ -237,6 +235,7 @@
         int mEllipsizedWidth;
         TextUtils.TruncateAt mEllipsize;
         int mMaxLines;
+        int mBreakStrategy;
 
         Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
 
@@ -245,8 +244,7 @@
 
         Locale mLocale;
 
-        private static final Object sLock = new Object();
-        private static final Builder[] sCached = new Builder[3];
+        private static final SynchronizedPool<Builder> sPool = new SynchronizedPool<Builder>(3);
     }
 
     public StaticLayout(CharSequence source, TextPaint paint,
@@ -316,10 +314,9 @@
                     : new Ellipsizer(source),
               paint, outerwidth, align, textDir, spacingmult, spacingadd);
 
-        Builder b = Builder.obtain();
-        b.setText(source, bufstart, bufend)
+        Builder b = Builder.obtain(source, bufstart, bufend, outerwidth)
             .setPaint(paint)
-            .setWidth(outerwidth)
+            .setAlignment(align)
             .setTextDir(textDir)
             .setSpacingMult(spacingmult)
             .setSpacingAdd(spacingadd)
@@ -366,6 +363,35 @@
         mLines = new int[mLineDirections.length];
     }
 
+    private StaticLayout(Builder b) {
+        super((b.mEllipsize == null)
+                ? b.mText
+                : (b.mText instanceof Spanned)
+                    ? new SpannedEllipsizer(b.mText)
+                    : new Ellipsizer(b.mText),
+                b.mPaint, b.mWidth, b.mAlignment, b.mSpacingMult, b.mSpacingAdd);
+
+        if (b.mEllipsize != null) {
+            Ellipsizer e = (Ellipsizer) getText();
+
+            e.mLayout = this;
+            e.mWidth = b.mEllipsizedWidth;
+            e.mMethod = b.mEllipsize;
+            mEllipsizedWidth = b.mEllipsizedWidth;
+
+            mColumns = COLUMNS_ELLIPSIZE;
+        } else {
+            mColumns = COLUMNS_NORMAL;
+            mEllipsizedWidth = b.mWidth;
+        }
+
+        mLineDirections = ArrayUtils.newUnpaddedArray(Directions.class, 2 * mColumns);
+        mLines = new int[mLineDirections.length];
+        mMaximumVisibleLineCount = b.mMaxLines;
+
+        generate(b, b.mIncludePad, b.mIncludePad);
+    }
+
     /* package */ void generate(Builder b, boolean includepad, boolean trackpad) {
         CharSequence source = b.mText;
         int bufStart = b.mStart;
@@ -477,10 +503,9 @@
                 }
             }
 
-            int breakStrategy = 0;  // 0 = kBreakStrategy_Greedy
             nSetupParagraph(b.mNativePtr, chs, paraEnd - paraStart,
                     firstWidth, firstWidthLineCount, restWidth,
-                    variableTabStops, TAB_INCREMENT, breakStrategy);
+                    variableTabStops, TAB_INCREMENT, b.mBreakStrategy);
 
             // measurement has to be done before performing line breaking
             // but we don't want to recompute fontmetrics or span ranges the
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 77082b0..ec527d5 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -1562,7 +1562,7 @@
     }
 
     /**
-     * Sets whether this node is visible to the user.
+     * Gets whether this node is visible to the user.
      *
      * @return Whether the node is visible to the user.
      */
diff --git a/core/java/android/widget/DayPickerView.java b/core/java/android/widget/DayPickerView.java
index e2f8efc..ec2528f 100644
--- a/core/java/android/widget/DayPickerView.java
+++ b/core/java/android/widget/DayPickerView.java
@@ -187,7 +187,6 @@
      * @param setSelected whether to set the specified day as selected
      */
     private void setDate(long timeInMillis, boolean animate, boolean setSelected) {
-        // Set the selected day
         if (setSelected) {
             mSelectedDay.setTimeInMillis(timeInMillis);
         }
@@ -196,6 +195,9 @@
         if (position != getCurrentItem()) {
             setCurrentItem(position, animate);
         }
+
+        mTempCalendar.setTimeInMillis(timeInMillis);
+        mAdapter.setSelectedDay(mTempCalendar);
     }
 
     public long getDate() {
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index 349f3f0..a50941b 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -815,12 +815,12 @@
         mContext = context;
         mIntent = intent;
 
-        mAppWidgetId = intent.getIntExtra(RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID, -1);
-
-        mLayoutInflater = LayoutInflater.from(context);
         if (mIntent == null) {
             throw new IllegalArgumentException("Non-null Intent must be specified.");
         }
+
+        mAppWidgetId = intent.getIntExtra(RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID, -1);
+        mLayoutInflater = LayoutInflater.from(context);
         mRequestedViews = new RemoteViewsFrameLayoutRefSet();
 
         // Strip the previously injected app widget id from service intent
diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java
index 3fb096c6..d9f1f0e 100644
--- a/core/java/android/widget/SimpleMonthView.java
+++ b/core/java/android/widget/SimpleMonthView.java
@@ -80,11 +80,12 @@
     private final SimpleDateFormat mTitleFormatter;
     private final SimpleDateFormat mDayOfWeekFormatter;
 
-    private final int mMonthHeight;
-    private final int mDayOfWeekHeight;
-    private final int mDayHeight;
-    private final int mCellWidth;
-    private final int mDaySelectorRadius;
+    // Desired dimensions.
+    private final int mDesiredMonthHeight;
+    private final int mDesiredDayOfWeekHeight;
+    private final int mDesiredDayHeight;
+    private final int mDesiredCellWidth;
+    private final int mDesiredDaySelectorRadius;
 
     // Next/previous drawables.
     private final Drawable mPrevDrawable;
@@ -99,6 +100,13 @@
     private int mMonth;
     private int mYear;
 
+    // Dimensions as laid out.
+    private int mMonthHeight;
+    private int mDayOfWeekHeight;
+    private int mDayHeight;
+    private int mCellWidth;
+    private int mDaySelectorRadius;
+
     private int mPaddedWidth;
     private int mPaddedHeight;
 
@@ -158,11 +166,11 @@
         super(context, attrs, defStyleAttr, defStyleRes);
 
         final Resources res = context.getResources();
-        mMonthHeight = res.getDimensionPixelSize(R.dimen.date_picker_month_height);
-        mDayOfWeekHeight = res.getDimensionPixelSize(R.dimen.date_picker_day_of_week_height);
-        mDayHeight = res.getDimensionPixelSize(R.dimen.date_picker_day_height);
-        mCellWidth = res.getDimensionPixelSize(R.dimen.date_picker_day_width);
-        mDaySelectorRadius = res.getDimensionPixelSize(R.dimen.date_picker_day_selector_radius);
+        mDesiredMonthHeight = res.getDimensionPixelSize(R.dimen.date_picker_month_height);
+        mDesiredDayOfWeekHeight = res.getDimensionPixelSize(R.dimen.date_picker_day_of_week_height);
+        mDesiredDayHeight = res.getDimensionPixelSize(R.dimen.date_picker_day_height);
+        mDesiredCellWidth = res.getDimensionPixelSize(R.dimen.date_picker_day_width);
+        mDesiredDaySelectorRadius = res.getDimensionPixelSize(R.dimen.date_picker_day_selector_radius);
 
         mPrevDrawable = context.getDrawable(R.drawable.ic_chevron_left);
         mNextDrawable = context.getDrawable(R.drawable.ic_chevron_right);
@@ -400,7 +408,7 @@
         final TextPaint p = mDayOfWeekPaint;
         final int headerHeight = mMonthHeight;
         final int rowHeight = mDayOfWeekHeight;
-        final int colWidth = mPaddedWidth / DAYS_IN_WEEK;
+        final int colWidth = mCellWidth;
 
         // Text is vertically centered within the day of week height.
         final float halfLineHeight = (p.ascent() + p.descent()) / 2f;
@@ -426,7 +434,7 @@
         final TextPaint p = mDayPaint;
         final int headerHeight = mMonthHeight + mDayOfWeekHeight;
         final int rowHeight = mDayHeight;
-        final int colWidth = mPaddedWidth / DAYS_IN_WEEK;
+        final int colWidth = mCellWidth;
 
         // Text is vertically centered within the row height.
         final float halfLineHeight = (p.ascent() + p.descent()) / 2f;
@@ -627,9 +635,9 @@
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        final int preferredHeight = mDayHeight * mNumWeeks + mDayOfWeekHeight + mMonthHeight
-                + getPaddingTop() + getPaddingBottom();
-        final int preferredWidth = mCellWidth * DAYS_IN_WEEK
+        final int preferredHeight = mDesiredDayHeight * mNumWeeks + mDesiredDayOfWeekHeight
+                + mDesiredMonthHeight + getPaddingTop() + getPaddingBottom();
+        final int preferredWidth = mDesiredCellWidth * DAYS_IN_WEEK
                 + getPaddingStart() + getPaddingEnd();
         final int resolvedWidth = resolveSize(preferredWidth, widthMeasureSpec);
         final int resolvedHeight = resolveSize(preferredHeight, heightMeasureSpec);
@@ -637,16 +645,46 @@
     }
 
     @Override
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        final int paddedLeft = getPaddingLeft();
-        final int paddedTop = getPaddingTop();
-        final int paddedRight = w - getPaddingRight();
-        final int paddedBottom = h - getPaddingBottom();
-        mPaddedWidth = paddedRight - paddedLeft;
-        mPaddedHeight = paddedBottom - paddedTop;
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        if (!changed) {
+            return;
+        }
 
-        final int monthHeight = mMonthHeight;
+        // Let's initialize a completely reasonable number of variables.
+        final int w = right - left;
+        final int h = bottom - top;
+        final int paddingLeft = getPaddingLeft();
+        final int paddingTop = getPaddingTop();
+        final int paddingRight = getPaddingRight();
+        final int paddingBottom = getPaddingBottom();
+        final int paddedRight = w - paddingRight;
+        final int paddedBottom = h - paddingBottom;
+        final int paddedWidth = paddedRight - paddingLeft;
+        final int paddedHeight = paddedBottom - paddingTop;
+        if (paddedWidth == mPaddedWidth || paddedHeight == mPaddedHeight) {
+            return;
+        }
+
+        mPaddedWidth = paddedWidth;
+        mPaddedHeight = paddedHeight;
+
+        // We may have been laid out smaller than our preferred size. If so,
+        // scale all dimensions to fit.
+        final int measuredPaddedHeight = getMeasuredHeight() - paddingTop - paddingBottom;
+        final float scaleH = paddedHeight / (float) measuredPaddedHeight;
+        final int monthHeight = (int) (mDesiredMonthHeight * scaleH);
         final int cellWidth = mPaddedWidth / DAYS_IN_WEEK;
+        mMonthHeight = monthHeight;
+        mDayOfWeekHeight = (int) (mDesiredDayOfWeekHeight * scaleH);
+        mDayHeight = (int) (mDesiredDayHeight * scaleH);
+        mCellWidth = cellWidth;
+
+        // Compute the largest day selector radius that's still within the clip
+        // bounds and desired selector radius.
+        final int maxSelectorWidth = cellWidth / 2 + Math.min(paddingLeft, paddingRight);
+        final int maxSelectorHeight = mDayHeight / 2 + paddingBottom;
+        mDaySelectorRadius = Math.min(mDesiredDaySelectorRadius,
+                Math.min(maxSelectorWidth, maxSelectorHeight));
 
         // Vertically center the previous/next drawables within the month
         // header, horizontally center within the day cell, then expand the
@@ -660,7 +698,7 @@
 
             // Button bounds don't include padding, but hit area does.
             prevDrawable.setBounds(iconLeft, iconTop, iconLeft + dW, iconTop + dH);
-            mPrevHitArea.set(0, 0, paddedLeft + cellWidth, paddedTop + monthHeight);
+            mPrevHitArea.set(0, 0, paddingLeft + cellWidth, paddingTop + monthHeight);
         }
 
         final Drawable nextDrawable = mNextDrawable;
@@ -668,11 +706,11 @@
             final int dW = nextDrawable.getIntrinsicWidth();
             final int dH = nextDrawable.getIntrinsicHeight();
             final int iconTop = (monthHeight - dH) / 2;
-            final int iconRight = mPaddedWidth - (cellWidth - dW) / 2;
+            final int iconRight = paddedWidth - (cellWidth - dW) / 2;
 
             // Button bounds don't include padding, but hit area does.
             nextDrawable.setBounds(iconRight - dW, iconTop, iconRight, iconTop + dH);
-            mNextHitArea.set(paddedRight - cellWidth, 0, w, paddedTop + monthHeight);
+            mNextHitArea.set(paddedRight - cellWidth, 0, w, paddingTop + monthHeight);
         }
 
         // Invalidate cached accessibility information.
@@ -753,7 +791,7 @@
 
         // Compute left edge.
         final int col = index % DAYS_IN_WEEK;
-        final int colWidth = mPaddedWidth / DAYS_IN_WEEK;
+        final int colWidth = mCellWidth;
         final int left = getPaddingLeft() + col * colWidth;
 
         // Compute top edge.
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 718ef93..2723080 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -543,6 +543,8 @@
     private float mSpacingMult = 1.0f;
     private float mSpacingAdd = 0.0f;
 
+    private int mBreakStrategy;
+
     private int mMaximum = Integer.MAX_VALUE;
     private int mMaxMode = LINES;
     private int mMinimum = 0;
@@ -680,6 +682,7 @@
         boolean elegant = false;
         float letterSpacing = 0;
         String fontFeatureSettings = null;
+        mBreakStrategy = Layout.BREAK_STRATEGY_SIMPLE;
 
         final Resources.Theme theme = context.getTheme();
 
@@ -1133,6 +1136,9 @@
             case com.android.internal.R.styleable.TextView_fontFeatureSettings:
                 fontFeatureSettings = a.getString(attr);
                 break;
+
+            case com.android.internal.R.styleable.TextView_breakStrategy:
+                mBreakStrategy = a.getInt(attr, Layout.BREAK_STRATEGY_SIMPLE);
             }
         }
         a.recycle();
@@ -2960,6 +2966,35 @@
     }
 
     /**
+     * Sets the break strategy for breaking paragraphs into lines. The default value for
+     * TextView is {@link Layout#BREAK_STRATEGY_HIGH_QUALITY}, and the default value for
+     * EditText is {@link Layout#BREAK_STRATEGY_SIMPLE}, the latter to avoid the
+     * text "dancing" when being edited.
+     *
+     * @attr ref android.R.styleable#TextView_breakStrategy
+     * @see #getBreakStrategy()
+     */
+    public void setBreakStrategy(@Layout.BreakStrategy int breakStrategy) {
+        mBreakStrategy = breakStrategy;
+        if (mLayout != null) {
+            nullLayouts();
+            requestLayout();
+            invalidate();
+        }
+    }
+
+    /**
+     * @return the currently set break strategy.
+     *
+     * @attr ref android.R.styleable#TextView_breakStrategy
+     * @see #setBreakStrategy(int)
+     */
+    @Layout.BreakStrategy
+    public int getBreakStrategy() {
+        return mBreakStrategy;
+    }
+
+    /**
      * Sets font feature settings.  The format is the same as the CSS
      * font-feature-settings attribute:
      * http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings
@@ -6492,27 +6527,25 @@
                                 hintBoring, mIncludePad, mEllipsize,
                                 ellipsisWidth);
                     }
-                } else if (shouldEllipsize) {
-                    mHintLayout = new StaticLayout(mHint,
-                                0, mHint.length(),
-                                mTextPaint, hintWidth, alignment, mTextDir, mSpacingMult,
-                                mSpacingAdd, mIncludePad, mEllipsize,
-                                ellipsisWidth, mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
-                } else {
-                    mHintLayout = new StaticLayout(mHint, mTextPaint,
-                            hintWidth, alignment, mTextDir, mSpacingMult, mSpacingAdd,
-                            mIncludePad);
                 }
-            } else if (shouldEllipsize) {
-                mHintLayout = new StaticLayout(mHint,
-                            0, mHint.length(),
-                            mTextPaint, hintWidth, alignment, mTextDir, mSpacingMult,
-                            mSpacingAdd, mIncludePad, mEllipsize,
-                            ellipsisWidth, mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
-            } else {
-                mHintLayout = new StaticLayout(mHint, mTextPaint,
-                        hintWidth, alignment, mTextDir, mSpacingMult, mSpacingAdd,
-                        mIncludePad);
+            }
+            // TODO: code duplication with makeSingleLayout()
+            if (mHintLayout == null) {
+                StaticLayout.Builder builder = StaticLayout.Builder.obtain(mHint, 0,
+                        mHint.length(), hintWidth)
+                        .setPaint(mTextPaint)
+                        .setAlignment(alignment)
+                        .setTextDir(mTextDir)
+                        .setSpacingMult(mSpacingMult)
+                        .setSpacingAdd(mSpacingAdd)
+                        .setIncludePad(mIncludePad)
+                        .setBreakStrategy(mBreakStrategy);
+                if (shouldEllipsize) {
+                    builder.setEllipsize(mEllipsize)
+                            .setEllipsizedWidth(ellipsisWidth)
+                            .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
+                }
+                mHintLayout = builder.build();
             }
         }
 
@@ -6544,9 +6577,8 @@
         Layout result = null;
         if (mText instanceof Spannable) {
             result = new DynamicLayout(mText, mTransformed, mTextPaint, wantWidth,
-                    alignment, mTextDir, mSpacingMult,
-                    mSpacingAdd, mIncludePad, getKeyListener() == null ? effectiveEllipsize : null,
-                            ellipsisWidth);
+                    alignment, mTextDir, mSpacingMult, mSpacingAdd, mIncludePad, mBreakStrategy,
+                    getKeyListener() == null ? effectiveEllipsize : null, ellipsisWidth);
         } else {
             if (boring == UNKNOWN_BORING) {
                 boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir, mBoring);
@@ -6583,29 +6615,27 @@
                                 boring, mIncludePad, effectiveEllipsize,
                                 ellipsisWidth);
                     }
-                } else if (shouldEllipsize) {
-                    result = new StaticLayout(mTransformed,
-                            0, mTransformed.length(),
-                            mTextPaint, wantWidth, alignment, mTextDir, mSpacingMult,
-                            mSpacingAdd, mIncludePad, effectiveEllipsize,
-                            ellipsisWidth, mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
-                } else {
-                    result = new StaticLayout(mTransformed, mTextPaint,
-                            wantWidth, alignment, mTextDir, mSpacingMult, mSpacingAdd,
-                            mIncludePad);
                 }
-            } else if (shouldEllipsize) {
-                result = new StaticLayout(mTransformed,
-                        0, mTransformed.length(),
-                        mTextPaint, wantWidth, alignment, mTextDir, mSpacingMult,
-                        mSpacingAdd, mIncludePad, effectiveEllipsize,
-                        ellipsisWidth, mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
-            } else {
-                result = new StaticLayout(mTransformed, mTextPaint,
-                        wantWidth, alignment, mTextDir, mSpacingMult, mSpacingAdd,
-                        mIncludePad);
             }
         }
+        if (result == null) {
+            StaticLayout.Builder builder = StaticLayout.Builder.obtain(mTransformed,
+                    0, mTransformed.length(), wantWidth)
+                    .setPaint(mTextPaint)
+                    .setAlignment(alignment)
+                    .setTextDir(mTextDir)
+                    .setSpacingMult(mSpacingMult)
+                    .setSpacingAdd(mSpacingAdd)
+                    .setIncludePad(mIncludePad)
+                    .setBreakStrategy(mBreakStrategy);
+            if (shouldEllipsize) {
+                builder.setEllipsize(effectiveEllipsize)
+                        .setEllipsizedWidth(ellipsisWidth)
+                        .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
+            }
+            // TODO: explore always setting maxLines
+            result = builder.build();
+        }
         return result;
     }
 
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index c58d5cb..2365b48 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -25,8 +25,10 @@
 import android.graphics.drawable.Drawable;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.SpannableStringBuilder;
 import android.text.format.DateFormat;
 import android.text.format.DateUtils;
+import android.text.style.TtsSpan;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.StateSet;
@@ -155,13 +157,16 @@
         mHourView.setMinWidth(computeStableWidth(mHourView, 24));
         mMinuteView.setMinWidth(computeStableWidth(mMinuteView, 60));
 
+        final SpannableStringBuilder amLabel = new SpannableStringBuilder()
+                .append(amPmStrings[0], new TtsSpan.VerbatimBuilder(amPmStrings[0]).build(), 0);
+
         // Set up AM/PM labels.
         mAmPmLayout = mainView.findViewById(R.id.ampm_layout);
         mAmLabel = (CheckedTextView) mAmPmLayout.findViewById(R.id.am_label);
-        mAmLabel.setText(amPmStrings[0]);
+        mAmLabel.setText(obtainVerbatim(amPmStrings[0]));
         mAmLabel.setOnClickListener(mClickListener);
         mPmLabel = (CheckedTextView) mAmPmLayout.findViewById(R.id.pm_label);
-        mPmLabel.setText(amPmStrings[1]);
+        mPmLabel.setText(obtainVerbatim(amPmStrings[1]));
         mPmLabel.setOnClickListener(mClickListener);
 
         // For the sake of backwards compatibility, attempt to extract the text
@@ -220,6 +225,11 @@
         initialize(currentHour, currentMinute, false /* 12h */, HOUR_INDEX);
     }
 
+    private static final CharSequence obtainVerbatim(String text) {
+        return new SpannableStringBuilder().append(text,
+                new TtsSpan.VerbatimBuilder(text).build(), 0);
+    }
+
     /**
      * The legacy text color might have been poorly defined. Ensures that it
      * has an appropriate activated state, using the selected state if one
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 93dc995..05ed3ab 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -104,7 +104,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 122 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 123 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 84568e4..cd117eb1 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -151,7 +151,6 @@
     android_util_FileObserver.cpp \
     android/opengl/poly_clip.cpp.arm \
     android/opengl/util.cpp \
-    android_server_FingerprintManager.cpp \
     android_server_NetworkManagementSocketTagger.cpp \
     android_server_Watchdog.cpp \
     android_ddm_DdmHandleNativeHeap.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index a4c91b3..f1b04a5 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -552,6 +552,7 @@
     char gctypeOptsBuf[sizeof("-Xgc:")-1 + PROPERTY_VALUE_MAX];
     char backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1 + PROPERTY_VALUE_MAX];
     char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX];
+    char cachePruneBuf[sizeof("-Xzygote-max-boot-retry=")-1 + PROPERTY_VALUE_MAX];
     char dex2oatXmsImageFlagsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
     char dex2oatXmxImageFlagsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
     char dex2oatXmsFlagsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
@@ -829,6 +830,10 @@
     snprintf(cpuAbiListBuf, sizeof(cpuAbiListBuf), "--cpu-abilist=%s", propBuf);
     addOption(cpuAbiListBuf);
 
+    // Dalvik-cache pruning counter.
+    parseRuntimeOption("dalvik.vm.zygote.max-boot-retry", cachePruneBuf,
+                       "-Xzygote-max-boot-retry=");
+
     initArgs.version = JNI_VERSION_1_4;
     initArgs.options = mOptions.editArray();
     initArgs.nOptions = mOptions.size();
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 4a98f27..fc05a6d 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -142,7 +142,14 @@
 
 static const char* const kEventHandlerClassPathName =
         "android/media/AudioPortEventHandler";
-static jmethodID gPostEventFromNative;
+static struct {
+    jfieldID    mJniCallback;
+} gEventHandlerFields;
+static struct {
+    jmethodID    postEventFromNative;
+} gAudioPortEventHandlerMethods;
+
+static Mutex gLock;
 
 enum AudioError {
     kAudioStatusOk = 0,
@@ -173,14 +180,14 @@
 private:
     void sendEvent(int event);
 
-    jclass      mClass;     // Reference to AudioPortEventHandlerDelegate class
-    jobject     mObject;    // Weak ref to AudioPortEventHandlerDelegate Java object to call on
+    jclass      mClass;     // Reference to AudioPortEventHandler class
+    jobject     mObject;    // Weak ref to AudioPortEventHandler Java object to call on
 };
 
 JNIAudioPortCallback::JNIAudioPortCallback(JNIEnv* env, jobject thiz, jobject weak_thiz)
 {
 
-    // Hold onto the SoundTriggerModule class for use in calling the static method
+    // Hold onto the AudioPortEventHandler class for use in calling the static method
     // that posts events to the application thread.
     jclass clazz = env->GetObjectClass(thiz);
     if (clazz == NULL) {
@@ -189,7 +196,7 @@
     }
     mClass = (jclass)env->NewGlobalRef(clazz);
 
-    // We use a weak reference so the SoundTriggerModule object can be garbage collected.
+    // We use a weak reference so the AudioPortEventHandler object can be garbage collected.
     // The reference is only used as a proxy for callbacks.
     mObject  = env->NewGlobalRef(weak_thiz);
 }
@@ -211,7 +218,7 @@
     if (env == NULL) {
         return;
     }
-    env->CallStaticVoidMethod(mClass, gPostEventFromNative, mObject,
+    env->CallStaticVoidMethod(mClass, gAudioPortEventHandlerMethods.postEventFromNative, mObject,
                               event, 0, 0, NULL);
     if (env->ExceptionCheck()) {
         ALOGW("An exception occurred while notifying an event.");
@@ -234,6 +241,23 @@
     sendEvent(AUDIOPORT_EVENT_SERVICE_DIED);
 }
 
+static sp<JNIAudioPortCallback> setJniCallback(JNIEnv* env,
+                                       jobject thiz,
+                                       const sp<JNIAudioPortCallback>& callback)
+{
+    Mutex::Autolock l(gLock);
+    sp<JNIAudioPortCallback> old =
+            (JNIAudioPortCallback*)env->GetLongField(thiz, gEventHandlerFields.mJniCallback);
+    if (callback.get()) {
+        callback->incStrong((void*)setJniCallback);
+    }
+    if (old != 0) {
+        old->decStrong((void*)setJniCallback);
+    }
+    env->SetLongField(thiz, gEventHandlerFields.mJniCallback, (jlong)callback.get());
+    return old;
+}
+
 static int check_AudioSystem_Command(status_t status)
 {
     switch (status) {
@@ -1355,7 +1379,9 @@
 
     sp<JNIAudioPortCallback> callback = new JNIAudioPortCallback(env, thiz, weak_this);
 
-    AudioSystem::setAudioPortCallback(callback);
+    if (AudioSystem::addAudioPortCallback(callback) == NO_ERROR) {
+        setJniCallback(env, thiz, callback);
+    }
 }
 
 static void
@@ -1363,9 +1389,11 @@
 {
     ALOGV("eventHandlerFinalize");
 
-    sp<JNIAudioPortCallback> callback;
+    sp<JNIAudioPortCallback> callback = setJniCallback(env, thiz, 0);
 
-    AudioSystem::setAudioPortCallback(callback);
+    if (callback != 0) {
+        AudioSystem::removeAudioPortCallback(callback);
+    }
 }
 
 static jint
@@ -1636,9 +1664,11 @@
                                                 "Landroid/media/AudioHandle;");
 
     jclass eventHandlerClass = FindClassOrDie(env, kEventHandlerClassPathName);
-    gPostEventFromNative = GetStaticMethodIDOrDie(env, eventHandlerClass, "postEventFromNative",
-                                                  "(Ljava/lang/Object;IIILjava/lang/Object;)V");
-
+    gAudioPortEventHandlerMethods.postEventFromNative = GetStaticMethodIDOrDie(
+                                                    env, eventHandlerClass, "postEventFromNative",
+                                                    "(Ljava/lang/Object;IIILjava/lang/Object;)V");
+    gEventHandlerFields.mJniCallback = GetFieldIDOrDie(env,
+                                                    eventHandlerClass, "mJniCallback", "J");
 
     jclass audioMixClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMix");
     gAudioMixClass = MakeGlobalRefOrDie(env, audioMixClass);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 1cb0455..b0771dd 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2601,6 +2601,12 @@
         android:description="@string/permdesc_performCdmaProvisioning"
         android:protectionLevel="signature|system" />
 
+    <!-- @SystemApi Allows an application to perform SIM Activation @hide -->
+    <permission android:name="android.permission.PERFORM_SIM_ACTIVATION"
+        android:label="@string/permlab_performSimActivation"
+        android:description="@string/permdesc_performSimActivation"
+        android:protectionLevel="signature|system" />
+
     <!-- @SystemApi Allows enabling/disabling location update notifications from
          the radio.
          <p>Not for use by third-party applications. -->
diff --git a/core/res/res/values-mcc310-mnc260/strings.xml b/core/res/res/values-mcc310-mnc260/strings.xml
index 75b1b53..dc79877 100644
--- a/core/res/res/values-mcc310-mnc260/strings.xml
+++ b/core/res/res/values-mcc310-mnc260/strings.xml
@@ -25,9 +25,13 @@
     <string-array name="wfcOperatorErrorCodes" translatable="false">
         <item>REG09</item>
     </string-array>
-    <!-- WFC Operator Error Messages -->
-    <string-array name="wfcOperatorErrorMessages">
-        <item>Wi-Fi Calling isn\&apos;t available. Contact your carrier to enable Wi-Fi Calling.</item>
+    <!-- WFC Operator Error Messages showed as alerts -->
+    <string-array name="wfcOperatorErrorAlertMessages">
+        <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
+    </string-array>
+    <!-- WFC Operator Error Messages showed as notifications -->
+    <string-array name="wfcOperatorErrorNotificationMessages">
+        <item>Register with your carrier</item>
     </string-array>
     <!-- Template for showing cellular network operator name while WFC is active -->
     <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index b6d32b2..3945222 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4283,6 +4283,15 @@
         <attr name="letterSpacing" />
         <!-- Font feature settings. -->
         <attr name="fontFeatureSettings" />
+        <!-- Break strategy (control over paragraph layout). -->
+        <attr name="breakStrategy">
+            <!-- Line breaking uses simple strategy. -->
+            <enum name="simple" value="0" />
+            <!-- Line breaking uses high-quality strategy, including hyphenation. -->
+            <enum name="high_quality" value="1" />
+            <!-- Line breaking stratgegy balances line lengths. -->
+            <enum name="balanced" value="2" />
+        </attr>
     </declare-styleable>
     <declare-styleable name="TextViewAppearance">
         <!-- Base text color, typeface, size, and style. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 1b2e952..e879244 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -471,6 +471,18 @@
     <!-- Wifi driver supports batched scan -->
     <bool translatable="false" name="config_wifi_batched_scan_supported">false</bool>
 
+    <!-- Idle Receive current for wifi radio. 0 by default-->
+    <integer translatable="false" name="config_wifi_idle_receive_cur_ma">1</integer>
+
+    <!-- Rx current for wifi radio. 0 by default-->
+    <integer translatable="false" name="config_wifi_active_rx_cur_ma">2</integer>
+
+    <!-- Tx current for wifi radio. 0 by default-->
+    <integer translatable="false" name="config_wifi_tx_cur_ma">3</integer>
+
+    <!-- Operating volatage for wifi radio. 0 by default-->
+    <integer translatable="false" name="config_wifi_operating_voltage_mv">4</integer>
+
     <!-- Flag indicating whether the we should enable the automatic brightness in Settings.
          Software implementation will be used if config_hardware_auto_brightness_available is not set -->
     <bool name="config_automatic_brightness_available">false</bool>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 5c7daf2..f59a4d8 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2656,5 +2656,6 @@
 
   <!--IntentFilter auto verification -->
   <public type="attr" name="autoVerify" />
+  <public type="attr" name="breakStrategy" />
 
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 0a77014..6cd3139 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -249,10 +249,20 @@
     <string name="wfcRegErrorTitle">Wi-Fi Calling</string>
     <!-- WFC Operator Error Codes -->
     <string-array name="wfcOperatorErrorCodes" translatable="false" />
-    <!-- WFC Operator Error Messages -->
-    <string-array name="wfcOperatorErrorMessages" />
+    <!-- WFC Operator Error Messages showed as alerts -->
+    <string-array name="wfcOperatorErrorAlertMessages" />
+    <!-- WFC Operator Error Messages showed as notifications -->
+    <string-array name="wfcOperatorErrorNotificationMessages" />
     <!-- Template for showing cellular network operator name while WFC is active -->
     <string name="wfcSpnFormat">%s</string>
+    <!-- WFC, summary for Disabled -->
+    <string name="wifi_calling_off_summary">Off</string>
+    <!-- WFC, summary for Wi-Fi Preferred -->
+    <string name="wfc_mode_wifi_preferred_summary">Wi-Fi preferred</string>
+    <!-- WFC, summary for Cellular Preferred -->
+    <string name="wfc_mode_cellular_preferred_summary">Cellular preferred</string>
+    <!-- WFC, summary for Wi-Fi Only -->
+    <string name="wfc_mode_wifi_only_summary">Wi-Fi only</string>
 
     <!--
         {0} is one of "bearerServiceCode*"
@@ -1889,6 +1899,10 @@
     <string name="permdesc_performCdmaProvisioning">Allows the app to start CDMA provisioning.
         Malicious apps may unnecessarily start CDMA provisioning.</string>
 
+    <string name="permlab_performSimActivation">start SIM card setup</string>
+    <string name="permdesc_performSimActivation">Allows the app to handle SIM activation requests.
+        The app may directly perform activation or may delegate to another app.</string>
+
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_locationUpdates">control location update notifications</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index cc64b43..3c3d286 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -497,6 +497,7 @@
         <item name="textEditSideNoPasteWindowLayout">?attr/textEditSideNoPasteWindowLayout</item>
         <item name="textEditSuggestionItemLayout">?attr/textEditSuggestionItemLayout</item>
         <item name="textCursorDrawable">?attr/textCursorDrawable</item>
+        <item name="breakStrategy">high_quality</item>
     </style>
 
     <style name="Widget.CheckedTextView">
@@ -527,6 +528,7 @@
         <item name="textAppearance">?attr/textAppearanceMediumInverse</item>
         <item name="textColor">?attr/editTextColor</item>
         <item name="gravity">center_vertical</item>
+        <item name="breakStrategy">simple</item>
     </style>
 
     <style name="Widget.ExpandableListView" parent="Widget.ListView">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 19352c9..220d5e7 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -328,6 +328,10 @@
   <java-symbol type="integer" name="config_wifi_framework_current_network_boost" />
   <java-symbol type="string"  name="config_wifi_random_mac_oui" />
   <java-symbol type="integer"  name="config_wifi_network_switching_blacklist_time" />
+  <java-symbol type="integer"  name="config_wifi_idle_receive_cur_ma" />
+  <java-symbol type="integer"  name="config_wifi_active_rx_cur_ma" />
+  <java-symbol type="integer"  name="config_wifi_tx_cur_ma" />
+  <java-symbol type="integer"  name="config_wifi_operating_voltage_mv" />
 
   <java-symbol type="bool" name="editable_voicemailnumber" />
 
@@ -759,8 +763,13 @@
   <java-symbol type="string" name="phoneTypeWorkPager" />
   <java-symbol type="string" name="wfcRegErrorTitle" />
   <java-symbol type="array" name="wfcOperatorErrorCodes" />
-  <java-symbol type="array" name="wfcOperatorErrorMessages" />
+  <java-symbol type="array" name="wfcOperatorErrorAlertMessages" />
+  <java-symbol type="array" name="wfcOperatorErrorNotificationMessages" />
   <java-symbol type="string" name="wfcSpnFormat" />
+  <java-symbol type="string" name="wifi_calling_off_summary" />
+  <java-symbol type="string" name="wfc_mode_wifi_preferred_summary" />
+  <java-symbol type="string" name="wfc_mode_cellular_preferred_summary" />
+  <java-symbol type="string" name="wfc_mode_wifi_only_summary" />
   <java-symbol type="string" name="policydesc_disableCamera" />
   <java-symbol type="string" name="policydesc_encryptedStorage" />
   <java-symbol type="string" name="policydesc_expirePassword" />
diff --git a/core/tests/coretests/src/android/net/UriTest.java b/core/tests/coretests/src/android/net/UriTest.java
index cd45017..6fa28b1 100644
--- a/core/tests/coretests/src/android/net/UriTest.java
+++ b/core/tests/coretests/src/android/net/UriTest.java
@@ -804,4 +804,56 @@
         assertFalse(Uri.parse("content://com.example/path/path").isPathPrefixMatch(
                 Uri.parse("content://com.example/path%2Fpath")));
     }
+
+    public void testToSafeString() {
+        checkToSafeString("tel:xxxxxx", "tel:Google");
+        checkToSafeString("tel:xxxxxxxxxx", "tel:1234567890");
+        checkToSafeString("tEl:xxx.xxx-xxxx", "tEl:123.456-7890");
+
+        checkToSafeString("sms:xxxxxx", "sms:123abc");
+        checkToSafeString("smS:xxx.xxx-xxxx", "smS:123.456-7890");
+
+        checkToSafeString("smsto:xxxxxx", "smsto:123abc");
+        checkToSafeString("SMSTo:xxx.xxx-xxxx", "SMSTo:123.456-7890");
+
+        checkToSafeString("mailto:xxxxxxx@xxxxxxx.xxx", "mailto:android@android.com");
+        checkToSafeString("Mailto:xxxxxxx@xxxxxxx.xxxxxxxxxx",
+                "Mailto:android@android.com/secret");
+
+        checkToSafeString("sip:xxxxxxx@xxxxxxx.xxxxxxxx", "sip:android@android.com:1234");
+        checkToSafeString("sIp:xxxxxxx@xxxxxxx.xxx", "sIp:android@android.com");
+
+        checkToSafeString("http://www.android.com/...", "http://www.android.com");
+        checkToSafeString("HTTP://www.android.com/...", "HTTP://www.android.com");
+        checkToSafeString("http://www.android.com/...", "http://www.android.com/");
+        checkToSafeString("http://www.android.com/...", "http://www.android.com/secretUrl?param");
+        checkToSafeString("http://www.android.com/...",
+                "http://user:pwd@www.android.com/secretUrl?param");
+        checkToSafeString("http://www.android.com/...",
+                "http://user@www.android.com/secretUrl?param");
+        checkToSafeString("http://www.android.com/...", "http://www.android.com/secretUrl?param");
+        checkToSafeString("http:///...", "http:///path?param");
+        checkToSafeString("http:///...", "http://");
+        checkToSafeString("http://:12345/...", "http://:12345/");
+
+        checkToSafeString("https://www.android.com/...", "https://www.android.com/secretUrl?param");
+        checkToSafeString("https://www.android.com:8443/...",
+                "https://user:pwd@www.android.com:8443/secretUrl?param");
+        checkToSafeString("https://www.android.com/...", "https://user:pwd@www.android.com");
+        checkToSafeString("Https://www.android.com/...", "Https://user:pwd@www.android.com");
+
+        checkToSafeString("ftp://ftp.android.com/...", "ftp://ftp.android.com/");
+        checkToSafeString("ftP://ftp.android.com/...", "ftP://anonymous@ftp.android.com/");
+        checkToSafeString("ftp://ftp.android.com:2121/...",
+                "ftp://root:love@ftp.android.com:2121/");
+
+        checkToSafeString("unsupported://ajkakjah/askdha/secret?secret",
+                "unsupported://ajkakjah/askdha/secret?secret");
+        checkToSafeString("unsupported:ajkakjah/askdha/secret?secret",
+                "unsupported:ajkakjah/askdha/secret?secret");
+    }
+
+    private void checkToSafeString(String expectedSafeString, String original) {
+        assertEquals(expectedSafeString, Uri.parse(original).toSafeString());
+    }
 }
diff --git a/docs/html/google/gcm/c2dm.jd b/docs/html/google/gcm/c2dm.jd
index 6ae7c1a..d0f8c711 100644
--- a/docs/html/google/gcm/c2dm.jd
+++ b/docs/html/google/gcm/c2dm.jd
@@ -33,7 +33,10 @@
 </div>
 </div>
 
-<p>Android Cloud to Device Messaging (C2DM) is deprecated. The C2DM service will continue to be maintained in the short term, but C2DM will accept no new users, and it will grant no new quotas. <strong>C2DM developers are strongly encouraged to move to Google Cloud Messaging (GCM)</strong>. GCM is the next generation of C2DM.</p>
+<p>Android Cloud to Device Messaging (C2DM) was officially deprecated on June 26, 2012, and has been
+ shut down completely as of April 1, 2015.  <strong>C2DM developers are strongly encouraged to move
+  to Google Cloud Messaging (GCM)</strong>. GCM is the next generation of C2DM.</p>
+
 <p>This document is addressed to  C2DM developers who are moving to GCM. It describes the differences between GCM and C2DM, and explains how to migrate existing C2DM apps to GCM.</p>
 
 
diff --git a/docs/html/guide/index.jd b/docs/html/guide/index.jd
index d78a1b1..cb4f65c 100644
--- a/docs/html/guide/index.jd
+++ b/docs/html/guide/index.jd
@@ -30,7 +30,7 @@
 work in the background.</p>
 
 <p>From one component you can start another component using an <em>intent</em>. You can even start
-a component in a different app, such an activity in a maps app to show an address. This model
+a component in a different app, such as an activity in a maps app to show an address. This model
 provides multiple entry points for a single app and allows any app to behave as a user's "default"
 for an action that other apps may invoke.</p>
 
diff --git a/docs/html/images/tv/channel-info.png b/docs/html/images/tv/channel-info.png
new file mode 100644
index 0000000..5a48078
--- /dev/null
+++ b/docs/html/images/tv/channel-info.png
Binary files differ
diff --git a/docs/html/images/tv/do-not-attempt.png b/docs/html/images/tv/do-not-attempt.png
new file mode 100644
index 0000000..18a8775
--- /dev/null
+++ b/docs/html/images/tv/do-not-attempt.png
Binary files differ
diff --git a/docs/html/images/tv/prog-guide.png b/docs/html/images/tv/prog-guide.png
new file mode 100644
index 0000000..caa2278
--- /dev/null
+++ b/docs/html/images/tv/prog-guide.png
Binary files differ
diff --git a/docs/html/images/tv/tvinput-life.png b/docs/html/images/tv/tvinput-life.png
new file mode 100644
index 0000000..fc53f89
--- /dev/null
+++ b/docs/html/images/tv/tvinput-life.png
Binary files differ
diff --git a/docs/html/training/custom-views/optimizing-view.jd b/docs/html/training/custom-views/optimizing-view.jd
index 7f2e762..022618b 100644
--- a/docs/html/training/custom-views/optimizing-view.jd
+++ b/docs/html/training/custom-views/optimizing-view.jd
@@ -12,33 +12,21 @@
     <div id="tb">
 
         <h2>This lesson teaches you to</h2>
-        <ol>
-            <li><a href="#less">Do Less, Less Frequently</a></li>
-            <li><a href="#accelerate">Use Hardware Acceleration</a></li>
-        </ol>
-
-        <h2>You should also read</h2>
         <ul>
-            <li><a href="{@docRoot}guide/topics/graphics/hardware-accel.html">
-                Hardware Acceleration
-            </a>
-        </li>
-    </ul>
-<h2>Try it out</h2>
-<div class="download-box">
-<a href="{@docRoot}shareables/training/CustomView.zip"
-class="button">Download the sample</a>
-<p class="filename">CustomView.zip</p>
-</div>
-</div>
+            <li><a href="#less">Do Less, Less Frequently</a></li>
+        </ul>
+        <h2>Try it out</h2>
+        <div class="download-box">
+            <a href="{@docRoot}shareables/training/CustomView.zip"
+                class="button">Download the sample</a>
+            <p class="filename">CustomView.zip</p>
         </div>
-
+    </div>
+</div>
 
 <p>Now that you have a well-designed view that responds to gestures and transitions between states,
-you need to ensure
-that the view runs fast. To avoid a UI that feels sluggish or stutters during playback, you must
-ensure that your
-animations consistently run at 60 frames per second.</p>
+ensure that the view runs fast. To avoid a UI that feels sluggish or stutters during playback,
+ensure that animations consistently run at 60 frames per second.</p>
 
 <h2 id="less">Do Less, Less Frequently</h2>
 
@@ -52,19 +40,13 @@
 allocation while an
 animation is running.</p>
 
-<p>In addition to making {@link android.view.View#onDraw onDraw()} leaner, you should also make sure
+<p>In addition to making {@link android.view.View#onDraw onDraw()} leaner, also make sure
 it's called as
 infrequently as possible. Most calls to {@link android.view.View#onDraw onDraw()} are the result of
 a call to {@link
 android.view.View#invalidate() invalidate()}, so eliminate unnecessary calls to {@link
 android.view.View#invalidate()
-invalidate()}. When possible, call the four-parameter variant of {@link
-android.view.View#invalidate() invalidate()}
-rather than the version that takes no parameters. The no-parameter variant invalidates the entire
-view, while the
-four-parameter variant invalidates only a specified portion of the view. This approach allows draw calls to
-be more efficient and
-can eliminate unnecessary invalidation of views that fall outside the invalid rectangle.</p>
+invalidate()}.</p>
 
 <p>Another very expensive operation is traversing layouts. Any time a view calls {@link
 android.view.View#requestLayout()
@@ -78,7 +60,7 @@
 as shallow as
 possible.</p>
 
-<p>If you have a complex UI, you should consider writing a custom {@link android.view.ViewGroup
+<p>If you have a complex UI, consider writing a custom {@link android.view.ViewGroup
 ViewGroup} to perform
 its layout. Unlike the built-in views, your custom view can make application-specific assumptions
 about the size and
@@ -88,89 +70,3 @@
 views, but it never
 measures them. Instead, it sets their sizes directly according to its own custom layout
 algorithm.</p>
-
-<h2 id="accelerate">Use Hardware Acceleration</h2>
-
-<p>As of Android 3.0, the Android 2D graphics system can be accelerated by the GPU (Graphics
-Processing Unit) hardware
-found in most newer Android devices. GPU hardware acceleration can result in a tremendous
-performance increase for many
-applications, but it isn't the right choice for every application. The Android framework
-gives you the ability to finely control which parts of your application are or are not
-hardware accelerated.</p>
-
-<p>See <a href="{@docRoot}guide/topics/graphics/hardware-accel.html">Hardware Acceleration</a>
-        in the Android Developers Guide for directions on how to enable acceleration at the
-        application, activity, or window level. Notice  that in addition to the directions in
-        the developer guide, you must also set your application's target API to 11 or higher by
-        specifying {@code &lt;uses-sdk
-        android:targetSdkVersion="11"/&gt;} in your {@code AndroidManifest.xml} file.</p>
-
-<p>Once you've enabled hardware acceleration, you may or may not see a performance increase.
-Mobile GPUs are very good at certain tasks, such as scaling, rotating, and translating
-bitmapped images. They are not particularly good at other tasks, such as drawing lines or curves. To
-get the most out of GPU acceleration, you should maximize the number of operations that the GPU is
-good at, and minimize the number of operations that the GPU isn't good at.</p>
-
-<p>In the PieChart example, for instance, drawing the pie is relatively expensive. Redrawing the pie
-each time it's
-rotated causes the UI to feel sluggish. The solution is to place the pie chart into a child
-{@link android.view.View} and set that
-{@link android.view.View}'s
-<a href="{@docRoot}reference/android/view/View.html#setLayerType(int, android.graphics.Paint)">
-    layer type</a> to {@link android.view.View#LAYER_TYPE_HARDWARE}, so that the GPU can cache it as
-a static
-image. The sample
-defines the child view as an inner class of {@code PieChart}, which minimizes the amount of code
-changes that are needed
-to implement this solution.</p>
-
-<pre>
-   private class PieView extends View {
-
-       public PieView(Context context) {
-           super(context);
-           if (!isInEditMode()) {
-               setLayerType(View.LAYER_TYPE_HARDWARE, null);
-           }
-       }
-       
-       &#64;Override
-       protected void onDraw(Canvas canvas) {
-           super.onDraw(canvas);
-
-           for (Item it : mData) {
-               mPiePaint.setShader(it.mShader);
-               canvas.drawArc(mBounds,
-                       360 - it.mEndAngle,
-                       it.mEndAngle - it.mStartAngle,
-                       true, mPiePaint);
-           }
-       }
-
-       &#64;Override
-       protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-           mBounds = new RectF(0, 0, w, h);
-       }
-
-       RectF mBounds;
-   }
-</pre>
-
-<p>After this code change, {@code PieChart.PieView.onDraw()} is called only when the view is first
-shown. During the rest
-of the application's lifetime, the pie chart is cached as an image, and redrawn at different
-rotation angles by the GPU.
-GPU hardware is particularly good at this sort of thing, and the performance difference is
-immediately noticeable.</p>
-
-<p>There is a tradeoff, though. Caching images as hardware layers consumes video memory, which is a
-limited resource.
-For this reason, the final version of {@code PieChart.PieView} only sets its layer type to
-{@link android.view.View#LAYER_TYPE_HARDWARE}
-while the user is actively scrolling. At all other times, it sets its layer type to
-{@link android.view.View#LAYER_TYPE_NONE}, which
-allows the GPU to stop caching the image.</p>
-
-<p>Finally, don't forget to profile your code. Techniques that improve performance on one view
-might negatively affect performance on another.</p>
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index 11ae1a6..2873b5b3 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -998,10 +998,25 @@
            Building TV Games</a>
       </li>
 
-      <li>
-        <a href="<?cs var:toroot ?>training/tv/tif/index.html"
+      <li class="nav-section">
+        <div class="nav-section-header">
+          <a href="<?cs var:toroot ?>training/tv/tif/index.html"
            description="How to build Live TV apps.">
            Building Live TV Apps</a>
+        </div>
+        <ul>
+          <li>
+            <a href="<?cs var:toroot ?>training/tv/tif/tvinput.html">
+              Developing a TV Input Service</a>
+          <li>
+            <a href="<?cs var:toroot ?>training/tv/tif/channel.html">
+              Working with Channel Data</a>
+          </li>
+          <li>
+            <a href="<?cs var:toroot ?>training/tv/tif/ui.html">
+              Managing User Interaction</a>
+          </li>
+        </ul>
       </li>
 
       <li>
diff --git a/docs/html/training/tv/tif/channel.jd b/docs/html/training/tv/tif/channel.jd
new file mode 100644
index 0000000..999f1ca
--- /dev/null
+++ b/docs/html/training/tv/tif/channel.jd
@@ -0,0 +1,239 @@
+page.title=Working with Channel Data
+page.tags=tv, tif
+helpoutsWidget=true
+
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+  <h2>This lesson teaches you to</h2>
+  <ol>
+    <li><a href="#permission">Get Permission</a></li>
+    <li><a href="#register">Register Channels in the Database</a></li>
+    <li><a href="#update">Update Channel Data</a></li>
+  </ol>
+  <h2>Try It Out</h2>
+  <ul>
+    <li><a class="external-link" href="https://github.com/googlesamples/androidtv-sample-inputs">
+      TV Input Service sample app</a></li>
+  </ul>
+</div>
+</div>
+
+<p>Your TV input must provide Electronic Program Guide (EPG) data for at least one channel in its
+setup activity. You should also periodically update that data, with consideration for the size of
+the update and the processing thread that handles it. This lesson discusses creating and updating
+channel and program data on the system database with these considerations in mind.</p>
+
+<p>&nbsp;</p>
+
+<h2 id="permission">Get Permission</h2>
+
+<p>In order for your TV input to work with EPG data, it must declare the
+read and write permissions in its Android manifest file as follows:</p>
+
+<pre>
+&lt;uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA" /&gt;
+&lt;uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" /&gt;
+</pre>
+
+<h2 id="register">Register Channels in the Database</h2>
+
+<p>The Android TV system database maintains records of channel data for TV inputs. In your setup
+activity, for each of your channels, you must map your channel data to the following fields of the
+{@link android.media.tv.TvContract.Channels} class:</p>
+
+<ul>
+  <li>{@link android.media.tv.TvContract.Channels#COLUMN_DISPLAY_NAME} - the displayed name of the
+  channel</li>
+  <li>{@link android.media.tv.TvContract.Channels#COLUMN_DISPLAY_NUMBER} - the displayed channel
+  number</li>
+  <li>{@link android.media.tv.TvContract.Channels#COLUMN_INPUT_ID} - the ID of the TV input service</li>
+  <li>{@link android.media.tv.TvContract.Channels#COLUMN_SERVICE_TYPE} - the channel's service type</li>
+  <li>{@link android.media.tv.TvContract.Channels#COLUMN_TYPE} - the channel's broadcast standard
+  type</li>
+  <li>{@link android.media.tv.TvContract.Channels#COLUMN_VIDEO_FORMAT} - the default video format
+  for the channel</li>
+</ul>
+
+<p>Although the TV input framework is generic enough to handle both traditional broadcast and
+over-the-top (OTT) content without any distinction, you may want to define the following columns in
+addition to those above to better identify traditional broadcast channels:</p>
+
+<ul>
+  <li>{@link android.media.tv.TvContract.Channels#COLUMN_ORIGINAL_NETWORK_ID} - the television
+  network ID</li>
+  <li>{@link android.media.tv.TvContract.Channels#COLUMN_SERVICE_ID} - the service ID</li>
+  <li>{@link android.media.tv.TvContract.Channels#COLUMN_TRANSPORT_STREAM_ID} - the transport stream
+  ID</li>
+</ul>
+
+<p>For internet streaming based TV inputs, assign your own values to the above accordingly so that
+each channel can be identified uniquely.</p>
+
+<p>Pull your channel metadata (in XML, JSON, or whatever) from your backend server, and in your setup
+activity map the values to the system database as follows:</p>
+
+<pre>
+ContentValues values = new ContentValues();
+
+values.put(Channels.COLUMN_DISPLAY_NUMBER, channel.mNumber);
+values.put(Channels.COLUMN_DISPLAY_NAME, channel.mName);
+values.put(Channels.COLUMN_ORIGINAL_NETWORK_ID, channel.mOriginalNetworkId);
+values.put(Channels.COLUMN_TRANSPORT_STREAM_ID, channel.mTransportStreamId);
+values.put(Channels.COLUMN_SERVICE_ID, channel.mServiceId);
+values.put(Channels.COLUMN_VIDEO_FORMAT, channel.mVideoFormat);
+
+Uri uri = context.getContentResolver().insert(TvContract.Channels.CONTENT_URI, values);
+</pre>
+
+<p>In the example above, <code>channel</code> is an object which holds channel metadata from the
+backend server.</p>
+
+<h3 id="art">Present Channel and Program Information</h2>
+
+<p>The system TV app presents channel and program information to users as they flip through channels,
+as shown in figure 1. To make sure the channel and program information works with the system TV app's
+channel and program information presenter, follow the guidelines below.</p>
+
+<ol>
+<li><strong>Channel number</strong> ({@link android.media.tv.TvContract.Channels#COLUMN_DISPLAY_NUMBER})
+<li><strong>Icon</strong>
+(<a href="guide/topics/manifest/application-element.html#icon"><code>android:icon</code></a> in the
+TV input's manifest)</li>
+<li><strong>Program description</strong> ({@link android.media.tv.TvContract.Programs#COLUMN_SHORT_DESCRIPTION})
+<li><strong>Program title</strong> ({@link android.media.tv.TvContract.Programs#COLUMN_TITLE})</li>
+<li><strong>Channel logo</strong> ({@link android.media.tv.TvContract.Channels.Logo})
+  <ul>
+    <li>Use the color #EEEEEE to match the surrounding text</li>
+    <li>Don't include padding
+  </ul></li>
+<li><strong>Poster art</strong> ({@link android.media.tv.TvContract.Programs#COLUMN_POSTER_ART_URI})
+  <ul>
+    <li>Aspect ratio between 16:9 and 4:3</li>
+  </ul>
+</ol>
+
+<img src="{@docRoot}images/tv/channel-info.png" id="figure1">
+<p class="img-caption">
+  <strong>Figure 1.</strong> The system TV app channel and program information presenter.
+</p>
+
+<p>The system TV app provides the same information through the program guide, including poster art,
+as shown in figure 2.</p>
+
+<img src="{@docRoot}images/tv/prog-guide.png" id="figure2">
+<p class="img-caption">
+  <strong>Figure 2.</strong> The system TV app program guide.
+</p>
+
+<h2 id="update">Update Channel Data</h2>
+
+<p>When updating existing channel data, use the
+{@link android.content.ContentProvider#update(android.net.Uri, android.content.ContentValues,
+java.lang.String, java.lang.String[]) update()}
+method instead of deleting and re-adding the data. You can identify the current version of the data
+by using {@link android.media.tv.TvContract.Channels#COLUMN_VERSION_NUMBER Channels.COLUMN_VERSION_NUMBER}
+and {@link android.media.tv.TvContract.Programs#COLUMN_VERSION_NUMBER Programs.COLUMN_VERSION_NUMBER}
+when choosing the records to update.</p>
+
+<p class="note"><strong>Note:</strong> Adding channel data to the {@link android.content.ContentProvider}
+can take time. Only add current programs (those within two hours of the current time) when you update,
+and use a <a href="{@docRoot}training/sync-adapters/creating-sync-adapter.html">Sync Adapter</a> to
+update the rest of the channel data in the background. See the <a class="external-link" href="https://github.com/googlesamples/androidtv-sample-inputs/blob/master/app/src/main/java/com/example/android/sampletvinput/syncadapter/SyncAdapter.java">
+Android TV Live TV Sample App</a> for an example.</p>
+
+<h3 id="batch">Batch Loading Channel Data</h3>
+
+<p>When updating the system database with a large amount of channel data, use the {@link android.content.ContentResolver}
+{@link android.content.ContentResolver#applyBatch applyBatch()}
+or
+{@link android.content.ContentResolver#bulkInsert(android.net.Uri, android.content.ContentValues[]) bulkInsert()}
+method. Here's an example using {@link android.content.ContentResolver#applyBatch applyBatch()}:<p>
+
+<pre>
+ArrayList&lt;ContentProviderOperation&gt; ops = new ArrayList&lt;&gt;();
+int programsCount = mChannelInfo.mPrograms.size();
+for (int j = 0; j &lt; programsCount; ++j) {
+    ProgramInfo program = mChannelInfo.mPrograms.get(j);
+    ops.add(ContentProviderOperation.newInsert(
+            TvContract.Programs.CONTENT_URI)
+            .withValues(programs.get(j))
+            .withValue(Programs.COLUMN_START_TIME_UTC_MILLIS,
+                    programStartSec * 1000)
+            .withValue(Programs.COLUMN_END_TIME_UTC_MILLIS,
+                    (programStartSec + program.mDurationSec) * 1000)
+            .build());
+    programStartSec = programStartSec + program.mDurationSec;
+    if (j % 100 == 99 || j == programsCount - 1) {
+        try {
+            <strong>getContentResolver().applyBatch(TvContract.AUTHORITY, ops);</strong>
+        } catch (RemoteException | OperationApplicationException e) {
+            Log.e(TAG, "Failed to insert programs.", e);
+            return;
+        }
+        ops.clear();
+    }
+}
+</pre>
+
+<h3 id="async">Processing Channel Data Asynchronously</h3>
+
+<p>Data manipulation, such as fetching a stream from the server or accessing the database, should
+not block the UI thread. Using an {@link android.os.AsyncTask} is one
+way to perform updates asynchronously.  For example, when loading channel info from a backend server,
+you can use {@link android.os.AsyncTask} as follows:</p>
+
+<pre>
+private static class LoadTvInputTask extends AsyncTask&lt;Uri, Void, Void>&gt; {
+
+    private Context mContext;
+
+    public LoadTvInputTask(Context context) {
+        mContext = context;
+    }
+
+    &#64;Override
+    protected Void doInBackground(Uri... uris) {
+        try {
+            fetchUri(uris[0]);
+        } catch (IOException e) {
+          Log.d(“LoadTvInputTask”, “fetchUri error”);
+        }
+        return null;
+    }
+
+    private void fetchUri(Uri videoUri) throws IOException {
+        InputStream inputStream = null;
+        try {
+            inputStream = mContext.getContentResolver().openInputStream(videoUri);
+            XmlPullParser parser = Xml.newPullParser();
+            try {
+                parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
+                parser.setInput(inputStream, null);
+                sTvInput = ChannelXMLParser.parseTvInput(parser);
+                sSampleChannels = ChannelXMLParser.parseChannelXML(parser);
+            } catch (XmlPullParserException e) {
+                e.printStackTrace();
+            }
+        } finally {
+            if (inputStream != null) {
+                inputStream.close();
+            }
+        }
+    }
+}
+</pre>
+
+<p>If you need to update EPG data on a regular basis, consider using
+a <a href="{@docRoot}training/sync-adapters/creating-sync-adapter.html">
+Sync Adapter</a> or {@link android.app.job.JobScheduler} to run the update process during idle time,
+such as every day at 3:00 a.m. See the <a class="external-link" href="https://github.com/googlesamples/androidtv-sample-inputs/blob/master/app/src/main/java/com/example/android/sampletvinput/syncadapter/SyncAdapter.java">
+Android TV live TV sample app</a> for an example.</p>
+
+<p>Other techniques to separate the data update tasks from the UI thread include using the
+{@link android.os.HandlerThread} class, or you may implement your own using {@link android.os.Looper}
+and {@link android.os.Handler} classes.  See <a href="{@docRoot}guide/components/processes-and-threads.html">
+Processes and Threads</a> for more information.</p>
\ No newline at end of file
diff --git a/docs/html/training/tv/tif/index.jd b/docs/html/training/tv/tif/index.jd
index 9c10850..5739294 100644
--- a/docs/html/training/tv/tif/index.jd
+++ b/docs/html/training/tv/tif/index.jd
@@ -1,17 +1,26 @@
 page.title=Building Live TV Apps
 page.tags=tv, tif
 helpoutsWidget=true
-page.article=true
+startpage=true
 
 @jd:body
 
 <div id="tb-wrapper">
 <div id="tb">
+  <h2>Dependencies and Prerequisites</h2>
+  <ul>
+    <li>Android 5.0 (API level 21) or higher</li>
+  </ul>
   <h2>You should also read</h2>
   <ul>
     <li><a href="{@docRoot}reference/android/media/tv/package-summary.html">
       android.media.tv</a></li>
   </ul>
+  <h2>Try It Out</h2>
+  <ul>
+    <li><a class="external-link" href="https://github.com/googlesamples/androidtv-sample-inputs">
+      TV Input Service sample app</a></li>
+  </ul>
 </div>
 </div>
 
@@ -44,6 +53,17 @@
   Building a TV input service for your content can help make it more accessible on TV devices.
 </p>
 
-<p>For more information about TV Input Framework, see the
-<a href="{@docRoot}reference/android/media/tv/package-summary.html">android.media.tv</a>
-reference.</p>
+<h2>Topics</h2>
+
+<dl>
+  <dt><b><a href="tvinput.html">Developing a TV Input Service</a></b></dt>
+    <dd>Learn how to develop a TV input service, which works with the system TV app.</dd>
+
+  <dt><b><a href="channel.html">Working with Channel Data</a></b></dt>
+    <dd>Learn how to describe channel and program data for the system.</dd>
+
+  <dt><b><a href="ui.html">Managing User Interaction</a></b></dt>
+    <dd>Learn how to present overlays, manage content availability, and handle content selection.</dd>
+</dl>
+
+
diff --git a/docs/html/training/tv/tif/tvinput.jd b/docs/html/training/tv/tif/tvinput.jd
new file mode 100644
index 0000000..91f8ded
--- /dev/null
+++ b/docs/html/training/tv/tif/tvinput.jd
@@ -0,0 +1,177 @@
+page.title=Developing a TV Input Service
+page.tags=tv, tif
+helpoutsWidget=true
+
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+  <h2>This lesson teaches you to</h2>
+  <ol>
+    <li><a href="#manifest">Declare Your TV Input Service in the Manifest</a></li>
+    <li><a href="#tvinput">Define Your TV Input Service</a></li>
+    <li><a href="#setup">Define Setup and Settings Activities</a></li>
+  </ol>
+  <h2>You should also read</h2>
+  <ul>
+    <li><a href="{@docRoot}reference/android/media/tv/package-summary.html">
+      android.media.tv</a></li>
+    <li><a class="external-lin" href="http://source.android.com/devices/tv/index.html">
+      TV Input Framework</a></li>
+  </ul>
+  <h2>Try It Out</h2>
+  <ul>
+    <li><a class="external-link" href="https://github.com/googlesamples/androidtv-sample-inputs">
+      TV Input Service sample app</a></li>
+  </ul>
+</div>
+</div>
+
+<p>A TV input service represents a media stream source, and lets you present your media content in a
+linear, broadcast TV fashion as channels and programs. With the TV input service, you can provide
+parental controls, program guide information, and content ratings. The TV input service works
+with the Android system TV app, developed for the device and immutable by third-party apps, which
+ultimately controls and presents content on the TV. See
+<a class="external-link" href="http://source.android.com/devices/tv/index.html">
+TV Input Framework</a> for more information about the framework architecture and its components.</p>
+
+<p>To develop a TV input service, you implement the following components:</p>
+
+<ul>
+  <li>{@link android.media.tv.TvInputService} provides long-running and background availability for
+  the TV input</li>
+  <li>{@link android.media.tv.TvInputService.Session} maintains the TV input state and communicates
+  with the hosting app</li>
+  <li>{@link android.media.tv.TvContract} describes the channels and programs available to the TV
+  input</li>
+  <li>{@link android.media.tv.TvContract.Channels} represents information about a TV channel</li>
+  <li>{@link android.media.tv.TvContract.Programs} describes a TV program with data such as program
+  title and start time</li>
+  <li>{@link android.media.tv.TvTrackInfo} represents an audio, video, or subtitle track</li>
+  <li>{@link android.media.tv.TvContentRating} describes a content rating, allows for custom content
+  rating schemes</li>
+  <li>{@link android.media.tv.TvInputManager} provides an API to the system TV app and manages
+  the interaction with TV inputs and apps</li>
+</ul>
+
+<h2 id="manifest">Declare Your TV Input Service in the Manifest</h2>
+
+<p>Your app manifest must declare your {@link android.media.tv.TvInputService}. Within that
+declaration, specify the {@link android.Manifest.permission#BIND_TV_INPUT} permission to allow the
+service to connect the TV input to the system. A system service (<code>TvInputManagerService</code>)
+performs the binding and has that permission. The system TV app sends requests to TV input services
+via the {@link android.media.tv.TvInputManager} interface. The service declaration must also
+include an intent filter that specifies the {@link android.media.tv.TvInputService}
+as the action to perform with the intent. Also within the service declaration, declare the service
+meta data in a separate XML resource. The service declaration, the intent filter and the service
+meta data are described in the following example.</p>
+
+<pre>
+&lt;service android:name="com.example.sampletvinput.SampleTvInput"
+    android:label="@string/sample_tv_input_label"
+    android:permission="android.permission.BIND_TV_INPUT"&gt;
+    &lt;intent-filter&gt;
+        &lt;action android:name="android.media.tv.TvInputService" /&gt;
+    &lt;/intent-filter&gt;
+    &lt;meta-data android:name="android.media.tv.input"
+      android:resource="@xml/sample_tv_input" /&gt;
+&lt;/service&gt;
+</pre>
+
+<p>Define the service meta data in separate XML file, as shown in the following example. The service
+meta data must include a setup interface that describes the TV input's initial configuration and
+channel scan. Also, the service meta data may (optionally) describe a settings activity for users to
+modify the TV input's behavior. The service meta data file is located in the XML resources directory
+for your application and must match the name of the resource in the manifest. Using the example
+manifest entries above, you would create an XML file in the location
+<code>res/xml/sample_tv_input.xml</code>, with the following contents:</p>
+
+<pre>
+&lt;tv-input xmlns:android="http://schemas.android.com/apk/res/android"
+  &lt;!-- Required: activity for setting up the input --&gt;
+  android:setupActivity="com.example.sampletvinput.SampleTvInputSetupActivity"
+  &lt;!-- Optional: activity for controlling the settings --&gt;
+  android:settingsActivity="com.example.sampletvinput.SampleTvInputSettingsActivity" /&gt;
+</pre>
+
+<h2 id="tvinput">Define Your TV Input Service</h2>
+
+<div class="figure">
+<img id="tvinputlife" src="{@docRoot}images/tv/tvinput-life.png" alt=""/>
+<p class="img-caption"><strong>Figure 1.</strong>TvInputService lifecycle.</p>
+</div>
+
+<p>For your service, you extend the {@link android.media.tv.TvInputService} class. A
+{@link android.media.tv.TvInputService} implementation is a
+<a href="{@docRoot}guide/components/bound-services.html">bound service</a> where the system service
+(<code>TvInputManagerService</code>) is the client that binds to it. The service life cycle methods
+you need to implement are illustrated in figure 1.</p>
+
+<p>The {@link android.app.Service#onCreate()} method initializes and starts the
+{@link android.os.HandlerThread} which provides a process thread separate from the UI thread to
+handle system-driven actions. In the following example, the {@link android.app.Service#onCreate()}
+method initializes the {@link android.view.accessibility.CaptioningManager} and prepares to handle
+the {@link android.media.tv.TvInputManager#ACTION_BLOCKED_RATINGS_CHANGED}
+and {@link android.media.tv.TvInputManager#ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED} actions. These
+actions describe system intents fired when the user changes the parental control settings, and when
+there is a change on the list of blocked ratings.</p>
+
+<pre>
+&#64;Override
+public void onCreate() {
+    super.onCreate();
+    mHandlerThread = new HandlerThread(getClass()
+      .getSimpleName());
+    mHandlerThread.start();
+    mDbHandler = new Handler(mHandlerThread.getLooper());
+    mHandler = new Handler();
+    mCaptioningManager = (CaptioningManager)
+      getSystemService(Context.CAPTIONING_SERVICE);
+
+    setTheme(android.R.style.Theme_Holo_Light_NoActionBar);
+
+    mSessions = new ArrayList&lt;BaseTvInputSessionImpl&gt;();
+    IntentFilter intentFilter = new IntentFilter();
+    intentFilter.addAction(TvInputManager
+      .ACTION_BLOCKED_RATINGS_CHANGED);
+    intentFilter.addAction(TvInputManager
+      .ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED);
+    registerReceiver(mBroadcastReceiver, intentFilter);
+}
+</pre>
+
+<p> See <a href="{@docRoot}training/tv/tif/ui.html#control">
+Control Content</a> for more information about working with blocked content and providing
+parental control. See {@link android.media.tv.TvInputManager} for more system-driven actions that
+you may want to handle in your TV input service.</p>
+
+<p>The {@link android.media.tv.TvInputService} creates a
+{@link android.media.tv.TvInputService.Session} that implements {@link android.os.Handler.Callback}
+to handle player state changes. With {@link android.media.tv.TvInputService.Session#onSetSurface(android.view.Surface) onSetSurface()},
+the {@link android.media.tv.TvInputService.Session} sets the {@link android.view.Surface} with the
+video content. See <a href="{@docRoot}training/tv/tif/ui.html#surface">Integrate Player with Surface</a>
+for more information about working with {@link android.view.Surface} to render video.</p>
+
+<p>The {@link android.media.tv.TvInputService.Session} handles the
+{@link android.media.tv.TvInputService.Session#onTune(android.net.Uri) onTune()}
+event when the user selects a channel, and notifies the system TV app for changes in the content and
+content meta data. These <code>notify()</code>code> methods are described in
+<a href="{@docRoot}training/tv/tif/ui.html#control">
+Control Content</a> and <a href="training/tv/tif/ui.html#track">Handle Track Selection</a> further
+in this training.</p>
+
+<h2 id="setup">Define Setup and Settings Activities</h2>
+
+<p>The system TV app works with the setup and settings activities you define for your TV input. The
+setup activity is required and must provide at least one channel record for the system database. The
+system TV app will invoke the setup activity when it cannot find a channel for the TV input.
+<p>The setup activity describes to the system TV app the channels made available through the TV
+input, as demonstrated in the next lesson, <a href="{@docRoot}training/tv/tif/channel.html">Creating
+and Updating Channel Data</a>.</p>
+
+<p>The settings activity is optional. You can define a settings activity to turn on parental
+controls, enable closed captions, set the display attributes, and so forth.</p>
+
+
diff --git a/docs/html/training/tv/tif/ui.jd b/docs/html/training/tv/tif/ui.jd
new file mode 100644
index 0000000..6ead3db
--- /dev/null
+++ b/docs/html/training/tv/tif/ui.jd
@@ -0,0 +1,304 @@
+page.title=Managing User Interaction
+page.tags=tv, tif
+helpoutsWidget=true
+
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+  <h2>This lesson teaches you to</h2>
+  <ol>
+    <li><a href="#surface">Integrate Player with Surface</a></li>
+    <li><a href="#overlay">Use an Overlay</a></li>
+    <li><a href="#control">Control Content</a></li>
+    <li><a href="#track">Handle Track Selection</a></li>
+  </ol>
+  <h2>Try It Out</h2>
+  <ul>
+    <li><a class="external-link" href="https://github.com/googlesamples/androidtv-sample-inputs">
+      TV Input Service sample app</a></li>
+  </ul>
+</div>
+</div>
+
+<p>In the live TV experience the user changes channels and is presented with
+channel and program information briefly before the information disappears. Other types of information,
+such as messages ("DO NOT ATTEMPT AT HOME"), subtitles, or ads may need to persist. As with any TV
+app, such information should not interfere with the program content playing on the screen.</p>
+
+<img src="{@docRoot}images/tv/do-not-attempt.png" id="figure1">
+<p class="img-caption">
+  <strong>Figure 1.</strong> An overlay message in a live TV app.
+</p>
+
+<p>Also consider whether certain program content should be presented, given the
+content's rating and parental control settings, and how your app behaves and informs the user when
+content is blocked or unavailable. This lesson describes how to develop your TV input's user
+experience for these considerations.</p>
+
+<h2 id="surface">Integrate Player with Surface</h2>
+
+<p>Your TV input must render video onto a {@link android.view.Surface} object, which is passed by
+the {@link android.media.tv.TvInputService.Session#onSetSurface(android.view.Surface) TvInputService.Session.onSetSurface()}
+method. Here's an example of how to use a {@link android.media.MediaPlayer} instance for playing
+content in the {@link android.view.Surface} object:</p>
+
+<pre>
+&#64;Override
+public boolean onSetSurface(Surface surface) {
+    if (mPlayer != null) {
+        mPlayer.setSurface(surface);
+    }
+    mSurface = surface;
+    return true;
+}
+
+&#64;Override
+public void onSetStreamVolume(float volume) {
+    if (mPlayer != null) {
+        mPlayer.setVolume(volume, volume);
+    }
+    mVolume = volume;
+}
+</pre>
+
+<p>Similarly, here's how to do it using <a href="{@docRoot}guide/topics/media/exoplayer.html">
+ExoPlayer</a>:</p>
+
+<pre>
+&#64;Override
+public boolean onSetSurface(Surface surface) {
+    if (mPlayer != null) {
+        mPlayer.sendMessage(mVideoRenderer,
+                MediaCodecVideoTrackRenderer.MSG_SET_SURFACE,
+                surface);
+    }
+    mSurface = surface;
+    return true;
+}
+
+&#64;Override
+public void onSetStreamVolume(float volume) {
+    if (mPlayer != null) {
+        mPlayer.sendMessage(mAudioRenderer,
+                MediaCodecAudioTrackRenderer.MSG_SET_VOLUME,
+                volume);
+    }
+    mVolume = volume;
+}
+</pre>
+
+<h2 id="overlay">Use an Overlay</h2>
+
+<p>Use an overlay to display subtitles, messages, ads or MHEG-5 data broadcasts. By default, the
+overlay is disabled. You can enable it when you create the session by calling
+{@link android.media.tv.TvInputService.Session#setOverlayViewEnabled(boolean) TvInputService.Session.setOverlayViewEnabled(true)},
+as in the following example:</p>
+
+<pre>
+&#64;Override
+public final Session onCreateSession(String inputId) {
+    BaseTvInputSessionImpl session = onCreateSessionInternal(inputId);
+    session.setOverlayViewEnabled(true);
+    mSessions.add(session);
+    return session;
+}
+</pre>
+
+<p>Use a {@link android.view.View} object for the overlay, returned from {@link android.media.tv.TvInputService.Session#onCreateOverlayView() TvInputService.Session.onCreateOverlayView()}, as shown here:</p>
+
+<pre>
+&#64;Override
+public View onCreateOverlayView() {
+    LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
+    View view = inflater.inflate(R.layout.overlayview, null);
+    mSubtitleView = (SubtitleView) view.findViewById(R.id.subtitles);
+
+    // Configure the subtitle view.
+    CaptionStyleCompat captionStyle;
+    float captionTextSize = getCaptionFontSize();
+    captionStyle = CaptionStyleCompat.createFromCaptionStyle(
+            mCaptioningManager.getUserStyle());
+    captionTextSize *= mCaptioningManager.getFontScale();
+    mSubtitleView.setStyle(captionStyle);
+    mSubtitleView.setTextSize(captionTextSize);
+    return view;
+}
+</pre>
+
+<p>The layout definition for the overlay might look something like this:</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"&gt;
+
+    &lt;com.google.android.exoplayer.text.SubtitleView
+        android:id="@+id/subtitles"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="bottom|center_horizontal"
+        android:layout_marginLeft="16dp"
+        android:layout_marginRight="16dp"
+        android:layout_marginBottom="32dp"
+        android:visibility="invisible"/&gt;
+&lt;/FrameLayout&gt;
+</pre>
+
+<h2 id="control">Control Content</h2>
+
+<p>When the user selects a channel, your TV input handles the {@link android.media.tv.TvInputService.Session#onTune(android.net.Uri)
+onTune()} callback in the {@link android.media.tv.TvInputService.Session} object. The system TV
+app's parental controls determine what content displays, given the content rating.
+The following sections describe how to manage channel and program selection using the
+{@link android.media.tv.TvInputService.Session} <code>notify</code> methods that
+communicate with the system TV app.</p>
+
+<h3 id="unavailable">Make Video Unavailable</h3>
+
+<p>When the user changes the channel, you want to make sure the screen doesn't display any stray
+video artifacts before your TV input renders the content. When you call {@link android.media.tv.TvInputService.Session#onTune(android.net.Uri) TvInputService.Session.onTune()},
+you can prevent the video from being presented by calling {@link android.media.tv.TvInputService.Session#notifyVideoUnavailable(int) TvInputService.Session.notifyVideoUnavailable()}
+and passing the {@link android.media.tv.TvInputManager#VIDEO_UNAVAILABLE_REASON_TUNING} constant, as
+shown in the following example.</p>
+
+<pre>
+&#64;Override
+public boolean onTune(Uri channelUri) {
+    if (mSubtitleView != null) {
+        mSubtitleView.setVisibility(View.INVISIBLE);
+    }
+    notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_TUNING);
+    mUnblockedRatingSet.clear();
+
+    mDbHandler.removeCallbacks(mPlayCurrentProgramRunnable);
+    mPlayCurrentProgramRunnable = new PlayCurrentProgramRunnable(channelUri);
+    mDbHandler.post(mPlayCurrentProgramRunnable);
+    return true;
+}
+</pre>
+
+<p>Then, when the content is rendered to the {@link android.view.Surface}, you call
+{@link android.media.tv.TvInputService.Session#notifyVideoAvailable() TvInputService.Session.notifyVideoAvailable()}
+to allow the video to display, like so:</p>
+
+<pre>
+&#64;Override
+public void onDrawnToSurface(Surface surface) {
+    mFirstFrameDrawn = true;
+    notifyVideoAvailable();
+}
+</pre>
+
+<p>This transition lasts only for fractions of a second, but presenting a blank screen is
+visually better than allowing the picture to flash odd blips and jitters.</p>
+
+<p>See also, <a href="#surface">Integrate Player with Surface</a> for more information about working
+with {@link android.view.Surface} to render video.</p>
+
+<h3 id="parental">Provide Parental Control</h3>
+
+<p>To determine if a given content is blocked by parental controls and content rating, you check the
+{@link android.media.tv.TvInputManager} class methods, {@link android.media.tv.TvInputManager#isParentalControlsEnabled()}
+and {@link android.media.tv.TvInputManager#isRatingBlocked(android.media.tv.TvContentRating)}. You
+might also want to make sure the content's {@link android.media.tv.TvContentRating} is included in a
+set of currently allowed content ratings. These considerations are shown in the following sample.</p>
+
+<pre>
+private void checkContentBlockNeeded() {
+    if (mCurrentContentRating == null || !mTvInputManager.isParentalControlsEnabled()
+            || !mTvInputManager.isRatingBlocked(mCurrentContentRating)
+            || mUnblockedRatingSet.contains(mCurrentContentRating)) {
+        // Content rating is changed so we don't need to block anymore.
+        // Unblock content here explicitly to resume playback.
+        unblockContent(null);
+        return;
+    }
+
+    mLastBlockedRating = mCurrentContentRating;
+    if (mPlayer != null) {
+        // Children restricted content might be blocked by TV app as well,
+        // but TIF should do its best not to show any single frame of blocked content.
+        releasePlayer();
+    }
+
+    notifyContentBlocked(mCurrentContentRating);
+}
+</pre>
+
+<p>Once you have determined if the content should or should not be blocked, notify the system TV
+app by calling the
+{@link android.media.tv.TvInputService.Session} method {@link android.media.tv.TvInputService.Session#notifyContentAllowed() notifyContentAllowed()}
+or
+{@link android.media.tv.TvInputService.Session#notifyContentBlocked(android.media.tv.TvContentRating) notifyContentBlocked()}
+, as shown in the previous example.</p>
+
+<p>Use the {@link android.media.tv.TvContentRating} class to generate the system-defined string for
+the {@link android.media.tv.TvContract.Programs#COLUMN_CONTENT_RATING} with the
+<code><a href="{@docRoot}reference/android/media/tv/TvContentRating.html#createRating(java.lang.String, java.lang.String, java.lang.String, java.lang.String...)">TvContentRating.createRating()</a></code>
+method, as shown here:</p>
+
+<pre>
+TvContentRating rating = TvContentRating.createRating(
+    "com.android.tv",
+    "US_TV",
+    "US_TV_PG",
+    "US_TV_D", "US_TV_L");
+</pre>
+
+<h2 id="track">Handle Track Selection</h2>
+
+<p>The {@link android.media.tv.TvTrackInfo} class holds information about media tracks such
+as the track type (video, audio, or subtitle) and so forth. </p>
+
+<p>The first time your TV input session is able to get track information, it should call
+<code><a href="{@docRoot}reference/android/media/tv/TvInputService.Session.html#notifyTracksChanged(java.util.List<android.media.tv.TvTrackInfo>)">TvInputService.Session.notifyTracksChanged()</a></code> with a list of all tracks to update the system TV app.  When there
+is a change in track information, call
+<code><a href="{@docRoot}reference/android/media/tv/TvInputService.Session.html#notifyTracksChanged(java.util.List<android.media.tv.TvTrackInfo>)">notifyTracksChanged()</a></code>
+again to update the system.
+
+</p>
+
+<p>The system TV app provides an interface for the user to select a specific track if more than one
+track is available for a given track type; for example, subtitles in different languages. Your TV
+input responds to the
+{@link android.media.tv.TvInputService.Session#onSelectTrack(int, java.lang.String) onSelectTrack()}
+call from the system TV app by calling
+{@link android.media.tv.TvInputService.Session#notifyTrackSelected(int, java.lang.String) notifyTrackSelected()}
+, as shown in the following example. Note that when <code>null</code>
+is passed as the track ID, this <em>deselects</em> the track.</p>
+
+<pre>
+&#64;Override
+public boolean onSelectTrack(int type, String trackId) {
+    if (mPlayer != null) {
+        if (type == TvTrackInfo.TYPE_SUBTITLE) {
+            if (!mCaptionEnabled && trackId != null) {
+                return false;
+            }
+            mSelectedSubtitleTrackId = trackId;
+            if (trackId == null) {
+                mSubtitleView.setVisibility(View.INVISIBLE);
+            }
+        }
+        if (mPlayer.selectTrack(type, trackId)) {
+            notifyTrackSelected(type, trackId);
+            return true;
+        }
+    }
+    return false;
+}
+</pre>
+
+
+
+
+
+
+
diff --git a/docs/html/training/wearables/apps/voice.jd b/docs/html/training/wearables/apps/voice.jd
index 6d49319..3aef3c4 100644
--- a/docs/html/training/wearables/apps/voice.jd
+++ b/docs/html/training/wearables/apps/voice.jd
@@ -131,6 +131,17 @@
   </tr>
 
   <tr>
+    <td>Start stopwatch</td>
+    <td>"Ok Google, start stopwatch"</td>
+    <td>
+      <dl>
+        <dt>Action</dt>
+        <dd><code>com.google.android.wearable.action.STOPWATCH</code></dd>
+      </dl>
+   </td>
+  </tr>
+
+  <tr>
     <td>Start/Stop a bike ride</td>
     <td>"OK Google, start cycling"<br/><br/>"OK Google, start my bike ride"<br/><br/>"OK Google, stop cycling"</td>
     <td>
diff --git a/docs/html/training/wearables/watch-faces/drawing.jd b/docs/html/training/wearables/watch-faces/drawing.jd
index 3c5da34..60da5d5 100644
--- a/docs/html/training/wearables/watch-faces/drawing.jd
+++ b/docs/html/training/wearables/watch-faces/drawing.jd
@@ -377,7 +377,8 @@
 
 <ul>
 <li>For devices that use low-bit ambient mode, the screen supports fewer bits for each color
-in ambient mode, so you should disable anti-aliasing.</li>
+in ambient mode, so you should disable anti-aliasing and bitmap filtering when the device switches
+to ambient mode.</li>
 <li>For devices that require burn-in protection, avoid using large blocks of white pixels in
 ambient mode and do not place content within 10 pixels of the edge of the screen, since the
 system shifts the content periodically to avoid pixel burn-in.</li>
@@ -385,7 +386,9 @@
 
 <p>For more information about low-bit ambient mode and burn-in protection, see
 <a href="{@docRoot}design/wear/watchfaces.html#SpecialScreens">Optimize for Special
-Screens</a>.</p>
+Screens</a>. For more information on how to disable bitmap filtering, see
+<a href="{@docRoot}training/wearables/watch-faces/performance.html#BitmapFiltering">Bitmap
+Filtering</a>.</p>
 
 
 <h2 id="Modes">Respond to Changes Between Modes</h2>
diff --git a/docs/html/training/wearables/watch-faces/performance.jd b/docs/html/training/wearables/watch-faces/performance.jd
index 68438fe..118bc6a0 100644
--- a/docs/html/training/wearables/watch-faces/performance.jd
+++ b/docs/html/training/wearables/watch-faces/performance.jd
@@ -99,7 +99,9 @@
 setFilterBitmap()} method. <a href="#fig2">Figure 2</a> shows a magnified view of a clock hand with
 and without bitmap filtering.</p>
 
-
+<p class="note"><strong>Note:</strong> In low-bit ambient mode, the system does not reliably
+render the colors in the image for bitmap filtering to process successfully. When ambient mode is
+active, disable bitmap filtering.</p>
 
 <h2 id="OutDrawing">Move Expensive Operations Outside the Drawing Method</h2>
 
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 1da198c..d3cb9b1 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -2120,9 +2120,9 @@
         int contextLen = contextEnd - contextStart;
         char[] buf = TemporaryBuffer.obtain(contextLen);
         TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
-        int result = getTextRunCursor(buf, 0, contextLen, dir, offset - contextStart, cursorOpt);
+        int relPos = getTextRunCursor(buf, 0, contextLen, dir, offset - contextStart, cursorOpt);
         TemporaryBuffer.recycle(buf);
-        return result;
+        return (relPos == -1) ? -1 : relPos + contextStart;
     }
 
     /**
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 56876e94..e8b8c77 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -816,9 +816,12 @@
      * returned.  You can use the method {@link #resolveOpacity} to perform a
      * standard reduction of two opacities to the appropriate single output.
      *
-     * <p>Note that the returned value does <em>not</em> take into account a
+     * <p>Note that the returned value does not necessarily take into account a
      * custom alpha or color filter that has been applied by the client through
-     * the {@link #setAlpha} or {@link #setColorFilter} methods.
+     * the {@link #setAlpha} or {@link #setColorFilter} methods. Some subclasses,
+     * such as {@link BitmapDrawable}, {@link ColorDrawable}, and {@link GradientDrawable},
+     * do account for the value of {@link #setAlpha}, but the general behavior is dependent
+     * upon the implementation of the subclass.
      *
      * @return int The opacity class of the Drawable.
      *
diff --git a/keystore/java/android/security/AndroidKeyStore.java b/keystore/java/android/security/AndroidKeyStore.java
index 846d1f1..0bd1dbd 100644
--- a/keystore/java/android/security/AndroidKeyStore.java
+++ b/keystore/java/android/security/AndroidKeyStore.java
@@ -536,26 +536,27 @@
         if (params.getUserAuthenticators().isEmpty()) {
             args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
         } else {
-        // TODO: Pass-in user authenticator IDs once the Keymaster API has stabilized
-//            for (int userAuthenticatorId : params.getUserAuthenticators()) {
-//                args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_ID, userAuthenticatorId);
-//            }
+            args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
+                    KeyStoreKeyConstraints.UserAuthenticator.allToKeymaster(
+                            params.getUserAuthenticators()));
+        }
+        if (params.isInvalidatedOnNewFingerprintEnrolled()) {
+            // TODO: Add the invalidate on fingerprint enrolled constraint once Keymaster supports
+            // that.
         }
         if (params.getUserAuthenticationValidityDurationSeconds() != null) {
             args.addInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
                     params.getUserAuthenticationValidityDurationSeconds());
         }
-        if (params.getKeyValidityStart() != null) {
-            args.addDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, params.getKeyValidityStart());
-        }
-        if (params.getKeyValidityForOriginationEnd() != null) {
-            args.addDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
-                    params.getKeyValidityForOriginationEnd());
-        }
-        if (params.getKeyValidityForConsumptionEnd() != null) {
-            args.addDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
-                    params.getKeyValidityForConsumptionEnd());
-        }
+        args.addDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
+                (params.getKeyValidityStart() != null)
+                        ? params.getKeyValidityStart() : new Date(0));
+        args.addDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
+                (params.getKeyValidityForOriginationEnd() != null)
+                        ? params.getKeyValidityForOriginationEnd() : new Date(Long.MAX_VALUE));
+        args.addDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
+                (params.getKeyValidityForConsumptionEnd() != null)
+                        ? params.getKeyValidityForConsumptionEnd() : new Date(Long.MAX_VALUE));
 
         // TODO: Remove this once keymaster does not require us to specify the size of imported key.
         args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, keyMaterial.length * 8);
diff --git a/keystore/java/android/security/AndroidKeyStoreProvider.java b/keystore/java/android/security/AndroidKeyStoreProvider.java
index 39f9d9c..a7c2ddb 100644
--- a/keystore/java/android/security/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/AndroidKeyStoreProvider.java
@@ -16,8 +16,12 @@
 
 package android.security;
 
+import java.lang.reflect.Method;
 import java.security.Provider;
 
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+
 /**
  * A provider focused on providing JCA interfaces for the Android KeyStore.
  *
@@ -71,4 +75,42 @@
         put("Cipher." + transformation, implClass);
         put("Cipher." + transformation + " SupportedKeyClasses", KeyStoreSecretKey.class.getName());
     }
+
+    /**
+     * Gets the {@link KeyStore} operation handle corresponding to the provided JCA crypto
+     * primitive.
+     *
+     * <p>The following primitives are supported: {@link Cipher} and {@link Mac}.
+     *
+     * @return KeyStore operation handle or {@code null} if the provided primitive's KeyStore
+     *         operation is not in progress.
+     *
+     * @throws IllegalArgumentException if the provided primitive is not supported or is not backed
+     *         by AndroidKeyStore provider.
+     */
+    public static Long getKeyStoreOperationHandle(Object cryptoPrimitive) {
+        if (cryptoPrimitive == null) {
+            throw new NullPointerException();
+        }
+        if ((!(cryptoPrimitive instanceof Mac)) && (!(cryptoPrimitive instanceof Cipher))) {
+            throw new IllegalArgumentException("Unsupported crypto primitive: " + cryptoPrimitive);
+        }
+        Object spi;
+        // TODO: Replace this Reflection based codewith direct invocations once the libcore changes
+        // are in.
+        try {
+            Method getSpiMethod = cryptoPrimitive.getClass().getDeclaredMethod("getSpi");
+            getSpiMethod.setAccessible(true);
+            spi = getSpiMethod.invoke(cryptoPrimitive);
+        } catch (ReflectiveOperationException e) {
+            throw new IllegalArgumentException(
+                    "Unsupported crypto primitive: " + cryptoPrimitive, e);
+        }
+        if (!(spi instanceof KeyStoreCryptoOperation)) {
+            throw new IllegalArgumentException(
+                    "Crypto primitive not backed by Android KeyStore: " + cryptoPrimitive
+                    + ", spi: " + spi);
+        }
+        return ((KeyStoreCryptoOperation) spi).getOperationHandle();
+    }
 }
diff --git a/keystore/java/android/security/KeyGeneratorSpec.java b/keystore/java/android/security/KeyGeneratorSpec.java
index 9122d8e..02b0816 100644
--- a/keystore/java/android/security/KeyGeneratorSpec.java
+++ b/keystore/java/android/security/KeyGeneratorSpec.java
@@ -59,6 +59,7 @@
     private final Integer mMaxUsesPerBoot;
     private final Set<Integer> mUserAuthenticators;
     private final Integer mUserAuthenticationValidityDurationSeconds;
+    private final boolean mInvalidatedOnNewFingerprintEnrolled;
 
     private KeyGeneratorSpec(
             Context context,
@@ -74,7 +75,8 @@
             Integer minSecondsBetweenOperations,
             Integer maxUsesPerBoot,
             Set<Integer> userAuthenticators,
-            Integer userAuthenticationValidityDurationSeconds) {
+            Integer userAuthenticationValidityDurationSeconds,
+            boolean invalidatedOnNewFingerprintEnrolled) {
         if (context == null) {
             throw new IllegalArgumentException("context == null");
         } else if (TextUtils.isEmpty(keyStoreAlias)) {
@@ -101,6 +103,7 @@
                 ? new HashSet<Integer>(userAuthenticators)
                 : Collections.<Integer>emptySet();
         mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
+        mInvalidatedOnNewFingerprintEnrolled = invalidatedOnNewFingerprintEnrolled;
     }
 
     /**
@@ -239,6 +242,19 @@
     }
 
     /**
+     * Returns {@code true} if this key must be permanently invalidated once a new fingerprint is
+     * enrolled. This constraint only has effect if fingerprint reader is one of the user
+     * authenticators protecting access to this key.
+     *
+     * @see #getUserAuthenticators()
+     *
+     * @hide
+     */
+    public boolean isInvalidatedOnNewFingerprintEnrolled() {
+        return mInvalidatedOnNewFingerprintEnrolled;
+    }
+
+    /**
      * Returns {@code true} if the key must be encrypted in the {@link java.security.KeyStore}.
      */
     public boolean isEncryptionRequired() {
@@ -260,6 +276,7 @@
         private Integer mMaxUsesPerBoot;
         private Set<Integer> mUserAuthenticators;
         private Integer mUserAuthenticationValidityDurationSeconds;
+        private boolean mInvalidatedOnNewFingerprintEnrolled;
 
         /**
          * Creates a new instance of the {@code Builder} with the given {@code context}. The
@@ -473,6 +490,22 @@
         }
 
         /**
+         * Sets whether this key must be invalidated (permanently) once a new fingerprint is
+         * enrolled. This only has effect if fingerprint reader is one of the user authenticators
+         * protecting access to the key.
+         *
+         * <p>By default, enrolling a new fingerprint does not invalidate the key.
+         *
+         * @see #setUserAuthenticators(Set)
+         *
+         * @hide
+         */
+        public Builder setInvalidatedOnNewFingerprintEnrolled(boolean invalidated) {
+            mInvalidatedOnNewFingerprintEnrolled = invalidated;
+            return this;
+        }
+
+        /**
          * Builds a new instance instance of {@code KeyGeneratorSpec}.
          *
          * @throws IllegalArgumentException if a required field is missing or violates a constraint.
@@ -481,7 +514,8 @@
             return new KeyGeneratorSpec(mContext, mKeystoreAlias, mFlags, mKeySize,
                     mKeyValidityStart, mKeyValidityForOriginationEnd, mKeyValidityForConsumptionEnd,
                     mPurposes, mPadding, mBlockMode, mMinSecondsBetweenOperations, mMaxUsesPerBoot,
-                    mUserAuthenticators, mUserAuthenticationValidityDurationSeconds);
+                    mUserAuthenticators, mUserAuthenticationValidityDurationSeconds,
+                    mInvalidatedOnNewFingerprintEnrolled);
         }
     }
 }
diff --git a/keystore/java/android/security/KeyStoreCipherSpi.java b/keystore/java/android/security/KeyStoreCipherSpi.java
index 87f0d8e..5219086 100644
--- a/keystore/java/android/security/KeyStoreCipherSpi.java
+++ b/keystore/java/android/security/KeyStoreCipherSpi.java
@@ -45,7 +45,7 @@
  *
  * @hide
  */
-public abstract class KeyStoreCipherSpi extends CipherSpi {
+public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCryptoOperation {
 
     public abstract static class AES extends KeyStoreCipherSpi {
         protected AES(@KeyStoreKeyConstraints.BlockModeEnum int blockMode,
@@ -129,6 +129,7 @@
      * error conditions in between.
      */
     private IBinder mOperationToken;
+    private Long mOperationHandle;
     private KeyStoreCryptoOperationChunkedStreamer mMainDataStreamer;
 
     protected KeyStoreCipherSpi(
@@ -192,6 +193,7 @@
             mOperationToken = null;
             mKeyStore.abort(operationToken);
         }
+        mOperationHandle = null;
         mMainDataStreamer = null;
         mAdditionalEntropyForBegin = null;
     }
@@ -222,14 +224,14 @@
         if (opResult == null) {
             throw new KeyStoreConnectException();
         } else if (opResult.resultCode != KeyStore.NO_ERROR) {
-            throw new CryptoOperationException("Failed to start keystore operation",
-                    KeymasterUtils.getExceptionForKeymasterError(opResult.resultCode));
+            throw KeymasterUtils.getCryptoOperationException(opResult.resultCode);
         }
 
         if (opResult.token == null) {
             throw new CryptoOperationException("Keystore returned null operation token");
         }
         mOperationToken = opResult.token;
+        mOperationHandle = opResult.operationHandle;
         loadAlgorithmSpecificParametersFromBeginResult(keymasterOutputArgs);
         mFirstOperationInitiated = true;
         mMainDataStreamer = new KeyStoreCryptoOperationChunkedStreamer(
@@ -249,7 +251,7 @@
         try {
             output = mMainDataStreamer.update(input, inputOffset, inputLen);
         } catch (KeymasterException e) {
-            throw new CryptoOperationException("Keystore operation failed", e);
+            throw KeymasterUtils.getCryptoOperationException(e);
         }
 
         if (output.length == 0) {
@@ -294,7 +296,7 @@
                 case KeymasterDefs.KM_ERROR_VERIFICATION_FAILED:
                     throw new AEADBadTagException();
                 default:
-                    throw new CryptoOperationException("Keystore operation failed", e);
+                    throw KeymasterUtils.getCryptoOperationException(e);
             }
         }
 
@@ -348,6 +350,23 @@
         throw new UnsupportedOperationException();
     }
 
+    @Override
+    public void finalize() throws Throwable {
+        try {
+            IBinder operationToken = mOperationToken;
+            if (operationToken != null) {
+                mKeyStore.abort(operationToken);
+            }
+        } finally {
+            super.finalize();
+        }
+    }
+
+    @Override
+    public Long getOperationHandle() {
+        return mOperationHandle;
+    }
+
     // The methods below may need to be overridden by subclasses that use algorithm-specific
     // parameters.
 
diff --git a/core/java/android/service/fingerprint/Fingerprint.aidl b/keystore/java/android/security/KeyStoreCryptoOperation.java
similarity index 63%
copy from core/java/android/service/fingerprint/Fingerprint.aidl
copy to keystore/java/android/security/KeyStoreCryptoOperation.java
index c9fd989..19abd05 100644
--- a/core/java/android/service/fingerprint/Fingerprint.aidl
+++ b/keystore/java/android/security/KeyStoreCryptoOperation.java
@@ -13,7 +13,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.service.fingerprint;
 
-// @hide
-parcelable Fingerprint;
+package android.security;
+
+/**
+ * Cryptographic operation backed by {@link KeyStore}.
+ *
+ * @hide
+ */
+public interface KeyStoreCryptoOperation {
+    /**
+     * Gets the KeyStore operation handle of this crypto operation.
+     *
+     * @return handle or {@code null} if the KeyStore operation is not in progress.
+     */
+    Long getOperationHandle();
+}
diff --git a/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java b/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java
index 2b279f6..993614b 100644
--- a/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java
+++ b/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java
@@ -120,7 +120,7 @@
             if (opResult == null) {
                 throw new KeyStoreConnectException();
             } else if (opResult.resultCode != KeyStore.NO_ERROR) {
-                throw KeymasterUtils.getExceptionForKeymasterError(opResult.resultCode);
+                throw KeymasterUtils.getKeymasterException(opResult.resultCode);
             }
 
             if (opResult.inputConsumed == chunk.length) {
@@ -203,7 +203,7 @@
         if (opResult == null) {
             throw new KeyStoreConnectException();
         } else if (opResult.resultCode != KeyStore.NO_ERROR) {
-            throw KeymasterUtils.getExceptionForKeymasterError(opResult.resultCode);
+            throw KeymasterUtils.getKeymasterException(opResult.resultCode);
         }
 
         return concat(output, opResult.output);
@@ -227,7 +227,7 @@
         if (opResult == null) {
             throw new KeyStoreConnectException();
         } else if (opResult.resultCode != KeyStore.NO_ERROR) {
-            throw KeymasterUtils.getExceptionForKeymasterError(opResult.resultCode);
+            throw KeymasterUtils.getKeymasterException(opResult.resultCode);
         }
 
         if (opResult.inputConsumed < chunk.length) {
diff --git a/keystore/java/android/security/KeyStoreHmacSpi.java b/keystore/java/android/security/KeyStoreHmacSpi.java
index 939b41c..1297cc2 100644
--- a/keystore/java/android/security/KeyStoreHmacSpi.java
+++ b/keystore/java/android/security/KeyStoreHmacSpi.java
@@ -33,7 +33,7 @@
  *
  * @hide
  */
-public abstract class KeyStoreHmacSpi extends MacSpi {
+public abstract class KeyStoreHmacSpi extends MacSpi implements KeyStoreCryptoOperation {
 
     public static class HmacSHA256 extends KeyStoreHmacSpi {
         public HmacSHA256() {
@@ -50,6 +50,7 @@
     // The fields below are reset by the engineReset operation.
     private KeyStoreCryptoOperationChunkedStreamer mChunkedStreamer;
     private IBinder mOperationToken;
+    private Long mOperationHandle;
 
     protected KeyStoreHmacSpi(@KeyStoreKeyConstraints.DigestEnum int digest, int macSizeBytes) {
         mDigest = digest;
@@ -87,6 +88,7 @@
             mOperationToken = null;
             mKeyStore.abort(operationToken);
         }
+        mOperationHandle = null;
         mChunkedStreamer = null;
 
         KeymasterArguments keymasterArgs = new KeymasterArguments();
@@ -101,13 +103,13 @@
         if (opResult == null) {
             throw new KeyStoreConnectException();
         } else if (opResult.resultCode != KeyStore.NO_ERROR) {
-            throw new CryptoOperationException("Failed to start keystore operation",
-                    KeymasterUtils.getExceptionForKeymasterError(opResult.resultCode));
+            throw KeymasterUtils.getCryptoOperationException(opResult.resultCode);
         }
         mOperationToken = opResult.token;
         if (mOperationToken == null) {
             throw new CryptoOperationException("Keystore returned null operation token");
         }
+        mOperationHandle = opResult.operationHandle;
         mChunkedStreamer = new KeyStoreCryptoOperationChunkedStreamer(
                 new KeyStoreCryptoOperationChunkedStreamer.MainDataStream(
                         mKeyStore, mOperationToken));
@@ -128,7 +130,7 @@
         try {
             output = mChunkedStreamer.update(input, offset, len);
         } catch (KeymasterException e) {
-            throw new CryptoOperationException("Keystore operation failed", e);
+            throw KeymasterUtils.getCryptoOperationException(e);
         }
         if ((output != null) && (output.length != 0)) {
             throw new CryptoOperationException("Update operation unexpectedly produced output");
@@ -145,7 +147,7 @@
         try {
             result = mChunkedStreamer.doFinal(null, 0, 0);
         } catch (KeymasterException e) {
-            throw new CryptoOperationException("Keystore operation failed", e);
+            throw KeymasterUtils.getCryptoOperationException(e);
         }
 
         engineReset();
@@ -157,11 +159,15 @@
         try {
             IBinder operationToken = mOperationToken;
             if (operationToken != null) {
-                mOperationToken = null;
                 mKeyStore.abort(operationToken);
             }
         } finally {
             super.finalize();
         }
     }
+
+    @Override
+    public Long getOperationHandle() {
+        return mOperationHandle;
+    }
 }
diff --git a/keystore/java/android/security/KeyStoreKeyConstraints.java b/keystore/java/android/security/KeyStoreKeyConstraints.java
index c011083..75034d1 100644
--- a/keystore/java/android/security/KeyStoreKeyConstraints.java
+++ b/keystore/java/android/security/KeyStoreKeyConstraints.java
@@ -23,7 +23,10 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.Locale;
+import java.util.Set;
 
 /**
  * Constraints for {@code AndroidKeyStore} keys.
@@ -520,4 +523,96 @@
             }
         }
     }
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({UserAuthenticator.LOCK_SCREEN})
+    public @interface UserAuthenticatorEnum {}
+
+    /**
+     * User authenticators which can be used to restrict/protect access to keys.
+     */
+    public static abstract class UserAuthenticator {
+        private UserAuthenticator() {}
+
+        /** Lock screen. */
+        public static final int LOCK_SCREEN = 1;
+
+        /** Fingerprint reader/sensor. */
+        public static final int FINGERPRINT_READER = 1 << 1;
+
+        /**
+         * @hide
+         */
+        public static int toKeymaster(@UserAuthenticatorEnum int userAuthenticator) {
+            switch (userAuthenticator) {
+                case LOCK_SCREEN:
+                    return LOCK_SCREEN;
+                case FINGERPRINT_READER:
+                    return FINGERPRINT_READER;
+                default:
+                    throw new IllegalArgumentException(
+                            "Unknown user authenticator: " + userAuthenticator);
+            }
+        }
+
+        /**
+         * @hide
+         */
+        public static @UserAuthenticatorEnum int fromKeymaster(int userAuthenticator) {
+            switch (userAuthenticator) {
+                case LOCK_SCREEN:
+                    return LOCK_SCREEN;
+                case FINGERPRINT_READER:
+                    return FINGERPRINT_READER;
+                default:
+                    throw new IllegalArgumentException(
+                            "Unknown user authenticator: " + userAuthenticator);
+            }
+        }
+
+        /**
+         * @hide
+         */
+        public static int allToKeymaster(Set<Integer> userAuthenticators) {
+            int result = 0;
+            for (@UserAuthenticatorEnum int userAuthenticator : userAuthenticators) {
+                result |= toKeymaster(userAuthenticator);
+            }
+            return result;
+        }
+
+        /**
+         * @hide
+         */
+        public static Set<Integer> allFromKeymaster(int userAuthenticators) {
+            int userAuthenticator = 1;
+            Set<Integer> result = null;
+            while (userAuthenticators != 0) {
+                if ((userAuthenticators & 1) != 0) {
+                    if (result == null) {
+                        result = new HashSet<Integer>();
+                    }
+                    result.add(fromKeymaster(userAuthenticator));
+                }
+                userAuthenticators >>>= 1;
+                userAuthenticator <<= 1;
+            }
+            return (result != null) ? result : Collections.<Integer>emptySet();
+        }
+
+        /**
+         * @hide
+         */
+        public static String toString(@UserAuthenticatorEnum int userAuthenticator) {
+            switch (userAuthenticator) {
+                case LOCK_SCREEN:
+                    return "LOCK_SCREEN";
+                case FINGERPRINT_READER:
+                    return "FINGERPRINT_READER";
+                default:
+                    throw new IllegalArgumentException(
+                            "Unknown user authenticator: " + userAuthenticator);
+            }
+        }
+    }
 }
diff --git a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
index 7796de8..8b0a3e9 100644
--- a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
@@ -23,6 +23,7 @@
 import java.security.InvalidAlgorithmParameterException;
 import java.security.SecureRandom;
 import java.security.spec.AlgorithmParameterSpec;
+import java.util.Date;
 
 import javax.crypto.KeyGeneratorSpi;
 import javax.crypto.SecretKey;
@@ -136,26 +137,27 @@
         if (spec.getUserAuthenticators().isEmpty()) {
             args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
         } else {
-        // TODO: Pass-in user authenticator IDs once the Keymaster API has stabilized
-//            for (int userAuthenticatorId : spec.getUserAuthenticators()) {
-//                args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_ID, userAuthenticatorId);
-//            }
+            args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
+                    KeyStoreKeyConstraints.UserAuthenticator.allToKeymaster(
+                            spec.getUserAuthenticators()));
+        }
+        if (spec.isInvalidatedOnNewFingerprintEnrolled()) {
+            // TODO: Add the invalidate on fingerprint enrolled constraint once Keymaster supports
+            // that.
         }
         if (spec.getUserAuthenticationValidityDurationSeconds() != null) {
             args.addInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
                     spec.getUserAuthenticationValidityDurationSeconds());
         }
-        if (spec.getKeyValidityStart() != null) {
-            args.addDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, spec.getKeyValidityStart());
-        }
-        if (spec.getKeyValidityForOriginationEnd() != null) {
-            args.addDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
-                    spec.getKeyValidityForOriginationEnd());
-        }
-        if (spec.getKeyValidityForConsumptionEnd() != null) {
-            args.addDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
-                    spec.getKeyValidityForConsumptionEnd());
-        }
+        args.addDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
+                (spec.getKeyValidityStart() != null)
+                ? spec.getKeyValidityStart() : new Date(0));
+        args.addDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
+                (spec.getKeyValidityForOriginationEnd() != null)
+                ? spec.getKeyValidityForOriginationEnd() : new Date(Long.MAX_VALUE));
+        args.addDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
+                (spec.getKeyValidityForConsumptionEnd() != null)
+                ? spec.getKeyValidityForConsumptionEnd() : new Date(Long.MAX_VALUE));
 
         if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0)
             || ((purposes & KeyStoreKeyConstraints.Purpose.DECRYPT) != 0)) {
@@ -175,8 +177,7 @@
         int errorCode = mKeyStore.generateKey(
                 keyAliasInKeystore, args, additionalEntropy, flags, new KeyCharacteristics());
         if (errorCode != KeyStore.NO_ERROR) {
-            throw new CryptoOperationException("Failed to generate key",
-                    KeymasterUtils.getExceptionForKeymasterError(errorCode));
+            throw KeymasterUtils.getCryptoOperationException(errorCode);
         }
         String keyAlgorithmJCA =
                 KeyStoreKeyConstraints.Algorithm.toJCASecretKeyAlgorithm(mAlgorithm, mDigest);
diff --git a/keystore/java/android/security/KeyStoreKeySpec.java b/keystore/java/android/security/KeyStoreKeySpec.java
index ddeefbd..e5e5acc 100644
--- a/keystore/java/android/security/KeyStoreKeySpec.java
+++ b/keystore/java/android/security/KeyStoreKeySpec.java
@@ -45,6 +45,7 @@
     private final Set<Integer> mUserAuthenticators;
     private final Set<Integer> mTeeBackedUserAuthenticators;
     private final Integer mUserAuthenticationValidityDurationSeconds;
+    private final boolean mInvalidatedOnNewFingerprintEnrolled;
 
 
     /**
@@ -63,7 +64,8 @@
             Integer maxUsesPerBoot,
             Set<Integer> userAuthenticators,
             Set<Integer> teeBackedUserAuthenticators,
-            Integer userAuthenticationValidityDurationSeconds) {
+            Integer userAuthenticationValidityDurationSeconds,
+            boolean invalidatedOnNewFingerprintEnrolled) {
         mKeystoreAlias = keystoreKeyAlias;
         mOrigin = origin;
         mKeySize = keySize;
@@ -84,6 +86,7 @@
                 ? new HashSet<Integer>(teeBackedUserAuthenticators)
                 : Collections.<Integer>emptySet();
         mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
+        mInvalidatedOnNewFingerprintEnrolled = invalidatedOnNewFingerprintEnrolled;
     }
 
     /**
@@ -223,4 +226,15 @@
     public Integer getUserAuthenticationValidityDurationSeconds() {
         return mUserAuthenticationValidityDurationSeconds;
     }
+
+    /**
+     * Returns {@code true} if this key will be permanently invalidated once a new fingerprint is
+     * enrolled. This constraint only has effect if fingerprint reader is one of the user
+     * authenticators protecting access to this key.
+     *
+     * @see #getUserAuthenticators()
+     */
+    public boolean isInvalidatedOnNewFingerprintEnrolled() {
+        return mInvalidatedOnNewFingerprintEnrolled;
+    }
 }
diff --git a/keystore/java/android/security/KeyStoreParameter.java b/keystore/java/android/security/KeyStoreParameter.java
index 2428c2a..b1b638f 100644
--- a/keystore/java/android/security/KeyStoreParameter.java
+++ b/keystore/java/android/security/KeyStoreParameter.java
@@ -59,6 +59,7 @@
     private final Integer mMaxUsesPerBoot;
     private final Set<Integer> mUserAuthenticators;
     private final Integer mUserAuthenticationValidityDurationSeconds;
+    private final boolean mInvalidatedOnNewFingerprintEnrolled;
 
     private KeyStoreParameter(int flags, Date keyValidityStart,
             Date keyValidityForOriginationEnd, Date keyValidityForConsumptionEnd,
@@ -70,7 +71,8 @@
             Integer minSecondsBetweenOperations,
             Integer maxUsesPerBoot,
             Set<Integer> userAuthenticators,
-            Integer userAuthenticationValidityDurationSeconds) {
+            Integer userAuthenticationValidityDurationSeconds,
+            boolean invalidatedOnNewFingerprintEnrolled) {
         if ((userAuthenticationValidityDurationSeconds != null)
                 && (userAuthenticationValidityDurationSeconds < 0)) {
             throw new IllegalArgumentException(
@@ -92,6 +94,7 @@
                 ? new HashSet<Integer>(userAuthenticators)
                 : Collections.<Integer>emptySet();
         mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
+        mInvalidatedOnNewFingerprintEnrolled = invalidatedOnNewFingerprintEnrolled;
     }
 
     /**
@@ -245,6 +248,19 @@
     }
 
     /**
+     * Returns {@code true} if this key must be permanently invalidated once a new fingerprint is
+     * enrolled. This constraint only has effect if fingerprint reader is one of the user
+     * authenticators protecting access to this key.
+     *
+     * @see #getUserAuthenticators()
+     *
+     * @hide
+     */
+    public boolean isInvalidatedOnNewFingerprintEnrolled() {
+        return mInvalidatedOnNewFingerprintEnrolled;
+    }
+
+    /**
      * Builder class for {@link KeyStoreParameter} objects.
      * <p>
      * This will build protection parameters for use with the
@@ -275,6 +291,7 @@
         private Integer mMaxUsesPerBoot;
         private Set<Integer> mUserAuthenticators;
         private Integer mUserAuthenticationValidityDurationSeconds;
+        private boolean mInvalidatedOnNewFingerprintEnrolled;
 
         /**
          * Creates a new instance of the {@code Builder} with the given
@@ -496,6 +513,22 @@
         }
 
         /**
+         * Sets whether this key must be invalidated (permanently) whenever a new fingerprint is
+         * enrolled. This only has effect if fingerprint reader is one of the user authenticators
+         * protecting access to the key.
+         *
+         * <p>By default, enrolling a new fingerprint does not invalidate the key.
+         *
+         * @see #setUserAuthenticators(Set)
+         *
+         * @hide
+         */
+        public Builder setInvalidatedOnNewFingerprintEnrolled(boolean invalidated) {
+            mInvalidatedOnNewFingerprintEnrolled = invalidated;
+            return this;
+        }
+
+        /**
          * Builds the instance of the {@code KeyStoreParameter}.
          *
          * @throws IllegalArgumentException if a required field is missing
@@ -506,7 +539,8 @@
                     mKeyValidityForOriginationEnd, mKeyValidityForConsumptionEnd, mPurposes,
                     mAlgorithm, mPadding, mDigest, mBlockMode, mMinSecondsBetweenOperations,
                     mMaxUsesPerBoot, mUserAuthenticators,
-                    mUserAuthenticationValidityDurationSeconds);
+                    mUserAuthenticationValidityDurationSeconds,
+                    mInvalidatedOnNewFingerprintEnrolled);
         }
     }
 }
diff --git a/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java
index 8921ba1..c205d9d 100644
--- a/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java
+++ b/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java
@@ -22,7 +22,7 @@
 import java.security.InvalidKeyException;
 import java.security.spec.InvalidKeySpecException;
 import java.security.spec.KeySpec;
-import java.util.Collections;
+import java.util.Date;
 import java.util.Set;
 
 import javax.crypto.SecretKey;
@@ -113,22 +113,44 @@
             throw new InvalidKeySpecException("Unsupported key characteristic", e);
         }
 
-        // TODO: Read user authentication IDs once the Keymaster API has stabilized
-        Set<Integer> userAuthenticators = Collections.emptySet();
-        Set<Integer> teeBackedUserAuthenticators = Collections.emptySet();
-//        Set<Integer> userAuthenticators = new HashSet<Integer>(
-//                getInts(keyCharacteristics, KeymasterDefs.KM_TAG_USER_AUTH_ID));
-//        Set<Integer> teeBackedUserAuthenticators = new HashSet<Integer>(
-//                keyCharacteristics.hwEnforced.getInts(KeymasterDefs.KM_TAG_USER_AUTH_ID));
+        Date keyValidityStart =
+                KeymasterUtils.getDate(keyCharacteristics, KeymasterDefs.KM_TAG_ACTIVE_DATETIME);
+        if ((keyValidityStart != null) && (keyValidityStart.getTime() <= 0)) {
+            keyValidityStart = null;
+        }
+        Date keyValidityForOriginationEnd = KeymasterUtils.getDate(keyCharacteristics,
+                KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME);
+        if ((keyValidityForOriginationEnd != null)
+                && (keyValidityForOriginationEnd.getTime() == Long.MAX_VALUE)) {
+            keyValidityForOriginationEnd = null;
+        }
+        Date keyValidityForConsumptionEnd = KeymasterUtils.getDate(keyCharacteristics,
+                KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME);
+        if ((keyValidityForConsumptionEnd != null)
+                && (keyValidityForConsumptionEnd.getTime() == Long.MAX_VALUE)) {
+            keyValidityForConsumptionEnd = null;
+        }
+
+        int swEnforcedUserAuthenticatorIds =
+                keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
+        int hwEnforcedUserAuthenticatorIds =
+                keyCharacteristics.hwEnforced.getInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
+        int userAuthenticatorIds = swEnforcedUserAuthenticatorIds | hwEnforcedUserAuthenticatorIds;
+        Set<Integer> userAuthenticators =
+                KeyStoreKeyConstraints.UserAuthenticator.allFromKeymaster(userAuthenticatorIds);
+        Set<Integer> teeBackedUserAuthenticators =
+                KeyStoreKeyConstraints.UserAuthenticator.allFromKeymaster(
+                        hwEnforcedUserAuthenticatorIds);
+
+        // TODO: Populate the value below from key characteristics once Keymaster is ready.
+        boolean invalidatedOnNewFingerprintEnrolled = false;
 
         return new KeyStoreKeySpec(entryAlias,
                 origin,
                 keySize,
-                KeymasterUtils.getDate(keyCharacteristics, KeymasterDefs.KM_TAG_ACTIVE_DATETIME),
-                KeymasterUtils.getDate(keyCharacteristics,
-                        KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME),
-                KeymasterUtils.getDate(keyCharacteristics,
-                        KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME),
+                keyValidityStart,
+                keyValidityForOriginationEnd,
+                keyValidityForConsumptionEnd,
                 purposes,
                 algorithm,
                 padding,
@@ -139,7 +161,8 @@
                 KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_MAX_USES_PER_BOOT),
                 userAuthenticators,
                 teeBackedUserAuthenticators,
-                KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_AUTH_TIMEOUT));
+                KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_AUTH_TIMEOUT),
+                invalidatedOnNewFingerprintEnrolled);
     }
 
     @Override
diff --git a/keystore/java/android/security/KeymasterUtils.java b/keystore/java/android/security/KeymasterUtils.java
index 6bb9636..c3092d5 100644
--- a/keystore/java/android/security/KeymasterUtils.java
+++ b/keystore/java/android/security/KeymasterUtils.java
@@ -29,7 +29,7 @@
 public abstract class KeymasterUtils {
     private KeymasterUtils() {}
 
-    public static KeymasterException getExceptionForKeymasterError(int keymasterErrorCode) {
+    public static KeymasterException getKeymasterException(int keymasterErrorCode) {
         switch (keymasterErrorCode) {
             case KeymasterDefs.KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT:
                 // The name of this parameter significantly differs between Keymaster and framework
@@ -42,6 +42,22 @@
         }
     }
 
+    public static CryptoOperationException getCryptoOperationException(KeymasterException e) {
+        switch (e.getErrorCode()) {
+            case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED:
+                return new UserNotAuthenticatedException();
+            // TODO: Handle TBD Keymaster error code "invalid key: new fingerprint enrolled"
+            // case KeymasterDefs.KM_ERROR_TBD
+            //     return new NewFingerprintEnrolledException();
+            default:
+                return new CryptoOperationException("Crypto operation failed", e);
+        }
+    }
+
+    public static CryptoOperationException getCryptoOperationException(int keymasterErrorCode) {
+        return getCryptoOperationException(getKeymasterException(keymasterErrorCode));
+    }
+
     public static Integer getInt(KeyCharacteristics keyCharacteristics, int tag) {
         if (keyCharacteristics.hwEnforced.containsTag(tag)) {
             return keyCharacteristics.hwEnforced.getInt(tag, -1);
diff --git a/keystore/java/android/security/NewFingerprintEnrolledException.java b/keystore/java/android/security/NewFingerprintEnrolledException.java
new file mode 100644
index 0000000..6da4a2a
--- /dev/null
+++ b/keystore/java/android/security/NewFingerprintEnrolledException.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+/**
+ * Indicates that a cryptographic operation could not be performed because the key used by the
+ * operation is permanently invalid because a new fingerprint was enrolled.
+ *
+ * @hide
+ */
+public class NewFingerprintEnrolledException extends CryptoOperationException {
+
+    /**
+     * Constructs a new {@code NewFingerprintEnrolledException} without detail message and cause.
+     */
+    public NewFingerprintEnrolledException() {
+        super("Invalid key: new fingerprint enrolled");
+    }
+
+    /**
+     * Constructs a new {@code NewFingerprintEnrolledException} with the provided detail message and
+     * no cause.
+     */
+    public NewFingerprintEnrolledException(String message) {
+        super(message);
+    }
+}
diff --git a/keystore/java/android/security/UserNotAuthenticatedException.java b/keystore/java/android/security/UserNotAuthenticatedException.java
new file mode 100644
index 0000000..b45817c
--- /dev/null
+++ b/keystore/java/android/security/UserNotAuthenticatedException.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+/**
+ * Indicates that a cryptographic operation could not be performed because the user has not been
+ * authenticated recently enough.
+ *
+ * @hide
+ */
+public class UserNotAuthenticatedException extends CryptoOperationException {
+    public UserNotAuthenticatedException() {
+        super("User not authenticated");
+    }
+
+    public UserNotAuthenticatedException(String message) {
+        super(message);
+    }
+}
diff --git a/media/java/android/media/AudioPortEventHandler.java b/media/java/android/media/AudioPortEventHandler.java
index c05fd77..c49e8c2 100644
--- a/media/java/android/media/AudioPortEventHandler.java
+++ b/media/java/android/media/AudioPortEventHandler.java
@@ -40,6 +40,12 @@
     private static final int AUDIOPORT_EVENT_SERVICE_DIED = 3;
     private static final int AUDIOPORT_EVENT_NEW_LISTENER = 4;
 
+    /**
+     * Accessed by native methods: JNI Callback context.
+     */
+    @SuppressWarnings("unused")
+    private long mJniCallback;
+
     void init() {
         synchronized (this) {
             if (mHandler != null) {
@@ -63,9 +69,6 @@
                                 listeners = mListeners;
                             }
                         }
-                        if (listeners.isEmpty()) {
-                            return;
-                        }
                         // reset audio port cache if the event corresponds to a change coming
                         // from audio policy service or if mediaserver process died.
                         if (msg.what == AUDIOPORT_EVENT_PORT_LIST_UPDATED ||
@@ -73,6 +76,11 @@
                                 msg.what == AUDIOPORT_EVENT_SERVICE_DIED) {
                             AudioManager.resetAudioPortGeneration();
                         }
+
+                        if (listeners.isEmpty()) {
+                            return;
+                        }
+
                         ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
                         ArrayList<AudioPatch> patches = new ArrayList<AudioPatch>();
                         if (msg.what != AUDIOPORT_EVENT_SERVICE_DIED) {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index c9805ae..82dec30 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -53,10 +53,10 @@
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
 
-import android.service.fingerprint.FingerprintManager;
-import android.service.fingerprint.FingerprintManager.AuthenticationCallback;
-import android.service.fingerprint.FingerprintUtils;
-import android.service.fingerprint.FingerprintManager.AuthenticationResult;
+import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
+import android.hardware.fingerprint.FingerprintUtils;
+import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index c2462e0..8d2562d 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -19,7 +19,7 @@
 import android.graphics.Bitmap;
 import android.media.AudioManager;
 import android.os.SystemClock;
-import android.service.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.FingerprintManager;
 import android.telephony.TelephonyManager;
 import android.view.WindowManagerPolicy;
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index e1cb878..64b4452 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -104,6 +104,7 @@
 
     // See mConnectAttempted
     private static final long MAX_UUID_DELAY_FOR_AUTO_CONNECT = 5000;
+    private static final long MAX_HOGP_DELAY_FOR_AUTO_CONNECT = 30000;
 
     /** Auto-connect after pairing only if locally initiated. */
     private boolean mConnectAfterPairing;
@@ -525,9 +526,11 @@
      */
     void onUuidChanged() {
         updateProfiles();
+        ParcelUuid[] uuids = mDevice.getUuids();
+        long timeout = MAX_UUID_DELAY_FOR_AUTO_CONNECT;
 
         if (DEBUG) {
-            Log.e(TAG, "onUuidChanged: Time since last connect"
+            Log.d(TAG, "onUuidChanged: Time since last connect"
                     + (SystemClock.elapsedRealtime() - mConnectAttempted));
         }
 
@@ -535,9 +538,11 @@
          * If a connect was attempted earlier without any UUID, we will do the
          * connect now.
          */
+        if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hogp)) {
+            timeout = MAX_HOGP_DELAY_FOR_AUTO_CONNECT;
+        }
         if (!mProfiles.isEmpty()
-                && (mConnectAttempted + MAX_UUID_DELAY_FOR_AUTO_CONNECT) > SystemClock
-                        .elapsedRealtime()) {
+                && (mConnectAttempted + timeout) > SystemClock.elapsedRealtime()) {
             connectWithoutResettingTimer(false);
         }
         dispatchAttributesChanged();
diff --git a/services/core/java/com/android/server/AssetAtlasService.java b/services/core/java/com/android/server/AssetAtlasService.java
index e6dc1c7..f106667 100644
--- a/services/core/java/com/android/server/AssetAtlasService.java
+++ b/services/core/java/com/android/server/AssetAtlasService.java
@@ -403,13 +403,13 @@
         if (cpuCount == 1) {
             new ComputeWorker(MIN_SIZE, MAX_SIZE, STEP, bitmaps, pixelCount, results, null).run();
         } else {
-            int start = MIN_SIZE;
-            int end = MAX_SIZE - (cpuCount - 1) * STEP;
+            int start = MIN_SIZE + (cpuCount - 1) * STEP;
+            int end = MAX_SIZE;
             int step = STEP * cpuCount;
 
             final CountDownLatch signal = new CountDownLatch(cpuCount);
 
-            for (int i = 0; i < cpuCount; i++, start += STEP, end += STEP) {
+            for (int i = 0; i < cpuCount; i++, start -= STEP, end -= STEP) {
                 ComputeWorker worker = new ComputeWorker(start, end, step,
                         bitmaps, pixelCount, results, signal);
                 new Thread(worker, "Atlas Worker #" + (i + 1)).start();
@@ -435,7 +435,8 @@
 
         if (DEBUG_ATLAS) {
             float delay = (System.nanoTime() - begin) / 1000.0f / 1000.0f / 1000.0f;
-            Log.d(LOG_TAG, String.format("Found best atlas configuration in %.2fs", delay));
+            Log.d(LOG_TAG, String.format("Found best atlas configuration (out of %d) in %.2fs",
+                    results.size(), delay));
         }
 
         WorkerResult result = results.get(0);
@@ -696,8 +697,8 @@
 
             Atlas.Entry entry = new Atlas.Entry();
             for (Atlas.Type type : Atlas.Type.values()) {
-                for (int width = mStart; width < mEnd; width += mStep) {
-                    for (int height = MIN_SIZE; height < MAX_SIZE; height += STEP) {
+                for (int width = mEnd; width > mStart; width -= mStep) {
+                    for (int height = MAX_SIZE; height > MIN_SIZE; height -= STEP) {
                         // If the atlas is not big enough, skip it
                         if (width * height <= mThreshold) continue;
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
index fd4974e..7a74e45 100644
--- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -72,7 +72,7 @@
     static final boolean DEBUG_TRANSITION = DEBUG_ALL || false;
     static final boolean DEBUG_URI_PERMISSION = DEBUG_ALL || false;
     static final boolean DEBUG_USER_LEAVING = DEBUG_ALL || false;
-    static final boolean DEBUG_VISBILITY = DEBUG_ALL || false;
+    static final boolean DEBUG_VISIBILITY = DEBUG_ALL || false;
 
     static final String POSTFIX_BACKUP = (APPEND_CATEGORY_NAME) ? "_Backup" : "";
     static final String POSTFIX_BROADCAST = (APPEND_CATEGORY_NAME) ? "_Broadcast" : "";
@@ -80,11 +80,29 @@
     static final String POSTFIX_CONFIGURATION = (APPEND_CATEGORY_NAME) ? "_Configuration" : "";
     static final String POSTFIX_FOCUS = (APPEND_CATEGORY_NAME) ? "_Focus" : "";
     static final String POSTFIX_IMMERSIVE = (APPEND_CATEGORY_NAME) ? "_Immersive" : "";
+    static final String POSTFIX_LOCKSCREEN = (APPEND_CATEGORY_NAME) ? "_LOCKSCREEN" : "";
     static final String POSTFIX_LRU = (APPEND_CATEGORY_NAME) ? "_LRU" : "";
     static final String POSTFIX_MU = "_MU";
     static final String POSTFIX_OOM_ADJ = (APPEND_CATEGORY_NAME) ? "_OomAdj" : "";
+    static final String POSTFIX_PAUSE = (APPEND_CATEGORY_NAME) ? "_Pause" : "";
+    static final String POSTFIX_POWER = (APPEND_CATEGORY_NAME) ? "_Power" : "";
+    static final String POSTFIX_PROCESS_OBSERVERS = (APPEND_CATEGORY_NAME)
+            ? "_ProcessObservers" : "";
+    static final String POSTFIX_PROCESSES = (APPEND_CATEGORY_NAME) ? "_Processes" : "";
+    static final String POSTFIX_PROVIDER = (APPEND_CATEGORY_NAME) ? "_Provider" : "";
+    static final String POSTFIX_PSS = (APPEND_CATEGORY_NAME) ? "_Pss" : "";
+    static final String POSTFIX_RESULTS = (APPEND_CATEGORY_NAME) ? "_Results" : "";
+    static final String POSTFIX_RECENTS = (APPEND_CATEGORY_NAME) ? "_Recents" : "";
     static final String POSTFIX_SERVICE = (APPEND_CATEGORY_NAME) ? "_Service" : "";
     static final String POSTFIX_SERVICE_EXECUTING =
             (APPEND_CATEGORY_NAME) ? "_ServiceExecuting" : "";
+    static final String POSTFIX_STACK = (APPEND_CATEGORY_NAME) ? "_Stack" : "";
+    static final String POSTFIX_SWITCH = (APPEND_CATEGORY_NAME) ? "_Switch" : "";
+    static final String POSTFIX_TASKS = (APPEND_CATEGORY_NAME) ? "_Tasks" : "";
+    static final String POSTFIX_THUMBNAILS = (APPEND_CATEGORY_NAME) ? "_Thumbnails" : "";
+    static final String POSTFIX_TRANSITION = (APPEND_CATEGORY_NAME) ? "_Transition" : "";
+    static final String POSTFIX_URI_PERMISSION = (APPEND_CATEGORY_NAME) ? "_UriPermission" : "";
+    static final String POSTFIX_USER_LEAVING = (APPEND_CATEGORY_NAME) ? "_UserLeaving" : "";
+    static final String POSTFIX_VISIBILITY = (APPEND_CATEGORY_NAME) ? "_Visibility" : "";
 
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c318370..5858477 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -26,12 +26,12 @@
 import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
 import static com.android.internal.util.XmlUtils.writeIntAttribute;
 import static com.android.internal.util.XmlUtils.writeLongAttribute;
-import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
-import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
-import static org.xmlpull.v1.XmlPullParser.START_TAG;
 import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
 import static com.android.server.am.ActivityManagerDebugConfig.*;
 import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
+import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
+import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
+import static org.xmlpull.v1.XmlPullParser.START_TAG;
 
 import android.Manifest;
 import android.app.AppOpsManager;
@@ -259,37 +259,30 @@
     private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
     private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
     private static final String TAG_IMMERSIVE = TAG + POSTFIX_IMMERSIVE;
+    private static final String TAG_LOCKSCREEN = TAG + POSTFIX_LOCKSCREEN;
     private static final String TAG_LRU = TAG + POSTFIX_LRU;
     private static final String TAG_MU = TAG + POSTFIX_MU;
     private static final String TAG_OOM_ADJ = TAG + POSTFIX_OOM_ADJ;
+    private static final String TAG_POWER = TAG + POSTFIX_POWER;
+    private static final String TAG_PROCESS_OBSERVERS = TAG + POSTFIX_PROCESS_OBSERVERS;
+    private static final String TAG_PROCESSES = TAG + POSTFIX_PROCESSES;
+    private static final String TAG_PROVIDER = TAG + POSTFIX_PROVIDER;
+    private static final String TAG_PSS = TAG + POSTFIX_PSS;
+    private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
+    private static final String TAG_SERVICE = TAG + POSTFIX_SERVICE;
+    private static final String TAG_STACK = TAG + POSTFIX_STACK;
+    private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
+    private static final String TAG_URI_PERMISSION = TAG + POSTFIX_URI_PERMISSION;
+    private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
 
-    // TODO(ogunwale): Migrate all the constants below to use ActivityManagerDebugConfig class.
-    static final boolean DEBUG_PAUSE = DEBUG_ALL || false;
-    static final boolean DEBUG_POWER = DEBUG_ALL || false;
-    static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false;
-    static final boolean DEBUG_PROCESS_OBSERVERS = DEBUG_ALL || false;
-    static final boolean DEBUG_PROCESSES = DEBUG_ALL || false;
-    static final boolean DEBUG_PROVIDER = DEBUG_ALL || false;
-    static final boolean DEBUG_RESULTS = DEBUG_ALL || false;
-    static final boolean DEBUG_SERVICE = DEBUG_ALL || false;
-    static final boolean DEBUG_SERVICE_EXECUTING = DEBUG_ALL || false;
-    static final boolean DEBUG_STACK = DEBUG_ALL || false;
-    static final boolean DEBUG_SWITCH = DEBUG_ALL || false;
-    static final boolean DEBUG_TASKS = DEBUG_ALL || false;
-    static final boolean DEBUG_THUMBNAILS = DEBUG_ALL || false;
-    static final boolean DEBUG_TRANSITION = DEBUG_ALL || false;
-    static final boolean DEBUG_URI_PERMISSION = DEBUG_ALL || false;
-    static final boolean DEBUG_USER_LEAVING = DEBUG_ALL || false;
-    static final boolean DEBUG_VISBILITY = DEBUG_ALL || false;
-    static final boolean DEBUG_PSS = DEBUG_ALL || false;
-    static final boolean DEBUG_LOCKSCREEN = DEBUG_ALL || false;
-    static final boolean DEBUG_RECENTS = DEBUG_ALL || false;
-
-    // Control over CPU and battery monitoring.
-    static final long BATTERY_STATS_TIME = 30*60*1000;      // write battery stats every 30 minutes.
+    /** Control over CPU and battery monitoring */
+    // write battery stats every 30 minutes.
+    static final long BATTERY_STATS_TIME = 30 * 60 * 1000;
     static final boolean MONITOR_CPU_USAGE = true;
-    static final long MONITOR_CPU_MIN_TIME = 5*1000;        // don't sample cpu less than every 5 seconds.
-    static final long MONITOR_CPU_MAX_TIME = 0x0fffffff;    // wait possibly forever for next cpu sample.
+    // don't sample cpu less than every 5 seconds.
+    static final long MONITOR_CPU_MIN_TIME = 5 * 1000;
+    // wait possibly forever for next cpu sample.
+    static final long MONITOR_CPU_MAX_TIME = 0x0fffffff;
     static final boolean MONITOR_THREAD_CPU_USAGE = false;
 
     // The flags that are set for all calls we make to the package manager.
@@ -1847,8 +1840,8 @@
                     return;
                 }
 
-                if (DEBUG_PSS) Slog.d(TAG, "Showing dump heap notification from "
-                        + procName + "/" + uid);
+                if (DEBUG_PSS) Slog.d(TAG_PSS,
+                        "Showing dump heap notification from " + procName + "/" + uid);
 
                 INotificationManager inm = NotificationManager.getService();
                 if (inm == null) {
@@ -1946,7 +1939,7 @@
                     }
                     memInfo.readMemInfo();
                     synchronized (ActivityManagerService.this) {
-                        if (DEBUG_PSS) Slog.d(TAG, "Collected native and kernel memory in "
+                        if (DEBUG_PSS) Slog.d(TAG_PSS, "Collected native and kernel memory in "
                                 + (SystemClock.uptimeMillis()-start) + "ms");
                         final long cachedKb = memInfo.getCachedSizeKb();
                         final long freeKb = memInfo.getFreeSizeKb();
@@ -1968,8 +1961,9 @@
                     long lastPssTime;
                     synchronized (ActivityManagerService.this) {
                         if (mPendingPssProcesses.size() <= 0) {
-                            if (mTestPssMode || DEBUG_PSS) Slog.d(TAG, "Collected PSS of " + num
-                                    + " processes in " + (SystemClock.uptimeMillis()-start) + "ms");
+                            if (mTestPssMode || DEBUG_PSS) Slog.d(TAG_PSS,
+                                    "Collected PSS of " + num + " processes in "
+                                    + (SystemClock.uptimeMillis() - start) + "ms");
                             mPendingPssProcesses.clear();
                             return;
                         }
@@ -2528,7 +2522,7 @@
 
     @Override
     public void notifyActivityDrawn(IBinder token) {
-        if (DEBUG_VISBILITY) Slog.d(TAG, "notifyActivityDrawn: token=" + token);
+        if (DEBUG_VISIBILITY) Slog.d(TAG_VISIBILITY, "notifyActivityDrawn: token=" + token);
         synchronized (this) {
             ActivityRecord r = mStackSupervisor.isInAnyStackLocked(token);
             if (r != null) {
@@ -2828,7 +2822,7 @@
         } else if (proc != null && !keepIfLarge
                 && mLastMemoryLevel > ProcessStats.ADJ_MEM_FACTOR_NORMAL
                 && proc.setProcState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY) {
-            if (DEBUG_PSS) Slog.d(TAG, "May not keep " + proc + ": pss=" + proc.lastCachedPss);
+            if (DEBUG_PSS) Slog.d(TAG_PSS, "May not keep " + proc + ": pss=" + proc.lastCachedPss);
             if (proc.lastCachedPss >= mProcessList.getCachedRestoreThresholdKb()) {
                 if (proc.baseProcessTracker != null) {
                     proc.baseProcessTracker.reportCachedKill(proc.pkgList, proc.lastCachedPss);
@@ -2910,7 +2904,7 @@
         //     object attached to it so we know it couldn't have crashed; and
         // (3) There is a pid assigned to it, so it is either starting or
         //     already running.
-        if (DEBUG_PROCESSES) Slog.v(TAG, "startProcess: name=" + processName
+        if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "startProcess: name=" + processName
                 + " app=" + app + " knownToBeDead=" + knownToBeDead
                 + " thread=" + (app != null ? app.thread : null)
                 + " pid=" + (app != null ? app.pid : -1));
@@ -2918,7 +2912,7 @@
             if (!knownToBeDead || app.thread == null) {
                 // We already have the app running, or are waiting for it to
                 // come up (we have a pid but not yet its thread), so keep it.
-                if (DEBUG_PROCESSES) Slog.v(TAG, "App already running: " + app);
+                if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "App already running: " + app);
                 // If this is a new package in the process, add the package to the list
                 app.addPackage(info.packageName, info.versionCode, mProcessStats);
                 checkTime(startTime, "startProcess: done, added package to proc");
@@ -2927,7 +2921,7 @@
 
             // An application record is attached to a previous process,
             // clean it up now.
-            if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG, "App died: " + app);
+            if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG_PROCESSES, "App died: " + app);
             checkTime(startTime, "startProcess: bad proc running, killing");
             Process.killProcessGroup(app.info.uid, app.pid);
             handleAppDiedLocked(app, true, true);
@@ -2942,7 +2936,7 @@
                 // If we are in the background, then check to see if this process
                 // is bad.  If so, we will just silently fail.
                 if (mBadProcesses.get(info.processName, info.uid) != null) {
-                    if (DEBUG_PROCESSES) Slog.v(TAG, "Bad process: " + info.uid
+                    if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "Bad process: " + info.uid
                             + "/" + info.processName);
                     return null;
                 }
@@ -2951,7 +2945,7 @@
                 // crash count so that we won't make it bad until they see at
                 // least one crash dialog again, and make the process good again
                 // if it had been bad.
-                if (DEBUG_PROCESSES) Slog.v(TAG, "Clearing bad process: " + info.uid
+                if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "Clearing bad process: " + info.uid
                         + "/" + info.processName);
                 mProcessCrashTimes.remove(info.processName, info.uid);
                 if (mBadProcesses.get(info.processName, info.uid) != null) {
@@ -2994,7 +2988,8 @@
             if (!mProcessesOnHold.contains(app)) {
                 mProcessesOnHold.add(app);
             }
-            if (DEBUG_PROCESSES) Slog.v(TAG, "System not ready, putting on hold: " + app);
+            if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES,
+                    "System not ready, putting on hold: " + app);
             checkTime(startTime, "startProcess: returning with proc on hold");
             return app;
         }
@@ -3029,7 +3024,7 @@
             app.setPid(0);
         }
 
-        if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG,
+        if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG_PROCESSES,
                 "startProcessLocked removing on hold: " + app);
         mProcessesOnHold.remove(app);
 
@@ -3198,7 +3193,8 @@
     }
 
     void updateUsageStats(ActivityRecord component, boolean resumed) {
-        if (DEBUG_SWITCH) Slog.d(TAG, "updateUsageStats: comp=" + component + "res=" + resumed);
+        if (DEBUG_SWITCH) Slog.d(TAG_SWITCH,
+                "updateUsageStats: comp=" + component + "res=" + resumed);
         final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
         if (resumed) {
             if (mUsageStatsService != null) {
@@ -3416,7 +3412,8 @@
             mPendingProcessChanges.toArray(mActiveProcessChanges);
             mAvailProcessChanges.addAll(mPendingProcessChanges);
             mPendingProcessChanges.clear();
-            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "*** Delivering " + N + " process changes");
+            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                    "*** Delivering " + N + " process changes");
         }
 
         int i = mProcessObservers.beginBroadcast();
@@ -3428,15 +3425,16 @@
                     for (int j=0; j<N; j++) {
                         ProcessChangeItem item = mActiveProcessChanges[j];
                         if ((item.changes&ProcessChangeItem.CHANGE_ACTIVITIES) != 0) {
-                            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "ACTIVITIES CHANGED pid="
-                                    + item.pid + " uid=" + item.uid + ": "
-                                    + item.foregroundActivities);
+                            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                                    "ACTIVITIES CHANGED pid=" + item.pid + " uid="
+                                    + item.uid + ": " + item.foregroundActivities);
                             observer.onForegroundActivitiesChanged(item.pid, item.uid,
                                     item.foregroundActivities);
                         }
                         if ((item.changes&ProcessChangeItem.CHANGE_PROCESS_STATE) != 0) {
-                            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "PROCSTATE CHANGED pid="
-                                    + item.pid + " uid=" + item.uid + ": " + item.processState);
+                            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                                    "PROCSTATE CHANGED pid=" + item.pid + " uid=" + item.uid
+                                    + ": " + item.processState);
                             observer.onProcessStateChanged(item.pid, item.uid, item.processState);
                         }
                     }
@@ -4352,7 +4350,7 @@
                     + ") has died and restarted (pid " + app.pid + ").");
             EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName);
         } else if (DEBUG_PROCESSES) {
-            Slog.d(TAG, "Received spurious death notification for thread "
+            Slog.d(TAG_PROCESSES, "Received spurious death notification for thread "
                     + thread.asBinder());
         }
     }
@@ -5387,9 +5385,8 @@
             boolean callerWillRestart, boolean allowRestart, String reason) {
         final String name = app.processName;
         final int uid = app.uid;
-        if (DEBUG_PROCESSES) Slog.d(
-            TAG, "Force removing proc " + app.toShortString() + " (" + name
-            + "/" + uid + ")");
+        if (DEBUG_PROCESSES) Slog.d(TAG_PROCESSES,
+            "Force removing proc " + app.toShortString() + " (" + name + "/" + uid + ")");
 
         mProcessNames.remove(name, uid);
         mIsolatedProcesses.remove(app.uid);
@@ -5633,7 +5630,7 @@
 
         // Remove this record from the list of starting applications.
         mPersistentStartingProcesses.remove(app);
-        if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG,
+        if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG_PROCESSES,
                 "Attach application locked removing on hold: " + app);
         mProcessesOnHold.remove(app);
 
@@ -5841,7 +5838,7 @@
                 ArrayList<ProcessRecord> procs =
                     new ArrayList<ProcessRecord>(mProcessesOnHold);
                 for (int ip=0; ip<NP; ip++) {
-                    if (DEBUG_PROCESSES) Slog.v(TAG, "Starting process on hold: "
+                    if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "Starting process on hold: "
                             + procs.get(ip));
                     startProcessLocked(procs.get(ip), "on-hold", null);
                 }
@@ -5982,7 +5979,7 @@
 
     @Override
     public final void activityDestroyed(IBinder token) {
-        if (DEBUG_SWITCH) Slog.v(TAG, "ACTIVITY DESTROYED: " + token);
+        if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "ACTIVITY DESTROYED: " + token);
         synchronized (this) {
             ActivityStack stack = ActivityRecord.getStackLocked(token);
             if (stack != null) {
@@ -6587,7 +6584,7 @@
      */
     private final boolean checkHoldingPermissionsLocked(
             IPackageManager pm, ProviderInfo pi, GrantUri grantUri, int uid, final int modeFlags) {
-        if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+        if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
                 "checkHoldingPermissionsLocked: uri=" + grantUri + " uid=" + uid);
         if (UserHandle.getUserId(uid) != grantUri.sourceUserId) {
             if (ActivityManager.checkComponentPermission(INTERACT_ACROSS_USERS, uid, -1, true)
@@ -6635,8 +6632,8 @@
                     if (pp.match(path)) {
                         if (!readMet) {
                             final String pprperm = pp.getReadPermission();
-                            if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Checking read perm for "
-                                    + pprperm + " for " + pp.getPath()
+                            if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
+                                    "Checking read perm for " + pprperm + " for " + pp.getPath()
                                     + ": match=" + pp.match(path)
                                     + " check=" + pm.checkUidPermission(pprperm, uid));
                             if (pprperm != null) {
@@ -6650,8 +6647,8 @@
                         }
                         if (!writeMet) {
                             final String ppwperm = pp.getWritePermission();
-                            if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Checking write perm "
-                                    + ppwperm + " for " + pp.getPath()
+                            if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
+                                    "Checking write perm " + ppwperm + " for " + pp.getPath()
                                     + ": match=" + pp.match(path)
                                     + " check=" + pm.checkUidPermission(ppwperm, uid));
                             if (ppwperm != null) {
@@ -6796,7 +6793,7 @@
         }
 
         if (targetPkg != null) {
-            if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+            if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
                     "Checking grant " + targetPkg + " permission to " + grantUri);
         }
 
@@ -6804,7 +6801,7 @@
 
         // If this is not a content: uri, we can't do anything with it.
         if (!ContentResolver.SCHEME_CONTENT.equals(grantUri.uri.getScheme())) {
-            if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+            if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
                     "Can't grant URI permission for non-content URI: " + grantUri);
             return -1;
         }
@@ -6822,7 +6819,7 @@
             try {
                 targetUid = pm.getPackageUid(targetPkg, UserHandle.getUserId(callingUid));
                 if (targetUid < 0) {
-                    if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+                    if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
                             "Can't grant URI permission no uid for: " + targetPkg);
                     return -1;
                 }
@@ -6835,7 +6832,7 @@
             // First...  does the target actually need this permission?
             if (checkHoldingPermissionsLocked(pm, pi, grantUri, targetUid, modeFlags)) {
                 // No need to grant the target this permission.
-                if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+                if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
                         "Target " + targetPkg + " already has full permission to " + grantUri);
                 return -1;
             }
@@ -6932,7 +6929,7 @@
         // to the uri, and the target doesn't.  Let's now give this to
         // the target.
 
-        if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+        if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
                 "Granting " + targetPkg + "/" + targetUid + " permission to " + grantUri);
 
         final String authority = grantUri.uri.getAuthority();
@@ -6990,7 +6987,7 @@
      */
     NeededUriGrants checkGrantUriPermissionFromIntentLocked(int callingUid,
             String targetPkg, Intent intent, int mode, NeededUriGrants needed, int targetUserId) {
-        if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+        if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
                 "Checking URI perm to data=" + (intent != null ? intent.getData() : null)
                 + " clip=" + (intent != null ? intent.getClipData() : null)
                 + " from " + intent + "; flags=0x"
@@ -7024,10 +7021,9 @@
                 return null;
             }
             if (targetUid < 0) {
-                if (DEBUG_URI_PERMISSION) {
-                    Slog.v(TAG, "Can't grant URI permission no uid for: " + targetPkg
-                            + " on user " + targetUserId);
-                }
+                if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
+                        "Can't grant URI permission no uid for: " + targetPkg
+                        + " on user " + targetUserId);
                 return null;
             }
         }
@@ -7134,7 +7130,7 @@
             final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(
                     perm.targetUid);
             if (perms != null) {
-                if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+                if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
                         "Removing " + perm.targetUid + " permission to " + perm.uri);
 
                 perms.remove(perm.uri);
@@ -7146,7 +7142,8 @@
     }
 
     private void revokeUriPermissionLocked(int callingUid, GrantUri grantUri, final int modeFlags) {
-        if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Revoking all granted permissions to " + grantUri);
+        if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
+                "Revoking all granted permissions to " + grantUri);
 
         final IPackageManager pm = AppGlobals.getPackageManager();
         final String authority = grantUri.uri.getAuthority();
@@ -7168,9 +7165,9 @@
                     final UriPermission perm = it.next();
                     if (perm.uri.sourceUserId == grantUri.sourceUserId
                             && perm.uri.uri.isPathPrefixMatch(grantUri.uri)) {
-                        if (DEBUG_URI_PERMISSION)
-                            Slog.v(TAG, "Revoking non-owned " + perm.targetUid +
-                                    " permission to " + perm.uri);
+                        if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
+                                "Revoking non-owned " + perm.targetUid
+                                + " permission to " + perm.uri);
                         persistChanged |= perm.revokeModes(
                                 modeFlags | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, false);
                         if (perm.modeFlags == 0) {
@@ -7200,8 +7197,7 @@
                 final UriPermission perm = it.next();
                 if (perm.uri.sourceUserId == grantUri.sourceUserId
                         && perm.uri.uri.isPathPrefixMatch(grantUri.uri)) {
-                    if (DEBUG_URI_PERMISSION)
-                        Slog.v(TAG,
+                    if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
                                 "Revoking " + perm.targetUid + " permission to " + perm.uri);
                     persistChanged |= perm.revokeModes(
                             modeFlags | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, true);
@@ -7386,7 +7382,7 @@
     }
 
     private void writeGrantedUriPermissions() {
-        if (DEBUG_URI_PERMISSION) Slog.v(TAG, "writeGrantedUriPermissions()");
+        if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION, "writeGrantedUriPermissions()");
 
         // Snapshot permissions so we can persist without lock
         ArrayList<UriPermission.Snapshot> persist = Lists.newArrayList();
@@ -7434,7 +7430,7 @@
     }
 
     private void readGrantedUriPermissionsLocked() {
-        if (DEBUG_URI_PERMISSION) Slog.v(TAG, "readGrantedUriPermissions()");
+        if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION, "readGrantedUriPermissions()");
 
         final long now = System.currentTimeMillis();
 
@@ -7612,9 +7608,8 @@
         for (int i = 0; i < trimCount; i++) {
             final UriPermission perm = persisted.get(i);
 
-            if (DEBUG_URI_PERMISSION) {
-                Slog.v(TAG, "Trimming grant created at " + perm.persistedCreateTime);
-            }
+            if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
+                    "Trimming grant created at " + perm.persistedCreateTime);
 
             perm.releasePersistableModes(~0);
             removeUriPermissionIfNeededLocked(perm);
@@ -7844,7 +7839,7 @@
                 TaskRecord tr = mRecentTasks.get(i);
                 // Only add calling user or related users recent tasks
                 if (!includedUsers.contains(Integer.valueOf(tr.userId))) {
-                    if (DEBUG_RECENTS) Slog.d(TAG, "Skipping, not user: " + tr);
+                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not user: " + tr);
                     continue;
                 }
 
@@ -7863,25 +7858,27 @@
                         // If the caller doesn't have the GET_TASKS permission, then only
                         // allow them to see a small subset of tasks -- their own and home.
                         if (!tr.isHomeTask() && tr.effectiveUid != callingUid) {
-                            if (DEBUG_RECENTS) Slog.d(TAG, "Skipping, not allowed: " + tr);
+                            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not allowed: " + tr);
                             continue;
                         }
                     }
                     if ((flags & ActivityManager.RECENT_IGNORE_HOME_STACK_TASKS) != 0) {
                         if (tr.stack != null && tr.stack.isHomeStack()) {
-                            if (DEBUG_RECENTS) Slog.d(TAG, "Skipping, home stack task: " + tr);
+                            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
+                                    "Skipping, home stack task: " + tr);
                             continue;
                         }
                     }
                     if (tr.autoRemoveRecents && tr.getTopActivity() == null) {
                         // Don't include auto remove tasks that are finished or finishing.
-                        if (DEBUG_RECENTS) Slog.d(TAG, "Skipping, auto-remove without activity: "
-                                + tr);
+                        if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
+                                "Skipping, auto-remove without activity: " + tr);
                         continue;
                     }
                     if ((flags&ActivityManager.RECENT_IGNORE_UNAVAILABLE) != 0
                             && !tr.isAvailable) {
-                        if (DEBUG_RECENTS) Slog.d(TAG, "Skipping, unavail real act: " + tr);
+                        if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
+                                "Skipping, unavail real act: " + tr);
                         continue;
                     }
 
@@ -8215,10 +8212,9 @@
      */
     @Override
     public void moveTaskToFront(int taskId, int flags, Bundle options) {
-        enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
-                "moveTaskToFront()");
+        enforceCallingPermission(android.Manifest.permission.REORDER_TASKS, "moveTaskToFront()");
 
-        if (DEBUG_STACK) Slog.d(TAG, "moveTaskToFront: moving taskId=" + taskId);
+        if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToFront: moving taskId=" + taskId);
         synchronized(this) {
             moveTaskToFrontLocked(taskId, flags, options);
         }
@@ -8378,8 +8374,8 @@
         synchronized (this) {
             long ident = Binder.clearCallingIdentity();
             try {
-                if (DEBUG_STACK) Slog.d(TAG, "moveTaskToStack: moving task=" + taskId + " to stackId="
-                        + stackId + " toTop=" + toTop);
+                if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToStack: moving task=" + taskId
+                        + " to stackId=" + stackId + " toTop=" + toTop);
                 mStackSupervisor.moveTaskToStackLocked(taskId, stackId, toTop);
             } finally {
                 Binder.restoreCallingIdentity(ident);
@@ -8790,7 +8786,7 @@
             for (int i=0; i<r.conProviders.size(); i++) {
                 ContentProviderConnection conn = r.conProviders.get(i);
                 if (conn.provider == cpr) {
-                    if (DEBUG_PROVIDER) Slog.v(TAG,
+                    if (DEBUG_PROVIDER) Slog.v(TAG_PROVIDER,
                             "Adding provider requested by "
                             + r.processName + " from process "
                             + cpr.info.processName + ": " + cpr.name.flattenToShortString()
@@ -8826,7 +8822,7 @@
             ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable) {
         if (conn != null) {
             cpr = conn.provider;
-            if (DEBUG_PROVIDER) Slog.v(TAG,
+            if (DEBUG_PROVIDER) Slog.v(TAG_PROVIDER,
                     "Removing provider requested by "
                     + conn.client.processName + " from process "
                     + cpr.info.processName + ": " + cpr.name.flattenToShortString()
@@ -8954,7 +8950,7 @@
                     checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
                     boolean success = updateOomAdjLocked(cpr.proc);
                     checkTime(startTime, "getContentProviderImpl: after updateOomAdj");
-                    if (DEBUG_PROVIDER) Slog.i(TAG, "Adjust success: " + success);
+                    if (DEBUG_PROVIDER) Slog.i(TAG_PROVIDER, "Adjust success: " + success);
                     // NOTE: there is still a race here where a signal could be
                     // pending on the process even though we managed to update its
                     // adj level.  Not sure what to do about this, but at least
@@ -8964,8 +8960,7 @@
                         // has been killed on us.  We need to wait for a new
                         // process to be started, and make sure its death
                         // doesn't kill our process.
-                        Slog.i(TAG,
-                                "Existing provider " + cpr.name.flattenToShortString()
+                        Slog.i(TAG, "Existing provider " + cpr.name.flattenToShortString()
                                 + " is crashing; detaching " + r);
                         boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
                         checkTime(startTime, "getContentProviderImpl: before appDied");
@@ -9076,18 +9071,16 @@
                     return cpr.newHolder(null);
                 }
 
-                if (DEBUG_PROVIDER) {
-                    RuntimeException e = new RuntimeException("here");
-                    Slog.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + (r != null ? r.uid : null)
-                          + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
-                }
+                if (DEBUG_PROVIDER) Slog.w(TAG_PROVIDER, "LAUNCHING REMOTE PROVIDER (myuid "
+                            + (r != null ? r.uid : null) + " pruid " + cpr.appInfo.uid + "): "
+                            + cpr.info.name + " callers=" + Debug.getCallers(6));
 
                 // This is single process, and our app is now connecting to it.
                 // See if we are already in the process of launching this
                 // provider.
                 final int N = mLaunchingProviders.size();
                 int i;
-                for (i=0; i<N; i++) {
+                for (i = 0; i < N; i++) {
                     if (mLaunchingProviders.get(i) == cpr) {
                         break;
                     }
@@ -9116,9 +9109,8 @@
                         ProcessRecord proc = getProcessRecordLocked(
                                 cpi.processName, cpr.appInfo.uid, false);
                         if (proc != null && proc.thread != null) {
-                            if (DEBUG_PROVIDER) {
-                                Slog.d(TAG, "Installing in existing process " + proc);
-                            }
+                            if (DEBUG_PROVIDER) Slog.d(TAG_PROVIDER,
+                                    "Installing in existing process " + proc);
                             if (!proc.pubProviders.containsKey(cpi.name)) {
                                 checkTime(startTime, "getContentProviderImpl: scheduling install");
                                 proc.pubProviders.put(cpi.name, cpr);
@@ -9833,7 +9825,7 @@
     }
 
     void logLockScreen(String msg) {
-        if (DEBUG_LOCKSCREEN) Slog.d(TAG, Debug.getCallers(2) + ":" + msg
+        if (DEBUG_LOCKSCREEN) Slog.d(TAG_LOCKSCREEN, Debug.getCallers(2) + ":" + msg
                 + " mLockScreenShown=" + lockScreenShownToString() + " mWakefulness="
                 + PowerManagerInternal.wakefulnessToString(mWakefulness)
                 + " mSleeping=" + mSleeping);
@@ -14905,8 +14897,8 @@
             throw new IllegalArgumentException("File descriptors passed in Intent");
         }
 
-        if (DEBUG_SERVICE)
-            Slog.v(TAG, "startService: " + service + " type=" + resolvedType);
+        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
+                "startService: " + service + " type=" + resolvedType);
         synchronized(this) {
             final int callingPid = Binder.getCallingPid();
             final int callingUid = Binder.getCallingUid();
@@ -14921,8 +14913,8 @@
     ComponentName startServiceInPackage(int uid, Intent service, String resolvedType, int userId)
             throws TransactionTooLargeException {
         synchronized(this) {
-            if (DEBUG_SERVICE)
-                Slog.v(TAG, "startServiceInPackage: " + service + " type=" + resolvedType);
+            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
+                    "startServiceInPackage: " + service + " type=" + resolvedType);
             final long origId = Binder.clearCallingIdentity();
             ComponentName res = mServices.startServiceLocked(null, service,
                     resolvedType, -1, uid, userId);
@@ -17388,11 +17380,11 @@
      * Record new PSS sample for a process.
      */
     void recordPssSampleLocked(ProcessRecord proc, int procState, long pss, long uss, long now) {
-        EventLogTags.writeAmPss(proc.pid, proc.uid, proc.processName, pss*1024, uss*1024);
+        EventLogTags.writeAmPss(proc.pid, proc.uid, proc.processName, pss * 1024, uss * 1024);
         proc.lastPssTime = now;
         proc.baseProcessTracker.addPss(pss, uss, true, proc.pkgList);
-        if (DEBUG_PSS) Slog.d(TAG, "PSS of " + proc.toShortString()
-                + ": " + pss + " lastPss=" + proc.lastPss
+        if (DEBUG_PSS) Slog.d(TAG_PSS,
+                "PSS of " + proc.toShortString() + ": " + pss + " lastPss=" + proc.lastPss
                 + " state=" + ProcessList.makeProcStateString(procState));
         if (proc.initialIdlePss == 0) {
             proc.initialIdlePss = pss;
@@ -17404,7 +17396,7 @@
 
         Long check = mMemWatchProcesses.get(proc.processName);
         if (check != null) {
-            if ((pss*1024) >= check && proc.thread != null && mMemWatchDumpProcName == null) {
+            if ((pss * 1024) >= check && proc.thread != null && mMemWatchDumpProcName == null) {
                 boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
                 if (!isDebuggable) {
                     if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
@@ -17438,7 +17430,7 @@
                                 IApplicationThread thread = myProc.thread;
                                 if (thread != null) {
                                     try {
-                                        if (DEBUG_PSS) Slog.d(TAG, "Requesting dump heap from "
+                                        if (DEBUG_PSS) Slog.d(TAG_PSS, "Requesting dump heap from "
                                                 + myProc + " to " + heapdumpFile);
                                         thread.dumpHeap(true, heapdumpFile.toString(), fd);
                                     } catch (RemoteException e) {
@@ -17474,7 +17466,7 @@
         if (mPendingPssProcesses.size() == 0) {
             mBgHandler.sendEmptyMessage(COLLECT_PSS_BG_MSG);
         }
-        if (DEBUG_PSS) Slog.d(TAG, "Requesting PSS of: " + proc);
+        if (DEBUG_PSS) Slog.d(TAG_PSS, "Requesting PSS of: " + proc);
         proc.pssProcState = procState;
         mPendingPssProcesses.add(proc);
     }
@@ -17489,7 +17481,7 @@
                 return;
             }
         }
-        if (DEBUG_PSS) Slog.d(TAG, "Requesting PSS of all procs!  memLowered=" + memLowered);
+        if (DEBUG_PSS) Slog.d(TAG_PSS, "Requesting PSS of all procs!  memLowered=" + memLowered);
         mLastFullPssTime = now;
         mFullPssPending = true;
         mPendingPssProcesses.ensureCapacity(mLruProcesses.size());
@@ -17705,7 +17697,7 @@
                     sb.append(" (");
                     sb.append((wtimeUsed*100)/realtimeSince);
                     sb.append("%)");
-                    Slog.i(TAG, sb.toString());
+                    Slog.i(TAG_POWER, sb.toString());
                     sb.setLength(0);
                     sb.append("CPU for ");
                     app.toShortString(sb);
@@ -17716,7 +17708,7 @@
                     sb.append(" (");
                     sb.append((cputimeUsed*100)/uptimeSince);
                     sb.append("%)");
-                    Slog.i(TAG, sb.toString());
+                    Slog.i(TAG_POWER, sb.toString());
                 }
                 // If a process has held a wake lock for more
                 // than 50% of the time during this period,
@@ -17833,7 +17825,7 @@
             app.lastStateTime = now;
             app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, true,
                     mTestPssMode, isSleeping(), now);
-            if (DEBUG_PSS) Slog.d(TAG, "Process state change from "
+            if (DEBUG_PSS) Slog.d(TAG_PSS, "Process state change from "
                     + ProcessList.makeProcStateString(app.setProcState) + " to "
                     + ProcessList.makeProcStateString(app.curProcState) + " next pss in "
                     + (app.nextPssTime-now) + ": " + app);
@@ -17844,9 +17836,8 @@
                 requestPssLocked(app, app.setProcState);
                 app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, false,
                         mTestPssMode, isSleeping(), now);
-            } else if (false && DEBUG_PSS) {
-                Slog.d(TAG, "Not requesting PSS of " + app + ": next=" + (app.nextPssTime-now));
-            }
+            } else if (false && DEBUG_PSS) Slog.d(TAG_PSS,
+                    "Not requesting PSS of " + app + ": next=" + (app.nextPssTime-now));
         }
         if (app.setProcState != app.curProcState) {
             if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
@@ -17879,13 +17870,15 @@
         }
 
         if (changes != 0) {
-            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Changes in " + app + ": " + changes);
+            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                    "Changes in " + app + ": " + changes);
             int i = mPendingProcessChanges.size()-1;
             ProcessChangeItem item = null;
             while (i >= 0) {
                 item = mPendingProcessChanges.get(i);
                 if (item.pid == app.pid) {
-                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Re-using existing item: " + item);
+                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                            "Re-using existing item: " + item);
                     break;
                 }
                 i--;
@@ -17895,16 +17888,18 @@
                 final int NA = mAvailProcessChanges.size();
                 if (NA > 0) {
                     item = mAvailProcessChanges.remove(NA-1);
-                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Retreiving available item: " + item);
+                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                            "Retreiving available item: " + item);
                 } else {
                     item = new ProcessChangeItem();
-                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Allocating new item: " + item);
+                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                            "Allocating new item: " + item);
                 }
                 item.changes = 0;
                 item.pid = app.pid;
                 item.uid = app.info.uid;
                 if (mPendingProcessChanges.size() == 0) {
-                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG,
+                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
                             "*** Enqueueing dispatch processes changed!");
                     mHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED).sendToTarget();
                 }
@@ -17913,8 +17908,8 @@
             item.changes |= changes;
             item.processState = app.repProcState;
             item.foregroundActivities = app.repForegroundActivities;
-            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Item "
-                    + Integer.toHexString(System.identityHashCode(item))
+            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                    "Item " + Integer.toHexString(System.identityHashCode(item))
                     + " " + app.toShortString() + ": changes=" + item.changes
                     + " procState=" + item.processState
                     + " foreground=" + item.foregroundActivities
@@ -18670,7 +18665,7 @@
                         + " does not match last path " + mMemWatchDumpFile);
                 return;
             }
-            if (DEBUG_PSS) Slog.d(TAG, "Dump heap finished for " + path);
+            if (DEBUG_PSS) Slog.d(TAG_PSS, "Dump heap finished for " + path);
             mHandler.sendEmptyMessage(POST_DUMP_HEAP_NOTIFICATION_MSG);
         }
     }
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index d34b33b..f3b18f5 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -17,8 +17,6 @@
 package com.android.server.am;
 
 import static com.android.server.am.ActivityManagerDebugConfig.*;
-import static com.android.server.am.ActivityManagerService.DEBUG_SWITCH;
-import static com.android.server.am.ActivityManagerService.DEBUG_THUMBNAILS;
 import static com.android.server.am.TaskPersister.DEBUG_PERSISTER;
 import static com.android.server.am.TaskPersister.DEBUG_RESTORER;
 import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
@@ -75,6 +73,8 @@
  */
 final class ActivityRecord {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityRecord" : TAG_AM;
+    private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
+    private static final String TAG_THUMBNAILS = TAG + POSTFIX_THUMBNAILS;
 
     private static final boolean SHOW_ACTIVITY_START_TIME = true;
     static final boolean DEBUG_SAVED_STATE = ActivityStackSupervisor.DEBUG_SAVED_STATE;
@@ -354,7 +354,7 @@
             synchronized (mService) {
                 ActivityRecord r = tokenToActivityRecordLocked(this);
                 if (r != null) {
-                    if (DEBUG_SWITCH) Log.v(TAG, "windowsGone(): " + r);
+                    if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsGone(): " + r);
                     r.nowVisible = false;
                     return;
                 }
@@ -863,7 +863,7 @@
 
     void updateThumbnailLocked(Bitmap newThumbnail, CharSequence description) {
         if (newThumbnail != null) {
-            if (DEBUG_THUMBNAILS) Slog.i(TAG,
+            if (DEBUG_THUMBNAILS) Slog.i(TAG_THUMBNAILS,
                     "Setting thumbnail of " + this + " to " + newThumbnail);
             boolean thumbnailUpdated = task.setLastThumbnail(newThumbnail);
             if (thumbnailUpdated && isPersistable()) {
@@ -1014,7 +1014,7 @@
 
     void windowsVisibleLocked() {
         mStackSupervisor.reportActivityVisibleLocked(this);
-        if (DEBUG_SWITCH) Log.v(TAG, "windowsVisibleLocked(): " + this);
+        if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsVisibleLocked(): " + this);
         if (!nowVisible) {
             nowVisible = true;
             lastVisibleTime = SystemClock.uptimeMillis();
@@ -1030,7 +1030,7 @@
                 if (size > 0) {
                     for (int i = 0; i < size; i++) {
                         ActivityRecord r = mStackSupervisor.mWaitingVisibleActivities.get(i);
-                        if (DEBUG_SWITCH) Log.v(TAG, "Was waiting for visible: " + r);
+                        if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "Was waiting for visible: " + r);
                     }
                     mStackSupervisor.mWaitingVisibleActivities.clear();
                     mStackSupervisor.scheduleIdleLocked();
@@ -1041,24 +1041,21 @@
     }
 
     ActivityRecord getWaitingHistoryRecordLocked() {
-        // First find the real culprit...  if we are waiting
-        // for another app to start, then we have paused dispatching
-        // for this activity.
-        ActivityRecord r = this;
-        if (mStackSupervisor.mWaitingVisibleActivities.contains(this)) {
+        // First find the real culprit...  if this activity is waiting for
+        // another activity to start or has stopped, then the key dispatching
+        // timeout should not be caused by this.
+        if (mStackSupervisor.mWaitingVisibleActivities.contains(this) || stopped) {
             final ActivityStack stack = mStackSupervisor.getFocusedStack();
-            // Hmmm, who might we be waiting for?
-            r = stack.mResumedActivity;
+            // Try to use the one which is closest to top.
+            ActivityRecord r = stack.mResumedActivity;
             if (r == null) {
                 r = stack.mPausingActivity;
             }
-            // Both of those null?  Fall back to 'this' again
-            if (r == null) {
-                r = this;
+            if (r != null) {
+                return r;
             }
         }
-
-        return r;
+        return this;
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 8ba34e2..a8deea3 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -17,14 +17,6 @@
 package com.android.server.am;
 
 import static com.android.server.am.ActivityManagerDebugConfig.*;
-import static com.android.server.am.ActivityManagerService.DEBUG_PAUSE;
-import static com.android.server.am.ActivityManagerService.DEBUG_RESULTS;
-import static com.android.server.am.ActivityManagerService.DEBUG_STACK;
-import static com.android.server.am.ActivityManagerService.DEBUG_SWITCH;
-import static com.android.server.am.ActivityManagerService.DEBUG_TASKS;
-import static com.android.server.am.ActivityManagerService.DEBUG_TRANSITION;
-import static com.android.server.am.ActivityManagerService.DEBUG_USER_LEAVING;
-import static com.android.server.am.ActivityManagerService.DEBUG_VISBILITY;
 
 import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
@@ -96,6 +88,14 @@
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStack" : TAG_AM;
     private static final String TAG_CLEANUP = TAG + POSTFIX_CLEANUP;
     private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
+    private static final String TAG_PAUSE = TAG + POSTFIX_PAUSE;
+    private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS;
+    private static final String TAG_STACK = TAG + POSTFIX_STACK;
+    private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
+    private static final String TAG_TASKS = TAG + POSTFIX_TASKS;
+    private static final String TAG_TRANSITION = TAG + POSTFIX_TRANSITION;
+    private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING;
+    private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
 
     private static final boolean VALIDATE_TOKENS = false;
 
@@ -538,23 +538,23 @@
         // If documentData is non-null then it must match the existing task data.
         Uri documentData = isDocument ? intent.getData() : null;
 
-        if (DEBUG_TASKS) Slog.d(TAG, "Looking for task of " + target + " in " + this);
+        if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + target + " in " + this);
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             final TaskRecord task = mTaskHistory.get(taskNdx);
             if (task.voiceSession != null) {
                 // We never match voice sessions; those always run independently.
-                if (DEBUG_TASKS) Slog.d(TAG, "Skipping " + task + ": voice session");
+                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": voice session");
                 continue;
             }
             if (task.userId != userId) {
                 // Looking for a different task.
-                if (DEBUG_TASKS) Slog.d(TAG, "Skipping " + task + ": different user");
+                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": different user");
                 continue;
             }
             final ActivityRecord r = task.getTopActivity();
             if (r == null || r.finishing || r.userId != userId ||
                     r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
-                if (DEBUG_TASKS) Slog.d(TAG, "Skipping " + task + ": mismatch root " + r);
+                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": mismatch root " + r);
                 continue;
             }
 
@@ -573,34 +573,32 @@
                 taskDocumentData = null;
             }
 
-            if (DEBUG_TASKS) Slog.d(TAG, "Comparing existing cls="
+            if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Comparing existing cls="
                     + taskIntent.getComponent().flattenToShortString()
                     + "/aff=" + r.task.rootAffinity + " to new cls="
                     + intent.getComponent().flattenToShortString() + "/aff=" + info.taskAffinity);
             if (!isDocument && !taskIsDocument && task.rootAffinity != null) {
                 if (task.rootAffinity.equals(target.taskAffinity)) {
-                    if (DEBUG_TASKS) Slog.d(TAG, "Found matching affinity!");
+                    if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching affinity!");
                     return r;
                 }
             } else if (taskIntent != null && taskIntent.getComponent() != null &&
                     taskIntent.getComponent().compareTo(cls) == 0 &&
                     Objects.equals(documentData, taskDocumentData)) {
-                if (DEBUG_TASKS) Slog.d(TAG, "Found matching class!");
+                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching class!");
                 //dump();
-                if (DEBUG_TASKS) Slog.d(TAG, "For Intent " + intent + " bringing to top: "
-                        + r.intent);
+                if (DEBUG_TASKS) Slog.d(TAG_TASKS,
+                        "For Intent " + intent + " bringing to top: " + r.intent);
                 return r;
             } else if (affinityIntent != null && affinityIntent.getComponent() != null &&
                     affinityIntent.getComponent().compareTo(cls) == 0 &&
                     Objects.equals(documentData, taskDocumentData)) {
-                if (DEBUG_TASKS) Slog.d(TAG, "Found matching class!");
+                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching class!");
                 //dump();
-                if (DEBUG_TASKS) Slog.d(TAG, "For Intent " + intent + " bringing to top: "
-                        + r.intent);
+                if (DEBUG_TASKS) Slog.d(TAG_TASKS,
+                        "For Intent " + intent + " bringing to top: " + r.intent);
                 return r;
-            } else if (DEBUG_TASKS) {
-                Slog.d(TAG, "Not a match: " + task);
-            }
+            } else if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Not a match: " + task);
         }
 
         return null;
@@ -652,7 +650,7 @@
         for (int i = 0; i < index; ) {
             TaskRecord task = mTaskHistory.get(i);
             if (isCurrentProfileLocked(task.userId)) {
-                if (DEBUG_TASKS) Slog.d(TAG, "switchUserLocked: stack=" + getStackId() +
+                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "switchUserLocked: stack=" + getStackId() +
                         " moving " + task + " to top");
                 mTaskHistory.remove(i);
                 mTaskHistory.add(task);
@@ -739,14 +737,15 @@
     boolean checkReadyForSleepLocked() {
         if (mResumedActivity != null) {
             // Still have something resumed; can't sleep until it is paused.
-            if (DEBUG_PAUSE) Slog.v(TAG, "Sleep needs to pause " + mResumedActivity);
-            if (DEBUG_USER_LEAVING) Slog.v(TAG, "Sleep => pause with userLeaving=false");
+            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep needs to pause " + mResumedActivity);
+            if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
+                    "Sleep => pause with userLeaving=false");
             startPausingLocked(false, true, false, false);
             return true;
         }
         if (mPausingActivity != null) {
             // Still waiting for something to pause; can't sleep yet.
-            if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still waiting to pause " + mPausingActivity);
+            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still waiting to pause " + mPausingActivity);
             return true;
         }
 
@@ -829,7 +828,7 @@
         }
 
         if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSING: " + prev);
-        else if (DEBUG_PAUSE) Slog.v(TAG, "Start pausing: " + prev);
+        else if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Start pausing: " + prev);
         mResumedActivity = null;
         mPausingActivity = prev;
         mLastPausedActivity = prev;
@@ -847,7 +846,7 @@
         mService.updateCpuStats();
 
         if (prev.app != null && prev.app.thread != null) {
-            if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending pause: " + prev);
+            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
             try {
                 EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
                         prev.userId, System.identityHashCode(prev),
@@ -881,8 +880,8 @@
             // key dispatch; the same activity will pick it up again on wakeup.
             if (!uiSleeping) {
                 prev.pauseKeyDispatchingLocked();
-            } else {
-                if (DEBUG_PAUSE) Slog.v(TAG, "Key dispatch not paused for screen off");
+            } else if (DEBUG_PAUSE) {
+                 Slog.v(TAG_PAUSE, "Key dispatch not paused for screen off");
             }
 
             if (dontWait) {
@@ -899,14 +898,14 @@
                 msg.obj = prev;
                 prev.pauseTime = SystemClock.uptimeMillis();
                 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
-                if (DEBUG_PAUSE) Slog.v(TAG, "Waiting for pause to complete...");
+                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Waiting for pause to complete...");
                 return true;
             }
 
         } else {
             // This activity failed to schedule the
             // pause, so just treat it as being paused now.
-            if (DEBUG_PAUSE) Slog.v(TAG, "Activity not running, resuming next.");
+            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Activity not running, resuming next.");
             if (!resuming) {
                 mStackSupervisor.getFocusedStack().resumeTopActivityLocked(null);
             }
@@ -915,8 +914,8 @@
     }
 
     final void activityPausedLocked(IBinder token, boolean timeout) {
-        if (DEBUG_PAUSE) Slog.v(
-            TAG, "Activity paused: token=" + token + ", timeout=" + timeout);
+        if (DEBUG_PAUSE) Slog.v(TAG_PAUSE,
+            "Activity paused: token=" + token + ", timeout=" + timeout);
 
         final ActivityRecord r = isInStackLocked(token);
         if (r != null) {
@@ -977,18 +976,18 @@
 
     private void completePauseLocked(boolean resumeNext) {
         ActivityRecord prev = mPausingActivity;
-        if (DEBUG_PAUSE) Slog.v(TAG, "Complete pause: " + prev);
+        if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Complete pause: " + prev);
 
         if (prev != null) {
             prev.state = ActivityState.PAUSED;
             if (prev.finishing) {
-                if (DEBUG_PAUSE) Slog.v(TAG, "Executing finish of activity: " + prev);
+                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Executing finish of activity: " + prev);
                 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false);
             } else if (prev.app != null) {
-                if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending stop: " + prev);
+                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending stop: " + prev);
                 if (mStackSupervisor.mWaitingVisibleActivities.remove(prev)) {
-                    if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(
-                            TAG, "Complete pause, no longer waiting: " + prev);
+                    if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(TAG_PAUSE,
+                            "Complete pause, no longer waiting: " + prev);
                 }
                 if (prev.configDestroy) {
                     // The previous is being paused because the configuration
@@ -996,7 +995,7 @@
                     // To juggle the fact that we are also starting a new
                     // 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);
+                    if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Destroying after pause: " + prev);
                     destroyActivityLocked(prev, true, "pause-config");
                 } else if (!hasVisibleBehindActivity()) {
                     // If we were visible then resumeTopActivities will release resources before
@@ -1008,14 +1007,14 @@
                         // then give up on things going idle and start clearing
                         // them out. Or if r is the last of activity of the last task the stack
                         // will be empty and must be cleared immediately.
-                        if (DEBUG_PAUSE) Slog.v(TAG, "To many pending stops, forcing idle");
+                        if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "To many pending stops, forcing idle");
                         mStackSupervisor.scheduleIdleLocked();
                     } else {
                         mStackSupervisor.checkReadyForSleepLocked();
                     }
                 }
             } else {
-                if (DEBUG_PAUSE) Slog.v(TAG, "App died during pause, not stopping: " + prev);
+                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "App died during pause, not stopping: " + prev);
                 prev = null;
             }
             // It is possible the activity was freezing the screen before it was paused.
@@ -1246,8 +1245,8 @@
         if (top == null) {
             return;
         }
-        if (DEBUG_VISBILITY) Slog.v(
-                TAG, "ensureActivitiesVisible behind " + top
+        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+                "ensureActivitiesVisible behind " + top
                 + " configChanges=0x" + Integer.toHexString(configChanges));
 
         if (DEBUG_STATES && starting != null && starting.task.stack == this) {
@@ -1285,8 +1284,8 @@
                 // mLaunchingBehind: Activities launching behind are at the back of the task stack
                 // but must be drawn initially for the animation as though they were visible.
                 if (!behindFullscreen || r.mLaunchTaskBehind) {
-                    if (DEBUG_VISBILITY) Slog.v(
-                            TAG, "Make visible? " + r + " finishing=" + r.finishing
+                    if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+                            "Make visible? " + r + " finishing=" + r.finishing
                             + " state=" + r.state);
 
                     // First: if this is not the current activity being started, make
@@ -1299,13 +1298,14 @@
                         // This activity needs to be visible, but isn't even
                         // running...  get it started, but don't resume it
                         // at this point.
-                        if (DEBUG_VISBILITY) Slog.v(TAG, "Start and freeze screen for " + r);
+                        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+                                "Start and freeze screen for " + r);
                         if (r != starting) {
                             r.startFreezingScreenLocked(r.app, configChanges);
                         }
                         if (!r.visible || r.mLaunchTaskBehind) {
-                            if (DEBUG_VISBILITY) Slog.v(
-                                    TAG, "Starting and making visible: " + r);
+                            if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+                                    "Starting and making visible: " + r);
                             setVisible(r, true);
                         }
                         if (r != starting) {
@@ -1315,7 +1315,8 @@
                     } else if (r.visible) {
                         // If this activity is already visible, then there is nothing
                         // else to do here.
-                        if (DEBUG_VISBILITY) Slog.v(TAG, "Skipping: already visible at " + r);
+                        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+                                "Skipping: already visible at " + r);
                         r.stopFreezingScreenLocked(false);
                         try {
                             if (r.returningOptions != null) {
@@ -1331,8 +1332,8 @@
                         if (r.state != ActivityState.RESUMED && r != starting) {
                             // If this activity is paused, tell it
                             // to now show its window.
-                            if (DEBUG_VISBILITY) Slog.v(
-                                    TAG, "Making visible and scheduling visibility: " + r);
+                            if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+                                    "Making visible and scheduling visibility: " + r);
                             try {
                                 if (mTranslucentActivityWaiting != null) {
                                     r.updateOptionsLocked(r.returningOptions);
@@ -1357,29 +1358,28 @@
 
                     if (r.fullscreen) {
                         // At this point, nothing else needs to be shown
-                        if (DEBUG_VISBILITY) Slog.v(TAG, "Fullscreen: at " + r);
+                        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Fullscreen: at " + r);
                         behindFullscreen = true;
                     } else if (!isHomeStack() && r.frontOfTask && task.isOverHomeStack()) {
-                        if (DEBUG_VISBILITY) Slog.v(TAG, "Showing home: at " + r);
+                        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Showing home: at " + r);
                         behindFullscreen = true;
                     }
                 } else {
-                    if (DEBUG_VISBILITY) Slog.v(
-                        TAG, "Make invisible? " + r + " finishing=" + r.finishing
-                        + " state=" + r.state
-                        + " behindFullscreen=" + behindFullscreen);
+                    if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+                        "Make invisible? " + r + " finishing=" + r.finishing
+                        + " state=" + r.state + " behindFullscreen=" + behindFullscreen);
                     // Now for any activities that aren't visible to the user, make
                     // sure they no longer are keeping the screen frozen.
                     if (r.visible) {
-                        if (DEBUG_VISBILITY) Slog.v(TAG, "Making invisible: " + r);
+                        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Making invisible: " + r);
                         try {
                             setVisible(r, false);
                             switch (r.state) {
                                 case STOPPING:
                                 case STOPPED:
                                     if (r.app != null && r.app.thread != null) {
-                                        if (DEBUG_VISBILITY) Slog.v(
-                                                TAG, "Scheduling invisibility: " + r);
+                                        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+                                                "Scheduling invisibility: " + r);
                                         r.app.thread.scheduleWindowVisibility(r.appToken, false);
                                     }
                                     break;
@@ -1410,7 +1410,7 @@
                                     + r.intent.getComponent(), e);
                         }
                     } else {
-                        if (DEBUG_VISBILITY) Slog.v(TAG, "Already invisible: " + r);
+                        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Already invisible: " + r);
                     }
                 }
             }
@@ -1480,7 +1480,8 @@
                 }
 
                 if (r.state == ActivityState.INITIALIZING && r.mStartingWindowShown) {
-                    if (DEBUG_VISBILITY) Slog.w(TAG, "Found orphaned starting window " + r);
+                    if (DEBUG_VISIBILITY) Slog.w(TAG_VISIBILITY,
+                            "Found orphaned starting window " + r);
                     r.mStartingWindowShown = false;
                     mWindowManager.removeAppStartingWindow(r.appToken);
                 }
@@ -1523,7 +1524,7 @@
     }
 
     private boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
-        if (ActivityManagerService.DEBUG_LOCKSCREEN) mService.logLockScreen("");
+        if (DEBUG_LOCKSCREEN) mService.logLockScreen("");
 
         if (!mService.mBooting && !mService.mBooted) {
             // Not ready yet!
@@ -1641,12 +1642,12 @@
         next.sleeping = false;
         mStackSupervisor.mWaitingVisibleActivities.remove(next);
 
-        if (DEBUG_SWITCH) Slog.v(TAG, "Resuming " + next);
+        if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next);
 
         // If we are currently pausing an activity, then don't do anything
         // until that is done.
         if (!mStackSupervisor.allPausedActivitiesComplete()) {
-            if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG,
+            if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
                     "resumeTopActivityLocked: Skip resume: some activity pausing.");
             if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
             return false;
@@ -1721,8 +1722,8 @@
             if (!mStackSupervisor.mWaitingVisibleActivities.contains(prev)
                     && next != null && !next.nowVisible) {
                 mStackSupervisor.mWaitingVisibleActivities.add(prev);
-                if (DEBUG_SWITCH) Slog.v(
-                        TAG, "Resuming top, waiting visible to hide: " + prev);
+                if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
+                        "Resuming top, waiting visible to hide: " + prev);
             } else {
                 // The next activity is already visible, so hide the previous
                 // activity's windows right now so we can show the new one ASAP.
@@ -1734,16 +1735,16 @@
                 // new one is found to be full-screen or not.
                 if (prev.finishing) {
                     mWindowManager.setAppVisibility(prev.appToken, false);
-                    if (DEBUG_SWITCH) Slog.v(TAG, "Not waiting for visible to hide: "
-                            + prev + ", waitingVisible="
+                    if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
+                            "Not waiting for visible to hide: " + prev + ", waitingVisible="
                             + mStackSupervisor.mWaitingVisibleActivities.contains(prev)
                             + ", nowVisible=" + next.nowVisible);
                 } else {
-                    if (DEBUG_SWITCH) Slog.v(TAG,
+                    if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
                             "Previous already visible but still waiting to hide: " + prev
-                                    + ", waitingVisible="
-                                    + mStackSupervisor.mWaitingVisibleActivities.contains(prev)
-                                    + ", nowVisible=" + next.nowVisible);
+                            + ", waitingVisible="
+                            + mStackSupervisor.mWaitingVisibleActivities.contains(prev)
+                            + ", nowVisible=" + next.nowVisible);
                 }
             }
         }
@@ -1765,7 +1766,7 @@
         boolean anim = true;
         if (prev != null) {
             if (prev.finishing) {
-                if (DEBUG_TRANSITION) Slog.v(TAG,
+                if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
                         "Prepare close transition: prev=" + prev);
                 if (mNoAnimActivities.contains(prev)) {
                     anim = false;
@@ -1778,7 +1779,8 @@
                 mWindowManager.setAppWillBeHidden(prev.appToken);
                 mWindowManager.setAppVisibility(prev.appToken, false);
             } else {
-                if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare open transition: prev=" + prev);
+                if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
+                        "Prepare open transition: prev=" + prev);
                 if (mNoAnimActivities.contains(next)) {
                     anim = false;
                     mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false);
@@ -1795,7 +1797,7 @@
                 mWindowManager.setAppVisibility(prev.appToken, false);
             }
         } else {
-            if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare open transition: no previous");
+            if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: no previous");
             if (mNoAnimActivities.contains(next)) {
                 anim = false;
                 mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false);
@@ -1817,7 +1819,7 @@
 
         ActivityStack lastStack = mStackSupervisor.getLastStack();
         if (next.app != null && next.app.thread != null) {
-            if (DEBUG_SWITCH) Slog.v(TAG, "Resume running: " + next);
+            if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resume running: " + next);
 
             // This activity is now becoming visible.
             mWindowManager.setAppVisibility(next.appToken, true);
@@ -1882,9 +1884,8 @@
                 if (a != null) {
                     final int N = a.size();
                     if (!next.finishing && N > 0) {
-                        if (DEBUG_RESULTS) Slog.v(
-                                TAG, "Delivering results to " + next
-                                + ": " + a);
+                        if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
+                                "Delivering results to " + next + ": " + a);
                         next.app.thread.scheduleSendResult(next.appToken, a);
                     }
                 }
@@ -1961,7 +1962,7 @@
                             next.labelRes, next.icon, next.logo, next.windowFlags,
                             null, true);
                 }
-                if (DEBUG_SWITCH) Slog.v(TAG, "Restarting: " + next);
+                if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next);
             }
             if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Restarting " + next);
             mStackSupervisor.startSpecificActivityLocked(next, true, true);
@@ -2083,7 +2084,7 @@
         // activity
         if (task == r.task && mTaskHistory.indexOf(task) != (mTaskHistory.size() - 1)) {
             mStackSupervisor.mUserLeaving = false;
-            if (DEBUG_USER_LEAVING) Slog.v(TAG,
+            if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
                     "startActivity() behind front, mUserLeaving=false");
         }
 
@@ -2108,9 +2109,9 @@
             if (proc == null || proc.thread == null) {
                 showStartingIcon = true;
             }
-            if (DEBUG_TRANSITION) Slog.v(TAG,
+            if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
                     "Prepare open transition: starting " + r);
-            if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
+            if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
                 mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, keepCurTransition);
                 mNoAnimActivities.add(r);
             } else {
@@ -2280,13 +2281,13 @@
                     // same task affinity as the one we are moving,
                     // then merge it into the same task.
                     targetTask = bottom.task;
-                    if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
+                    if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity " + target
                             + " out to bottom task " + bottom.task);
                 } else {
                     targetTask = createTaskRecord(mStackSupervisor.getNextTaskId(), target.info,
                             null, null, null, false);
                     targetTask.affinityIntent = target.intent;
-                    if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
+                    if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity " + target
                             + " out to new task " + target.task);
                 }
 
@@ -2311,8 +2312,8 @@
                     if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Removing activity " + p + " from task="
                             + task + " adding to task=" + targetTask
                             + " Callers=" + Debug.getCallers(4));
-                    if (DEBUG_TASKS) Slog.v(TAG, "Pushing next activity " + p
-                            + " out to target's task " + target.task);
+                    if (DEBUG_TASKS) Slog.v(TAG_TASKS,
+                            "Pushing next activity " + p + " out to target's task " + target.task);
                     p.setTask(targetTask, null);
                     targetTask.addActivityAtBottom(p);
 
@@ -2354,7 +2355,7 @@
                             noOptions = false;
                         }
                     }
-                    if (DEBUG_TASKS) Slog.w(TAG,
+                    if (DEBUG_TASKS) Slog.w(TAG_TASKS,
                             "resetTaskIntendedTask: calling finishActivity on " + p);
                     if (finishActivityLocked(
                             p, Activity.RESULT_CANCELED, null, "reset-task", false)) {
@@ -2428,7 +2429,8 @@
                 // in a task that is not currently on top.)
                 if (forceReset || finishOnTaskLaunch) {
                     final int start = replyChainEnd >= 0 ? replyChainEnd : i;
-                    if (DEBUG_TASKS) Slog.v(TAG, "Finishing task at index " + start + " to " + i);
+                    if (DEBUG_TASKS) Slog.v(TAG_TASKS,
+                            "Finishing task at index " + start + " to " + i);
                     for (int srcPos = start; srcPos >= i; --srcPos) {
                         final ActivityRecord p = activities.get(srcPos);
                         if (p.finishing) {
@@ -2444,8 +2446,9 @@
                     }
 
                     final int start = replyChainEnd >= 0 ? replyChainEnd : i;
-                    if (DEBUG_TASKS) Slog.v(TAG, "Reparenting from task=" + affinityTask + ":"
-                            + start + "-" + i + " to task=" + task + ":" + taskInsertionPoint);
+                    if (DEBUG_TASKS) Slog.v(TAG_TASKS,
+                            "Reparenting from task=" + affinityTask + ":" + start + "-" + i
+                            + " to task=" + task + ":" + taskInsertionPoint);
                     for (int srcPos = start; srcPos >= i; --srcPos) {
                         final ActivityRecord p = activities.get(srcPos);
                         p.setTask(task, null);
@@ -2454,8 +2457,8 @@
                         if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Removing and adding activity " + p
                                 + " to stack at " + task,
                                 new RuntimeException("here").fillInStackTrace());
-                        if (DEBUG_TASKS) Slog.v(TAG, "Pulling activity " + p + " from " + srcPos
-                                + " in to resetting task " + task);
+                        if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Pulling activity " + p
+                                + " from " + srcPos + " in to resetting task " + task);
                         mWindowManager.setAppTask(p.appToken, taskId);
                     }
                     mWindowManager.moveTaskToTop(taskId);
@@ -2613,7 +2616,7 @@
     }
 
     final void stopActivityLocked(ActivityRecord r) {
-        if (DEBUG_SWITCH) Slog.d(TAG, "Stopping: " + r);
+        if (DEBUG_SWITCH) Slog.d(TAG_SWITCH, "Stopping: " + r);
         if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
                 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
             if (!r.finishing) {
@@ -2638,8 +2641,8 @@
                 if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPING: " + r
                         + " (stop requested)");
                 r.state = ActivityState.STOPPING;
-                if (DEBUG_VISBILITY) Slog.v(
-                        TAG, "Stopping visible=" + r.visible + " for " + r);
+                if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+                        "Stopping visible=" + r.visible + " for " + r);
                 if (!r.visible) {
                     mWindowManager.setAppVisibility(r.appToken, false);
                 }
@@ -2776,7 +2779,7 @@
         // send the result
         ActivityRecord resultTo = r.resultTo;
         if (resultTo != null) {
-            if (DEBUG_RESULTS) Slog.v(TAG, "Adding result to " + resultTo
+            if (DEBUG_RESULTS) Slog.v(TAG_RESULTS, "Adding result to " + resultTo
                     + " who=" + r.resultWho + " req=" + r.requestCode
                     + " res=" + resultCode + " data=" + resultData);
             if (resultTo.userId != r.userId) {
@@ -2793,7 +2796,7 @@
                                      resultData);
             r.resultTo = null;
         }
-        else if (DEBUG_RESULTS) Slog.v(TAG, "No result destination from " + r);
+        else if (DEBUG_RESULTS) Slog.v(TAG_RESULTS, "No result destination from " + r);
 
         // Make sure this HistoryRecord is not holding on to other resources,
         // because clients have remote IPC references to this object so we
@@ -2841,7 +2844,7 @@
 
         if (mResumedActivity == r) {
             boolean endTask = index <= 0;
-            if (DEBUG_VISBILITY || DEBUG_TRANSITION) Slog.v(TAG,
+            if (DEBUG_VISIBILITY || DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
                     "Prepare close transition: finishing " + r);
             mWindowManager.prepareAppTransition(endTask
                     ? AppTransition.TRANSIT_TASK_CLOSE
@@ -2851,8 +2854,9 @@
             mWindowManager.setAppVisibility(r.appToken, false);
 
             if (mPausingActivity == null) {
-                if (DEBUG_PAUSE) Slog.v(TAG, "Finish needs to pause: " + r);
-                if (DEBUG_USER_LEAVING) Slog.v(TAG, "finish() => pause with userLeaving=false");
+                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish needs to pause: " + r);
+                if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
+                        "finish() => pause with userLeaving=false");
                 startPausingLocked(false, false, false, false);
             }
 
@@ -2862,10 +2866,10 @@
         } else if (r.state != ActivityState.PAUSING) {
             // If the activity is PAUSING, we will complete the finish once
             // it is done pausing; else we can just directly finish it here.
-            if (DEBUG_PAUSE) Slog.v(TAG, "Finish not pausing: " + r);
+            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish not pausing: " + r);
             return finishCurrentActivityLocked(r, FINISH_AFTER_PAUSE, oomAdj) == null;
         } else {
-            if (DEBUG_PAUSE) Slog.v(TAG, "Finish waiting for pause of: " + r);
+            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish waiting for pause of: " + r);
         }
 
         return false;
@@ -3160,7 +3164,7 @@
         }
         final TaskRecord task = r.task;
         if (task != null && task.removeActivity(r)) {
-            if (DEBUG_STACK) Slog.i(TAG,
+            if (DEBUG_STACK) Slog.i(TAG_STACK,
                     "removeActivityFromHistoryLocked: last activity removed from " + this);
             if (mStackSupervisor.isFrontStack(this) && task == topTask() &&
                     task.isOverHomeStack()) {
@@ -3213,7 +3217,7 @@
                     continue;
                 }
                 if (r.isDestroyable()) {
-                    if (DEBUG_SWITCH) Slog.v(TAG, "Destroying " + r + " in state " + r.state
+                    if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Destroying " + r + " in state " + r.state
                             + " resumed=" + mResumedActivity
                             + " pausing=" + mPausingActivity + " for reason " + reason);
                     if (destroyActivityLocked(r, true, reason)) {
@@ -3229,8 +3233,8 @@
 
     final boolean safelyDestroyActivityLocked(ActivityRecord r, String reason) {
         if (r.isDestroyable()) {
-            if (DEBUG_SWITCH) Slog.v(TAG, "Destroying " + r + " in state " + r.state
-                    + " resumed=" + mResumedActivity
+            if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
+                    "Destroying " + r + " in state " + r.state + " resumed=" + mResumedActivity
                     + " pausing=" + mPausingActivity + " for reason " + reason);
             return destroyActivityLocked(r, true, reason);
         }
@@ -3288,9 +3292,9 @@
      * but then create a new client-side object for this same HistoryRecord.
      */
     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)"));
+        if (DEBUG_SWITCH || DEBUG_CLEANUP) Slog.v(TAG_SWITCH,
+                "Removing activity from " + reason + ": token=" + r
+                + ", app=" + (r.app != null ? r.app.processName : "(null)"));
         EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY,
                 r.userId, System.identityHashCode(r),
                 r.task.taskId, r.shortComponentName, reason);
@@ -3322,7 +3326,7 @@
             boolean skipDestroy = false;
 
             try {
-                if (DEBUG_SWITCH) Slog.i(TAG, "Destroying: " + r);
+                if (DEBUG_SWITCH) Slog.i(TAG_SWITCH, "Destroying: " + r);
                 r.app.thread.scheduleDestroyActivity(r.appToken, r.finishing,
                         r.configChangeFlags);
             } catch (Exception e) {
@@ -3584,8 +3588,8 @@
         for (int taskNdx = top; taskNdx >= 0; --taskNdx) {
             final TaskRecord task = mTaskHistory.get(taskNdx);
             if (task.taskType == homeStackTaskType) {
-                if (DEBUG_TASKS || DEBUG_STACK)
-                    Slog.d(TAG, "moveHomeStackTaskToTop: moving " + task);
+                if (DEBUG_TASKS || DEBUG_STACK) Slog.d(TAG_STACK,
+                        "moveHomeStackTaskToTop: moving " + task);
                 mTaskHistory.remove(taskNdx);
                 mTaskHistory.add(top, task);
                 updateTaskMovement(task, true);
@@ -3596,7 +3600,7 @@
 
     final void moveTaskToFrontLocked(TaskRecord tr, boolean noAnimation, Bundle options,
             String reason) {
-        if (DEBUG_SWITCH) Slog.v(TAG, "moveTaskToFront: " + tr);
+        if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr);
 
         final int numTasks = mTaskHistory.size();
         final int index = mTaskHistory.indexOf(tr);
@@ -3618,7 +3622,7 @@
         ActivityRecord r = topRunningActivityLocked(null);
         mService.setFocusedActivityLocked(r, reason);
 
-        if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare to front transition: task=" + tr);
+        if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to front transition: task=" + tr);
         if (noAnimation) {
             mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false);
             if (r != null) {
@@ -3682,7 +3686,7 @@
             }
         }
 
-        if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare to back transition: task=" + taskId);
+        if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to back transition: task=" + taskId);
 
         boolean prevIsHome = false;
         if (tr.isOverHomeStack()) {
@@ -3912,8 +3916,8 @@
             results = r.results;
             newIntents = r.newIntents;
         }
-        if (DEBUG_SWITCH) Slog.v(TAG, "Relaunching: " + r
-                + " with results=" + results + " newIntents=" + newIntents
+        if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
+                "Relaunching: " + r + " with results=" + results + " newIntents=" + newIntents
                 + " andResume=" + andResume);
         EventLog.writeEvent(andResume ? EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY
                 : EventLogTags.AM_RELAUNCH_ACTIVITY, r.userId, System.identityHashCode(r),
@@ -3924,8 +3928,8 @@
         mStackSupervisor.removeChildActivityContainers(r);
 
         try {
-            if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG, "Moving to " +
-                    (andResume ? "RESUMED" : "PAUSED") + " Relaunching " + r);
+            if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH,
+                    "Moving to " + (andResume ? "RESUMED" : "PAUSED") + " Relaunching " + r);
             r.forceNewConfig = false;
             r.app.thread.scheduleRelaunchActivity(r.appToken, results, newIntents, changes,
                     !andResume, new Configuration(mService.mConfiguration),
@@ -3934,7 +3938,7 @@
             // the caller will only pass in 'andResume' if this activity is
             // currently resumed, which implies we aren't sleeping.
         } catch (RemoteException e) {
-            if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG, "Relaunch failed", e);
+            if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH, "Relaunch failed", e);
         }
 
         if (andResume) {
@@ -4087,8 +4091,7 @@
 
     public void unhandledBackLocked() {
         final int top = mTaskHistory.size() - 1;
-        if (DEBUG_SWITCH) Slog.d(
-            TAG, "Performing unhandledBack(): top activity at " + top);
+        if (DEBUG_SWITCH) Slog.d(TAG_SWITCH, "Performing unhandledBack(): top activity at " + top);
         if (top >= 0) {
             final ArrayList<ActivityRecord> activities = mTaskHistory.get(top).mActivities;
             int activityTop = activities.size() - 1;
@@ -4106,7 +4109,7 @@
      */
     boolean handleAppDiedLocked(ProcessRecord app) {
         if (mPausingActivity != null && mPausingActivity.app == app) {
-            if (DEBUG_PAUSE || DEBUG_CLEANUP) Slog.v(TAG,
+            if (DEBUG_PAUSE || DEBUG_CLEANUP) Slog.v(TAG_PAUSE,
                     "App died while pausing: " + mPausingActivity);
             mPausingActivity = null;
         }
@@ -4246,7 +4249,7 @@
         }
 
         if (mTaskHistory.isEmpty()) {
-            if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing stack=" + this);
+            if (DEBUG_STACK) Slog.i(TAG_STACK, "removeTask: removing stack=" + this);
             final boolean notHomeStack = !isHomeStack();
             if (isOnHomeDisplay()) {
                 String myReason = reason + " leftTaskHistoryEmpty";
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index f874244..669dff8 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -23,17 +23,11 @@
 import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static com.android.server.am.ActivityManagerDebugConfig.*;
-import static com.android.server.am.ActivityManagerService.DEBUG_PAUSE;
-import static com.android.server.am.ActivityManagerService.DEBUG_RECENTS;
-import static com.android.server.am.ActivityManagerService.DEBUG_RESULTS;
-import static com.android.server.am.ActivityManagerService.DEBUG_STACK;
-import static com.android.server.am.ActivityManagerService.DEBUG_SWITCH;
-import static com.android.server.am.ActivityManagerService.DEBUG_TASKS;
-import static com.android.server.am.ActivityManagerService.DEBUG_USER_LEAVING;
 import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_MSG;
 import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
+import static com.android.server.am.ActivityStack.ActivityState.*;
 
 import android.app.Activity;
 import android.app.ActivityManager;
@@ -120,6 +114,13 @@
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStackSupervisor" : TAG_AM;
     private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
     private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
+    private static final String TAG_PAUSE = TAG + POSTFIX_PAUSE;
+    private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS;
+    private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
+    private static final String TAG_STACK = TAG + POSTFIX_STACK;
+    private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
+    private static final String TAG_TASKS = TAG + POSTFIX_TASKS;
+    private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING;
 
     static final boolean DEBUG = DEBUG_ALL || false;
     static final boolean DEBUG_ADD_REMOVE = DEBUG || false;
@@ -381,7 +382,7 @@
     }
 
     void notifyActivityDrawnForKeyguard() {
-        if (ActivityManagerService.DEBUG_LOCKSCREEN) mService.logLockScreen("");
+        if (DEBUG_LOCKSCREEN) mService.logLockScreen("");
         mWindowManager.notifyActivityDrawnForKeyguard();
     }
 
@@ -422,7 +423,7 @@
         // The home stack should either be at the top or bottom of the stack list.
         if ((toFront && (stacks.get(topNdx) != mHomeStack))
                 || (!toFront && (stacks.get(0) != mHomeStack))) {
-            if (DEBUG_STACK) Slog.d(TAG, "moveHomeTask: topStack old="
+            if (DEBUG_STACK) Slog.d(TAG_STACK, "moveHomeTask: topStack old="
                     + ((lastFocusedStack != null) ? lastFocusedStack : stacks.get(topNdx))
                     + " new=" + mFocusedStack);
             stacks.remove(mHomeStack);
@@ -510,10 +511,10 @@
         }
 
         // Don't give up! Look in recents.
-        if (DEBUG_RECENTS) Slog.v(TAG, "Looking for task id=" + id + " in recents");
+        if (DEBUG_RECENTS) Slog.v(TAG_RECENTS, "Looking for task id=" + id + " in recents");
         TaskRecord task = mRecentTasks.taskForIdLocked(id);
         if (task == null) {
-            if (DEBUG_RECENTS) Slog.d(TAG, "\tDidn't find task id=" + id + " in recents");
+            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "\tDidn't find task id=" + id + " in recents");
             return null;
         }
 
@@ -522,10 +523,11 @@
         }
 
         if (!restoreRecentTaskLocked(task)) {
-            if (DEBUG_RECENTS) Slog.w(TAG, "Couldn't restore task id=" + id + " found in recents");
+            if (DEBUG_RECENTS) Slog.w(TAG_RECENTS,
+                    "Couldn't restore task id=" + id + " found in recents");
             return null;
         }
-        if (DEBUG_RECENTS) Slog.w(TAG, "Restored task id=" + id + " from in recents");
+        if (DEBUG_RECENTS) Slog.w(TAG_RECENTS, "Restored task id=" + id + " from in recents");
         return task;
     }
 
@@ -633,14 +635,14 @@
                 final ActivityStack stack = stacks.get(stackNdx);
                 if (isFrontStack(stack)) {
                     final ActivityRecord r = stack.mResumedActivity;
-                    if (r != null && r.state != ActivityState.RESUMED) {
+                    if (r != null && r.state != RESUMED) {
                         return false;
                     }
                 }
             }
         }
         // TODO: Not sure if this should check if all Paused are complete too.
-        if (DEBUG_STACK) Slog.d(TAG,
+        if (DEBUG_STACK) Slog.d(TAG_STACK,
                 "allResumedActivitiesComplete: mLastFocusedStack changing from=" +
                 mLastFocusedStack + " to=" + mFocusedStack);
         mLastFocusedStack = mFocusedStack;
@@ -648,17 +650,21 @@
     }
 
     boolean allResumedActivitiesVisible() {
+        boolean foundResumed = false;
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
             for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = stacks.get(stackNdx);
                 final ActivityRecord r = stack.mResumedActivity;
-                if (r != null && (!r.nowVisible || mWaitingVisibleActivities.contains(r))) {
-                    return false;
+                if (r != null) {
+                    if (!r.nowVisible || mWaitingVisibleActivities.contains(r)) {
+                        return false;
+                    }
+                    foundResumed = true;
                 }
             }
         }
-        return true;
+        return foundResumed;
     }
 
     /**
@@ -690,9 +696,7 @@
             for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = stacks.get(stackNdx);
                 final ActivityRecord r = stack.mPausingActivity;
-                if (r != null && r.state != ActivityState.PAUSED
-                        && r.state != ActivityState.STOPPED
-                        && r.state != ActivityState.STOPPING) {
+                if (r != null && r.state != PAUSED && r.state != STOPPED && r.state != STOPPING) {
                     if (DEBUG_STATES) {
                         Slog.d(TAG, "allPausedActivitiesComplete: r=" + r + " state=" + r.state);
                         pausing = false;
@@ -897,7 +901,7 @@
         ActivityContainer container = (ActivityContainer)iContainer;
         synchronized (mService) {
             if (container != null && container.mParentActivity != null &&
-                    container.mParentActivity.state != ActivityState.RESUMED) {
+                    container.mParentActivity.state != RESUMED) {
                 // Cannot start a child activity if the parent is not resumed.
                 return ActivityManager.START_CANCELED;
             }
@@ -1027,7 +1031,7 @@
                     } while (!outResult.timeout && outResult.who == null);
                 } else if (res == ActivityManager.START_TASK_TO_FRONT) {
                     ActivityRecord r = stack.topRunningActivityLocked(null);
-                    if (r.nowVisible && r.state == ActivityState.RESUMED) {
+                    if (r.nowVisible && r.state == RESUMED) {
                         outResult.timeout = false;
                         outResult.who = new ComponentName(r.info.packageName, r.info.name);
                         outResult.totalTime = 0;
@@ -1178,10 +1182,9 @@
                 results = r.results;
                 newIntents = r.newIntents;
             }
-            if (DEBUG_SWITCH) Slog.v(TAG, "Launching: " + r
-                    + " icicle=" + r.icicle
-                    + " with results=" + results + " newIntents=" + newIntents
-                    + " andResume=" + andResume);
+            if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
+                    "Launching: " + r + " icicle=" + r.icicle + " with results=" + results
+                    + " newIntents=" + newIntents + " andResume=" + andResume);
             if (andResume) {
                 EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY,
                         r.userId, System.identityHashCode(r),
@@ -1290,7 +1293,7 @@
             // other state.
             if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPED: " + r
                     + " (starting in stopped state)");
-            r.state = ActivityState.STOPPED;
+            r.state = STOPPED;
             r.stopped = true;
         }
 
@@ -1381,8 +1384,8 @@
         ActivityRecord resultRecord = null;
         if (resultTo != null) {
             sourceRecord = isInAnyStackLocked(resultTo);
-            if (DEBUG_RESULTS) Slog.v(
-                TAG, "Will send result to " + resultTo + " " + sourceRecord);
+            if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
+                    "Will send result to " + resultTo + " " + sourceRecord);
             if (sourceRecord != null) {
                 if (requestCode >= 0 && !sourceRecord.finishing) {
                     resultRecord = sourceRecord;
@@ -1726,7 +1729,8 @@
         // We'll invoke onUserLeaving before onPause only if the launching
         // activity did not explicitly state that this is an automated launch.
         mUserLeaving = (launchFlags & Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
-        if (DEBUG_USER_LEAVING) Slog.v(TAG, "startActivity() => mUserLeaving=" + mUserLeaving);
+        if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
+                "startActivity() => mUserLeaving=" + mUserLeaving);
 
         // If the caller has asked not to resume at this point, we make note
         // of this in the record so that we can skip it when trying to find
@@ -1933,7 +1937,7 @@
                         }
                     }
                     if (!movedToFront) {
-                        if (DEBUG_TASKS) Slog.d(TAG, "Bring to front target: " + targetStack
+                        if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Bring to front target: " + targetStack
                                 + " from " + intentActivity);
                         targetStack.moveToFront("intentActivityFound");
                     }
@@ -2139,8 +2143,8 @@
                         newTaskIntent != null ? newTaskIntent : intent,
                         voiceSession, voiceInteractor, !launchTaskBehind /* toTop */),
                         taskToAffiliate);
-                if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in new task " +
-                        r.task);
+                if (DEBUG_TASKS) Slog.v(TAG_TASKS,
+                        "Starting new activity " + r + " in new task " + r.task);
             } else {
                 r.setTask(reuseTask, taskToAffiliate);
             }
@@ -2207,7 +2211,7 @@
             // to keep the new one in the same task as the one that is starting
             // it.
             r.setTask(sourceTask, null);
-            if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+            if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + r
                     + " in existing task " + r.task + " from source " + sourceRecord);
 
         } else if (inTask != null) {
@@ -2246,7 +2250,7 @@
             }
 
             r.setTask(inTask, null);
-            if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+            if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + r
                     + " in explicit task " + r.task);
 
         } else {
@@ -2259,7 +2263,7 @@
             r.setTask(prev != null ? prev.task : targetStack.createTaskRecord(getNextTaskId(),
                             r.info, intent, null, null, true), null);
             mWindowManager.moveTaskToTop(r.task.taskId);
-            if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+            if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + r
                     + " in new guessed " + r.task);
         }
 
@@ -2599,8 +2603,8 @@
             return;
         }
         task.stack.moveTaskToFrontLocked(task, false /* noAnimation */, options, reason);
-        if (DEBUG_STACK) Slog.d(TAG, "findTaskToMoveToFront: moved to front of stack="
-                + task.stack);
+        if (DEBUG_STACK) Slog.d(TAG_STACK,
+                "findTaskToMoveToFront: moved to front of stack=" + task.stack);
     }
 
     ActivityStack getStack(int stackId) {
@@ -2793,20 +2797,20 @@
             stack = createStackOnDisplay(getNextStackId(), Display.DEFAULT_DISPLAY);
             // Restore home stack to top.
             moveHomeStack(true, "restoreRecentTask");
-            if (DEBUG_RECENTS)
-                Slog.v(TAG, "Created stack=" + stack + " for recents restoration.");
+            if (DEBUG_RECENTS) Slog.v(TAG_RECENTS,
+                    "Created stack=" + stack + " for recents restoration.");
         }
 
         if (stack == null) {
             // What does this mean??? Not sure how we would get here...
-            if (DEBUG_RECENTS)
-                Slog.v(TAG, "Unable to find/create stack to restore recent task=" + task);
+            if (DEBUG_RECENTS) Slog.v(TAG_RECENTS,
+                    "Unable to find/create stack to restore recent task=" + task);
             return false;
         }
 
         stack.addTask(task, false, false);
-        if (DEBUG_RECENTS)
-            Slog.v(TAG, "Added restored task=" + task + " to stack=" + stack);
+        if (DEBUG_RECENTS) Slog.v(TAG_RECENTS,
+                "Added restored task=" + task + " to stack=" + stack);
         final ArrayList<ActivityRecord> activities = task.mActivities;
         for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
             final ActivityRecord r = activities.get(activityNdx);
@@ -2839,18 +2843,18 @@
     }
 
     ActivityRecord findTaskLocked(ActivityRecord r) {
-        if (DEBUG_TASKS) Slog.d(TAG, "Looking for task of " + r);
+        if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + r);
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
             for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = stacks.get(stackNdx);
                 if (!r.isApplicationActivity() && !stack.isHomeStack()) {
-                    if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: (home activity) " + stack);
+                    if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping stack: (home activity) " + stack);
                     continue;
                 }
                 if (!stack.mActivityContainer.isEligibleForNewTasks()) {
-                    if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: (new task not allowed) " +
-                            stack);
+                    if (DEBUG_TASKS) Slog.d(TAG_TASKS,
+                            "Skipping stack: (new task not allowed) " + stack);
                     continue;
                 }
                 final ActivityRecord ar = stack.findTaskLocked(r);
@@ -2859,7 +2863,7 @@
                 }
             }
         }
-        if (DEBUG_TASKS) Slog.d(TAG, "No task found");
+        if (DEBUG_TASKS) Slog.d(TAG_TASKS, "No task found");
         return null;
     }
 
@@ -2968,7 +2972,7 @@
 
             if (mStoppingActivities.size() > 0) {
                 // Still need to tell some activities to stop; can't sleep yet.
-                if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still need to stop "
+                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still need to stop "
                         + mStoppingActivities.size() + " activities");
                 scheduleIdleLocked();
                 dontSleep = true;
@@ -2976,7 +2980,7 @@
 
             if (mGoingToSleepActivities.size() > 0) {
                 // Still need to tell some activities to sleep; can't sleep yet.
-                if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still need to sleep "
+                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still need to sleep "
                         + mGoingToSleepActivities.size() + " activities");
                 dontSleep = true;
             }
@@ -3127,16 +3131,14 @@
             // First, if we find an activity that is in the process of being destroyed,
             // then we just aren't going to do anything for now; we want things to settle
             // down before we try to prune more activities.
-            if (r.finishing || r.state == ActivityState.DESTROYING
-                    || r.state == ActivityState.DESTROYED) {
+            if (r.finishing || r.state == DESTROYING || r.state == DESTROYED) {
                 if (DEBUG_RELEASE) Slog.d(TAG, "Abort release; already destroying: " + r);
                 return;
             }
             // Don't consider any activies that are currently not in a state where they
             // can be destroyed.
-            if (r.visible || !r.stopped || !r.haveState
-                    || r.state == ActivityState.RESUMED || r.state == ActivityState.PAUSING
-                    || r.state == ActivityState.PAUSED || r.state == ActivityState.STOPPING) {
+            if (r.visible || !r.stopped || !r.haveState || r.state == RESUMED || r.state == PAUSING
+                    || r.state == PAUSED || r.state == STOPPING) {
                 if (DEBUG_RELEASE) Slog.d(TAG, "Not releasing in-use activity: " + r);
                 continue;
             }
@@ -3254,39 +3256,34 @@
     }
 
     void validateTopActivitiesLocked() {
-        // FIXME
-/*        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = stacks.get(stackNdx);
-            final ActivityRecord r = stack.topRunningActivityLocked(null);
-            final ActivityState state = r == null ? ActivityState.DESTROYED : r.state;
-            if (isFrontStack(stack)) {
-                if (r == null) {
-                    Slog.e(TAG, "validateTop...: null top activity, stack=" + stack);
+        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                final ActivityRecord r = stack.topRunningActivityLocked(null);
+                final ActivityState state = r == null ? DESTROYED : r.state;
+                if (isFrontStack(stack)) {
+                    if (r == null) Slog.e(TAG,
+                            "validateTop...: null top activity, stack=" + stack);
+                    else {
+                        final ActivityRecord pausing = stack.mPausingActivity;
+                        if (pausing != null && pausing == r) Slog.e(TAG,
+                                "validateTop...: top stack has pausing activity r=" + r
+                                + " state=" + state);
+                        if (state != INITIALIZING && state != RESUMED) Slog.e(TAG,
+                                "validateTop...: activity in front not resumed r=" + r
+                                + " state=" + state);
+                    }
                 } else {
-                    final ActivityRecord pausing = stack.mPausingActivity;
-                    if (pausing != null && pausing == r) {
-                        Slog.e(TAG, "validateTop...: top stack has pausing activity r=" + r +
-                            " state=" + state);
-                    }
-                    if (state != ActivityState.INITIALIZING && state != ActivityState.RESUMED) {
-                        Slog.e(TAG, "validateTop...: activity in front not resumed r=" + r +
-                                " state=" + state);
-                    }
-                }
-            } else {
-                final ActivityRecord resumed = stack.mResumedActivity;
-                if (resumed != null && resumed == r) {
-                    Slog.e(TAG, "validateTop...: back stack has resumed activity r=" + r +
-                        " state=" + state);
-                }
-                if (r != null && (state == ActivityState.INITIALIZING
-                        || state == ActivityState.RESUMED)) {
-                    Slog.e(TAG, "validateTop...: activity in back resumed r=" + r +
-                            " state=" + state);
+                    final ActivityRecord resumed = stack.mResumedActivity;
+                    if (resumed != null && resumed == r) Slog.e(TAG,
+                            "validateTop...: back stack has resumed activity r=" + r
+                            + " state=" + state);
+                    if (r != null && (state == INITIALIZING || state == RESUMED)) Slog.e(TAG,
+                            "validateTop...: activity in back resumed r=" + r + " state=" + state);
                 }
             }
         }
-*/
     }
 
     public void dump(PrintWriter pw, String prefix) {
@@ -3512,7 +3509,7 @@
         mHandler.sendMessage(mHandler.obtainMessage(HANDLE_DISPLAY_CHANGED, displayId, 0));
     }
 
-    public void handleDisplayAddedLocked(int displayId) {
+    private void handleDisplayAdded(int displayId) {
         boolean newDisplay;
         synchronized (mService) {
             newDisplay = mActivityDisplays.get(displayId) == null;
@@ -3530,7 +3527,7 @@
         }
     }
 
-    public void handleDisplayRemovedLocked(int displayId) {
+    private void handleDisplayRemoved(int displayId) {
         synchronized (mService) {
             ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
             if (activityDisplay != null) {
@@ -3544,7 +3541,7 @@
         mWindowManager.onDisplayRemoved(displayId);
     }
 
-    public void handleDisplayChangedLocked(int displayId) {
+    private void handleDisplayChanged(int displayId) {
         synchronized (mService) {
             ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
             if (activityDisplay != null) {
@@ -3554,7 +3551,7 @@
         mWindowManager.onDisplayChanged(displayId);
     }
 
-    StackInfo getStackInfo(ActivityStack stack) {
+    private StackInfo getStackInfoLocked(ActivityStack stack) {
         StackInfo info = new StackInfo();
         mWindowManager.getStackBounds(stack.mStackId, info.bounds);
         info.displayId = Display.DEFAULT_DISPLAY;
@@ -3580,7 +3577,7 @@
     StackInfo getStackInfoLocked(int stackId) {
         ActivityStack stack = getStack(stackId);
         if (stack != null) {
-            return getStackInfo(stack);
+            return getStackInfoLocked(stack);
         }
         return null;
     }
@@ -3590,7 +3587,7 @@
         for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) {
             ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
             for (int ndx = stacks.size() - 1; ndx >= 0; --ndx) {
-                list.add(getStackInfo(stacks.get(ndx)));
+                list.add(getStackInfoLocked(stacks.get(ndx)));
             }
         }
         return list;
@@ -3710,13 +3707,13 @@
                     }
                 } break;
                 case HANDLE_DISPLAY_ADDED: {
-                    handleDisplayAddedLocked(msg.arg1);
+                    handleDisplayAdded(msg.arg1);
                 } break;
                 case HANDLE_DISPLAY_CHANGED: {
-                    handleDisplayChangedLocked(msg.arg1);
+                    handleDisplayChanged(msg.arg1);
                 } break;
                 case HANDLE_DISPLAY_REMOVED: {
-                    handleDisplayRemovedLocked(msg.arg1);
+                    handleDisplayRemoved(msg.arg1);
                 } break;
                 case CONTAINER_CALLBACK_VISIBILITY: {
                     final ActivityContainer container = (ActivityContainer) msg.obj;
@@ -3851,12 +3848,12 @@
                 mStackId = stackId;
                 mStack = new ActivityStack(this, mRecentTasks);
                 mIdString = "ActivtyContainer{" + mStackId + "}";
-                if (DEBUG_STACK) Slog.d(TAG, "Creating " + this);
+                if (DEBUG_STACK) Slog.d(TAG_STACK, "Creating " + this);
             }
         }
 
         void attachToDisplayLocked(ActivityDisplay activityDisplay) {
-            if (DEBUG_STACK) Slog.d(TAG, "attachToDisplayLocked: " + this
+            if (DEBUG_STACK) Slog.d(TAG_STACK, "attachToDisplayLocked: " + this
                     + " to display=" + activityDisplay);
             mActivityDisplay = activityDisplay;
             mStack.mDisplayId = activityDisplay.mDisplayId;
@@ -3934,7 +3931,7 @@
         }
 
         protected void detachLocked() {
-            if (DEBUG_STACK) Slog.d(TAG, "detachLocked: " + this + " from display="
+            if (DEBUG_STACK) Slog.d(TAG_STACK, "detachLocked: " + this + " from display="
                     + mActivityDisplay + " Callers=" + Debug.getCallers(2));
             if (mActivityDisplay != null) {
                 mActivityDisplay.detachActivitiesLocked(mStack);
@@ -4111,8 +4108,8 @@
 
             setSurfaceIfReadyLocked();
 
-            if (DEBUG_STACK) Slog.d(TAG, "setSurface: " + this + " to display="
-                    + virtualActivityDisplay);
+            if (DEBUG_STACK) Slog.d(TAG_STACK,
+                    "setSurface: " + this + " to display=" + virtualActivityDisplay);
         }
 
         @Override
@@ -4135,7 +4132,7 @@
         }
 
         private void setSurfaceIfReadyLocked() {
-            if (DEBUG_STACK) Slog.v(TAG, "setSurfaceIfReadyLocked: mDrawn=" + mDrawn +
+            if (DEBUG_STACK) Slog.v(TAG_STACK, "setSurfaceIfReadyLocked: mDrawn=" + mDrawn +
                     " mContainerState=" + mContainerState + " mSurface=" + mSurface);
             if (mDrawn && mSurface != null && mContainerState == CONTAINER_STATE_NO_SURFACE) {
                 ((VirtualActivityDisplay) mActivityDisplay).setSurface(mSurface);
@@ -4178,13 +4175,13 @@
         }
 
         void attachActivities(ActivityStack stack) {
-            if (DEBUG_STACK) Slog.v(TAG, "attachActivities: attaching " + stack + " to displayId="
-                    + mDisplayId);
+            if (DEBUG_STACK) Slog.v(TAG_STACK,
+                    "attachActivities: attaching " + stack + " to displayId=" + mDisplayId);
             mStacks.add(stack);
         }
 
         void detachActivitiesLocked(ActivityStack stack) {
-            if (DEBUG_STACK) Slog.v(TAG, "detachActivitiesLocked: detaching " + stack
+            if (DEBUG_STACK) Slog.v(TAG_STACK, "detachActivitiesLocked: detaching " + stack
                     + " from displayId=" + mDisplayId);
             mStacks.remove(stack);
         }
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index 04912d0..3a20ded 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -16,10 +16,7 @@
 
 package com.android.server.am;
 
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.am.ActivityManagerService.DEBUG_RECENTS;
-import static com.android.server.am.ActivityManagerService.DEBUG_TASKS;
+import static com.android.server.am.ActivityManagerDebugConfig.*;
 import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
 
 import android.app.ActivityManager;
@@ -44,6 +41,8 @@
  */
 class RecentTasks extends ArrayList<TaskRecord> {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "RecentTasks" : TAG_AM;
+    private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
+    private static final String TAG_TASKS = TAG + POSTFIX_TASKS;
 
     // Maximum number recent bitmaps to keep in memory.
     private static final int MAX_RECENT_BITMAPS = 3;
@@ -83,8 +82,8 @@
         for (int i = size() - 1; i >= 0; --i) {
             TaskRecord tr = get(i);
             if (tr.userId == userId) {
-                if(DEBUG_TASKS) Slog.i(TAG, "remove RecentTask " + tr
-                        + " when finishing user" + userId);
+                if(DEBUG_TASKS) Slog.i(TAG_TASKS,
+                        "remove RecentTask " + tr + " when finishing user" + userId);
                 remove(i);
                 tr.removedFromRecents();
             }
@@ -170,21 +169,21 @@
                             continue;
                         } else {
                             // Otherwise just not available for now.
-                            if (DEBUG_RECENTS && task.isAvailable) Slog.d(TAG,
+                            if (DEBUG_RECENTS && task.isAvailable) Slog.d(TAG_RECENTS,
                                     "Making recent unavailable: " + task);
                             task.isAvailable = false;
                         }
                     } else {
                         if (!ai.enabled || !ai.applicationInfo.enabled
                                 || (ai.applicationInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
-                            if (DEBUG_RECENTS && task.isAvailable) Slog.d(TAG,
+                            if (DEBUG_RECENTS && task.isAvailable) Slog.d(TAG_RECENTS,
                                     "Making recent unavailable: " + task
                                     + " (enabled=" + ai.enabled + "/" + ai.applicationInfo.enabled
                                     + " flags=" + Integer.toHexString(ai.applicationInfo.flags)
                                     + ")");
                             task.isAvailable = false;
                         } else {
-                            if (DEBUG_RECENTS && !task.isAvailable) Slog.d(TAG,
+                            if (DEBUG_RECENTS && !task.isAvailable) Slog.d(TAG_RECENTS,
                                     "Making recent available: " + task);
                             task.isAvailable = true;
                         }
@@ -210,7 +209,7 @@
             top = top.mNextAffiliate;
             topIndex--;
         }
-        if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: adding affilliates starting at "
+        if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: adding affilliates starting at "
                 + topIndex + " from intial " + taskIndex);
         // Find the end of the chain, doing a sanity check along the way.
         boolean sane = top.mAffiliatedTaskId == task.mAffiliatedTaskId;
@@ -218,7 +217,7 @@
         TaskRecord prev = top;
         while (endIndex < recentsCount) {
             TaskRecord cur = get(endIndex);
-            if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: looking at next chain @"
+            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: looking at next chain @"
                     + endIndex + " " + cur);
             if (cur == top) {
                 // Verify start of the chain.
@@ -249,7 +248,7 @@
                             + cur.mPrevAffiliate);
                     sane = false;
                 }
-                if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: end of chain @" + endIndex);
+                if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: end of chain @" + endIndex);
                 break;
             } else {
                 // Verify middle of the chain's prev points to a valid item.
@@ -290,12 +289,12 @@
             // All looks good, we can just move all of the affiliated tasks
             // to the top.
             for (int i=topIndex; i<=endIndex; i++) {
-                if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: moving affiliated " + task
+                if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: moving affiliated " + task
                         + " from " + i + " to " + (i-topIndex));
                 TaskRecord cur = remove(i);
                 add(i - topIndex, cur);
             }
-            if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: done moving tasks  " +  topIndex
+            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: done moving tasks  " +  topIndex
                     + " to " + endIndex);
             return true;
         }
@@ -312,19 +311,20 @@
         int recentsCount = size();
         // Quick case: never add voice sessions.
         if (task.voiceSession != null) {
-            if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: not adding voice interaction " + task);
+            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
+                    "addRecent: not adding voice interaction " + task);
             return;
         }
         // Another quick case: check if the top-most recent task is the same.
         if (!isAffiliated && recentsCount > 0 && get(0) == task) {
-            if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: already at top: " + task);
+            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: already at top: " + task);
             return;
         }
         // Another quick case: check if this is part of a set of affiliated
         // tasks that are at the top.
         if (isAffiliated && recentsCount > 0 && task.inRecents
                 && task.mAffiliatedTaskId == get(0).mAffiliatedTaskId) {
-            if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: affiliated " + get(0)
+            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: affiliated " + get(0)
                     + " at top when adding " + task);
             return;
         }
@@ -341,7 +341,7 @@
                     remove(taskIndex);
                     add(0, task);
                     mService.notifyTaskPersisterLocked(task, false);
-                    if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: moving to top " + task
+                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: moving to top " + task
                             + " from " + taskIndex);
                     return;
                 } else {
@@ -361,7 +361,7 @@
             }
         }
 
-        if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: trimming tasks for " + task);
+        if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: trimming tasks for " + task);
         trimForTaskLocked(task, true);
 
         recentsCount = size();
@@ -376,7 +376,7 @@
             // If this is a simple non-affiliated task, or we had some failure trying to
             // handle it as part of an affilated task, then just place it at the top.
             add(0, task);
-            if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: adding " + task);
+            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: adding " + task);
         } else if (isAffiliated) {
             // If this is a new affiliated task, then move all of the affiliated tasks
             // to the front and insert this new one.
@@ -398,8 +398,8 @@
                         // after us in the list, so add at their position.
                         taskIndex = otherIndex;
                     }
-                    if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: new affiliated task added at "
-                            + taskIndex + ": " + task);
+                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
+                            "addRecent: new affiliated task added at " + taskIndex + ": " + task);
                     add(taskIndex, task);
 
                     // Now move everything to the front.
@@ -412,19 +412,19 @@
                     // everything and then go through our general path of adding a new task.
                     needAffiliationFix = true;
                 } else {
-                    if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: couldn't find other affiliation "
-                            + other);
+                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
+                            "addRecent: couldn't find other affiliation " + other);
                     needAffiliationFix = true;
                 }
             } else {
-                if (DEBUG_RECENTS) Slog.d(TAG,
+                if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
                         "addRecent: adding affiliated task without next/prev:" + task);
                 needAffiliationFix = true;
             }
         }
 
         if (needAffiliationFix) {
-            if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: regrouping affiliations");
+            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: regrouping affiliations");
             cleanupLocked(task.userId);
         }
     }
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 3b34541..82e6d47 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -18,8 +18,7 @@
 
 import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
 import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityManagerDebugConfig.*;
 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;
@@ -58,6 +57,8 @@
 
 final class TaskRecord {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM;
+    private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
+    private static final String TAG_TASKS = TAG + POSTFIX_TASKS;
 
     static final String ATTR_TASKID = "task_id";
     private static final String TAG_INTENT = "intent";
@@ -312,8 +313,7 @@
                     _intent.setSourceBounds(null);
                 }
             }
-            if (ActivityManagerService.DEBUG_TASKS) Slog.v(TAG,
-                    "Setting Intent of " + this + " to " + _intent);
+            if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Setting Intent of " + this + " to " + _intent);
             intent = _intent;
             realActivity = _intent != null ? _intent.getComponent() : null;
             origActivity = null;
@@ -325,7 +325,7 @@
                 targetIntent.setComponent(targetComponent);
                 targetIntent.setSelector(null);
                 targetIntent.setSourceBounds(null);
-                if (ActivityManagerService.DEBUG_TASKS) Slog.v(TAG,
+                if (DEBUG_TASKS) Slog.v(TAG_TASKS,
                         "Setting Intent of " + this + " to target " + targetIntent);
                 intent = targetIntent;
                 realActivity = targetComponent;
@@ -821,7 +821,7 @@
     }
 
     void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
-        if (ActivityManagerService.DEBUG_RECENTS) Slog.i(TAG, "Saving task=" + this);
+        if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this);
 
         out.attribute(null, ATTR_TASKID, String.valueOf(taskId));
         if (realActivity != null) {
@@ -1048,7 +1048,7 @@
             activities.get(activityNdx).task = task;
         }
 
-        if (ActivityManagerService.DEBUG_RECENTS) Slog.d(TAG, "Restored task=" + task);
+        if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task);
         return task;
     }
 
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index ab56b34..fd75077 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -23,16 +23,16 @@
 import android.os.Looper;
 import android.os.MessageQueue;
 import android.os.RemoteException;
-import android.service.fingerprint.FingerprintManager;
 import android.util.ArrayMap;
 import android.util.Slog;
 
 import com.android.server.SystemService;
 
-import android.service.fingerprint.FingerprintUtils;
-import android.service.fingerprint.Fingerprint;
-import android.service.fingerprint.IFingerprintService;
-import android.service.fingerprint.IFingerprintServiceReceiver;
+import android.hardware.fingerprint.FingerprintUtils;
+import android.hardware.fingerprint.Fingerprint;
+import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.IFingerprintService;
+import android.hardware.fingerprint.IFingerprintServiceReceiver;
 
 import static android.Manifest.permission.MANAGE_FINGERPRINT;
 import static android.Manifest.permission.USE_FINGERPRINT;
@@ -363,7 +363,7 @@
             startEnroll(token, groupId, flags);
         }
 
-        @Override 
+        @Override
         // Binder call
         public void authenticate(IBinder token, long sessionId, int groupId, int flags) {
             checkPermission(USE_FINGERPRINT);
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 87cf06e..958caea 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3509,8 +3509,14 @@
     /** {@inheritDoc} */
     @Override
     public int getSystemDecorLayerLw() {
-        if (mStatusBar != null) return mStatusBar.getSurfaceLayer();
-        if (mNavigationBar != null) return mNavigationBar.getSurfaceLayer();
+        if (mStatusBar != null && mStatusBar.isVisibleLw()) {
+            return mStatusBar.getSurfaceLayer();
+        }
+
+        if (mNavigationBar != null && mNavigationBar.isVisibleLw()) {
+            return mNavigationBar.getSurfaceLayer();
+        }
+
         return 0;
     }
 
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index a58f30d..55ec9fc 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -242,7 +242,7 @@
     }
 
     // This must be called while inside a transaction.
-    boolean stepAnimationLocked(long currentTime) {
+    boolean stepAnimationLocked(long currentTime, final int displayId) {
         if (mService.okToDisplay()) {
             // We will run animations as long as the display isn't frozen.
 
@@ -292,7 +292,7 @@
         }
 
         mAnimator.setAppLayoutChanges(this, WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM,
-                "AppWindowToken");
+                "AppWindowToken", displayId);
 
         clearAnimation();
         animating = false;
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 46fa38a..897b865 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -159,13 +159,13 @@
                     final AppWindowAnimator appAnimator = tokens.get(tokenNdx).mAppAnimator;
                     final boolean wasAnimating = appAnimator.animation != null
                             && appAnimator.animation != AppWindowAnimator.sDummyAnimation;
-                    if (appAnimator.stepAnimationLocked(mCurrentTime)) {
+                    if (appAnimator.stepAnimationLocked(mCurrentTime, displayId)) {
                         mAnimating = mAppWindowAnimating = true;
                     } else if (wasAnimating) {
                         // stopped animating, do one more pass through the layout
                         setAppLayoutChanges(appAnimator,
                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
-                                "appToken " + appAnimator.mAppToken + " done");
+                                "appToken " + appAnimator.mAppToken + " done", displayId);
                         if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
                                 "updateWindowsApps...: done animating " + appAnimator.mAppToken);
                     }
@@ -178,12 +178,12 @@
                 final AppWindowAnimator appAnimator = exitingAppTokens.get(i).mAppAnimator;
                 final boolean wasAnimating = appAnimator.animation != null
                         && appAnimator.animation != AppWindowAnimator.sDummyAnimation;
-                if (appAnimator.stepAnimationLocked(mCurrentTime)) {
+                if (appAnimator.stepAnimationLocked(mCurrentTime, displayId)) {
                     mAnimating = mAppWindowAnimating = true;
                 } else if (wasAnimating) {
                     // stopped animating, do one more pass through the layout
                     setAppLayoutChanges(appAnimator, WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
-                        "exiting appToken " + appAnimator.mAppToken + " done");
+                        "exiting appToken " + appAnimator.mAppToken + " done", displayId);
                     if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
                             "updateWindowsApps...: done animating exiting " + appAnimator.mAppToken);
                 }
@@ -575,11 +575,11 @@
                             // This will set mOrientationChangeComplete and cause a pass through layout.
                             setAppLayoutChanges(appAnimator,
                                     WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
-                                    "testTokenMayBeDrawnLocked: freezingScreen");
+                                    "testTokenMayBeDrawnLocked: freezingScreen", displayId);
                         } else {
                             setAppLayoutChanges(appAnimator,
                                     WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM,
-                                    "testTokenMayBeDrawnLocked");
+                                    "testTokenMayBeDrawnLocked", displayId);
 
                             // We can now show all of the drawn windows!
                             if (!mService.mOpeningApps.contains(wtoken)) {
@@ -792,28 +792,30 @@
         if (displayId < 0) {
             return 0;
         }
-        return mService.getDisplayContentLocked(displayId).pendingLayoutChanges;
+        final DisplayContent displayContent = mService.getDisplayContentLocked(displayId);
+        return (displayContent != null) ? displayContent.pendingLayoutChanges : 0;
     }
 
     void setPendingLayoutChanges(final int displayId, final int changes) {
-        if (displayId >= 0) {
-            mService.getDisplayContentLocked(displayId).pendingLayoutChanges |= changes;
+        if (displayId < 0) {
+            return;
+        }
+        final DisplayContent displayContent = mService.getDisplayContentLocked(displayId);
+        if (displayContent != null) {
+            displayContent.pendingLayoutChanges |= changes;
         }
     }
 
-    void setAppLayoutChanges(final AppWindowAnimator appAnimator, final int changes, String s) {
-        // Used to track which displays layout changes have been done.
-        SparseIntArray displays = new SparseIntArray(2);
+    void setAppLayoutChanges(final AppWindowAnimator appAnimator, final int changes, String reason,
+            final int displayId) {
         WindowList windows = appAnimator.mAppToken.allAppWindows;
         for (int i = windows.size() - 1; i >= 0; i--) {
-            final int displayId = windows.get(i).getDisplayId();
-            if (displayId >= 0 && displays.indexOfKey(displayId) < 0) {
+            if (displayId == windows.get(i).getDisplayId()) {
                 setPendingLayoutChanges(displayId, changes);
                 if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
-                    mService.debugLayoutRepeats(s, getPendingLayoutChanges(displayId));
+                    mService.debugLayoutRepeats(reason, getPendingLayoutChanges(displayId));
                 }
-                // Keep from processing this display again.
-                displays.put(displayId, changes);
+                break;
             }
         }
     }
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 7b74e91..6448de2 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -10,6 +10,7 @@
     $(LOCAL_REL_DIR)/com_android_server_AssetAtlasService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_connectivity_Vpn.cpp \
     $(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_fingerprint_FingerprintService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiCecController.cpp \
     $(LOCAL_REL_DIR)/com_android_server_input_InputApplicationHandle.cpp \
     $(LOCAL_REL_DIR)/com_android_server_input_InputManagerService.cpp \
diff --git a/core/jni/android_server_FingerprintManager.cpp b/services/core/jni/com_android_server_fingerprint_FingerprintService.cpp
similarity index 100%
rename from core/jni/android_server_FingerprintManager.cpp
rename to services/core/jni/com_android_server_fingerprint_FingerprintService.cpp
diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java
index a232a6e..d41629d 100644
--- a/services/net/java/android/net/dhcp/DhcpPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpPacket.java
@@ -611,10 +611,22 @@
     /**
      * Reads a string of specified length from the buffer.
      */
-    private static String readAsciiString(ByteBuffer buf, int byteCount) {
+    private static String readAsciiString(ByteBuffer buf, int byteCount, boolean nullOk) {
         byte[] bytes = new byte[byteCount];
         buf.get(bytes);
-        return new String(bytes, 0, bytes.length, StandardCharsets.US_ASCII);
+        int length = bytes.length;
+        if (!nullOk) {
+            // Stop at the first null byte. This is because some DHCP options (e.g., the domain
+            // name) are passed to netd via FrameworkListener, which refuses arguments containing
+            // null bytes. We don't do this by default because vendorInfo is an opaque string which
+            // could in theory contain null bytes.
+            for (length = 0; length < bytes.length; length++) {
+                if (bytes[length] == 0) {
+                    break;
+                }
+            }
+        }
+        return new String(bytes, 0, length, StandardCharsets.US_ASCII);
     }
 
     /**
@@ -797,7 +809,7 @@
                             break;
                         case DHCP_HOST_NAME:
                             expectedLen = optionLen;
-                            hostName = readAsciiString(packet, optionLen);
+                            hostName = readAsciiString(packet, optionLen, false);
                             break;
                         case DHCP_MTU:
                             expectedLen = 2;
@@ -805,7 +817,7 @@
                             break;
                         case DHCP_DOMAIN_NAME:
                             expectedLen = optionLen;
-                            domainName = readAsciiString(packet, optionLen);
+                            domainName = readAsciiString(packet, optionLen, false);
                             break;
                         case DHCP_BROADCAST_ADDRESS:
                             bcAddr = readIpAddress(packet);
@@ -834,7 +846,7 @@
                             break;
                         case DHCP_MESSAGE:
                             expectedLen = optionLen;
-                            message = readAsciiString(packet, optionLen);
+                            message = readAsciiString(packet, optionLen, false);
                             break;
                         case DHCP_MAX_MESSAGE_SIZE:
                             expectedLen = 2;
@@ -850,7 +862,7 @@
                             break;
                         case DHCP_VENDOR_CLASS_ID:
                             expectedLen = optionLen;
-                            vendorId = readAsciiString(packet, optionLen);
+                            vendorId = readAsciiString(packet, optionLen, true);
                             break;
                         case DHCP_CLIENT_IDENTIFIER: { // Client identifier
                             byte[] id = new byte[optionLen];
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index f25fc62..33979b1 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -10,6 +10,7 @@
 LOCAL_STATIC_JAVA_LIBRARIES := \
     services.core \
     services.devicepolicy \
+    services.net \
     easymocklib \
     guava \
     mockito-target
diff --git a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
new file mode 100644
index 0000000..2658937
--- /dev/null
+++ b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.dhcp;
+
+import android.net.NetworkUtils;
+import android.system.OsConstants;
+import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
+import java.net.Inet4Address;
+import java.nio.ByteBuffer;
+
+import static android.net.dhcp.DhcpPacket.*;
+
+
+public class DhcpPacketTest extends TestCase {
+
+    private static Inet4Address SERVER_ADDR =
+            (Inet4Address) NetworkUtils.numericToInetAddress("192.0.2.1");
+    private static Inet4Address CLIENT_ADDR =
+            (Inet4Address) NetworkUtils.numericToInetAddress("192.0.2.234");
+    private static byte[] CLIENT_MAC = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
+
+    class TestDhcpPacket extends DhcpPacket {
+        private byte mType;
+        // TODO: Make this a map of option numbers to bytes instead.
+        private byte[] mDomainBytes, mVendorInfoBytes;
+
+        public TestDhcpPacket(byte type, byte[] domainBytes, byte[] vendorInfoBytes) {
+            super(0xdeadbeef, INADDR_ANY, CLIENT_ADDR, INADDR_ANY, INADDR_ANY, CLIENT_MAC, true);
+            mType = type;
+            mDomainBytes = domainBytes;
+            mVendorInfoBytes = vendorInfoBytes;
+        }
+
+        public ByteBuffer buildPacket(int encap, short unusedDestUdp, short unusedSrcUdp) {
+            ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH);
+            fillInPacket(encap, CLIENT_ADDR, SERVER_ADDR,
+                         DHCP_CLIENT, DHCP_SERVER, result, DHCP_BOOTREPLY, false);
+            return result;
+        }
+
+        public void finishPacket(ByteBuffer buffer) {
+            addTlv(buffer, DHCP_MESSAGE_TYPE, mType);
+            if (mDomainBytes != null) {
+                addTlv(buffer, DHCP_DOMAIN_NAME, mDomainBytes);
+            }
+            if (mVendorInfoBytes != null) {
+                addTlv(buffer, DHCP_VENDOR_CLASS_ID, mVendorInfoBytes);
+            }
+            addTlvEnd(buffer);
+        }
+
+        // Convenience method.
+        public ByteBuffer build() {
+            // ENCAP_BOOTP packets don't contain ports, so just pass in 0.
+            ByteBuffer pkt = buildPacket(ENCAP_BOOTP, (short) 0, (short) 0);
+            pkt.flip();
+            return pkt;
+        }
+    }
+
+    private void assertDomainAndVendorInfoParses(
+            String expectedDomain, byte[] domainBytes,
+            String expectedVendorInfo, byte[] vendorInfoBytes) {
+        ByteBuffer packet = new TestDhcpPacket(DHCP_MESSAGE_TYPE_OFFER,
+                domainBytes, vendorInfoBytes).build();
+        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP);
+        assertEquals(expectedDomain, offerPacket.mDomainName);
+        assertEquals(expectedVendorInfo, offerPacket.mVendorId);
+    }
+
+    @SmallTest
+    public void testDomainName() throws Exception {
+        byte[] nullByte = new byte[] { 0x00 };
+        byte[] twoNullBytes = new byte[] { 0x00, 0x00 };
+        byte[] nonNullDomain = new byte[] {
+            (byte) 'g', (byte) 'o', (byte) 'o', (byte) '.', (byte) 'g', (byte) 'l'
+        };
+        byte[] trailingNullDomain = new byte[] {
+            (byte) 'g', (byte) 'o', (byte) 'o', (byte) '.', (byte) 'g', (byte) 'l', 0x00
+        };
+        byte[] embeddedNullsDomain = new byte[] {
+            (byte) 'g', (byte) 'o', (byte) 'o', 0x00, 0x00, (byte) 'g', (byte) 'l'
+        };
+        byte[] metered = "ANDROID_METERED".getBytes("US-ASCII");
+
+        byte[] meteredEmbeddedNull = metered.clone();
+        meteredEmbeddedNull[7] = (char) 0;
+
+        byte[] meteredTrailingNull = metered.clone();
+        meteredTrailingNull[meteredTrailingNull.length - 1] = (char) 0;
+
+        assertDomainAndVendorInfoParses("", nullByte, "\u0000", nullByte);
+        assertDomainAndVendorInfoParses("", twoNullBytes, "\u0000\u0000", twoNullBytes);
+        assertDomainAndVendorInfoParses("goo.gl", nonNullDomain, "ANDROID_METERED", metered);
+        assertDomainAndVendorInfoParses("goo", embeddedNullsDomain,
+                                        "ANDROID\u0000METERED", meteredEmbeddedNull);
+        assertDomainAndVendorInfoParses("goo.gl", trailingNullDomain,
+                                        "ANDROID_METERE\u0000", meteredTrailingNull);
+    }
+}
diff --git a/telephony/java/com/android/ims/ImsCallProfile.java b/telephony/java/com/android/ims/ImsCallProfile.java
index 8740e19..239c16a 100644
--- a/telephony/java/com/android/ims/ImsCallProfile.java
+++ b/telephony/java/com/android/ims/ImsCallProfile.java
@@ -270,7 +270,7 @@
         return "{ serviceType=" + mServiceType +
                 ", callType=" + mCallType +
                 ", restrictCause=" + mRestrictCause +
-                ", callExtras=" + mCallExtras.toString() +
+                //", callExtras=" + mCallExtras.toString() +
                 ", mediaProfile=" + mMediaProfile.toString() + " }";
     }
 
diff --git a/telephony/java/com/android/ims/internal/IImsUt.aidl b/telephony/java/com/android/ims/internal/IImsUt.aidl
index 50a0169..c531ea5 100644
--- a/telephony/java/com/android/ims/internal/IImsUt.aidl
+++ b/telephony/java/com/android/ims/internal/IImsUt.aidl
@@ -79,12 +79,13 @@
     /**
      * Updates the configuration of the call forward.
      */
-    int updateCallForward(int action, int condition, String number, int timeSeconds);
+    int updateCallForward(int action, int condition, String number,
+            int serviceClass, int timeSeconds);
 
     /**
      * Updates the configuration of the call waiting.
      */
-    int updateCallWaiting(boolean enable);
+    int updateCallWaiting(boolean enable, int serviceClass);
 
     /**
      * Updates the configuration of the CLIR supplementary service.
diff --git a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java b/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
index 9284796..0f73342 100644
--- a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
+++ b/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
@@ -141,6 +141,7 @@
         return (int)mControllerIdleTimeMs;
     }
 
+
     /**
      * product of current(mA), voltage(V) and time(ms)
      * @return energy used
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 36fc96b..440ad61 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -235,8 +235,10 @@
         public static final int SIM     = 4;
         /** EAP-Authentication and Key Agreement */
         public static final int AKA     = 5;
+        /** EAP-Authentication and Key Agreement Prime */
+        public static final int AKA_PRIME = 6;
         /** @hide */
-        public static final String[] strings = { "PEAP", "TLS", "TTLS", "PWD", "SIM", "AKA" };
+        public static final String[] strings = { "PEAP", "TLS", "TTLS", "PWD", "SIM", "AKA", "AKA'" };
 
         /** Prevent initialization */
         private Eap() {}
@@ -286,6 +288,7 @@
             case Eap.TTLS:
             case Eap.SIM:
             case Eap.AKA:
+            case Eap.AKA_PRIME:
                 mFields.put(EAP_KEY, Eap.strings[eapMethod]);
                 mFields.put(OPP_KEY_CACHING, "1");
                 break;
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 6371891..275c7d1 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -861,6 +861,14 @@
     public static final int WIFI_FEATURE_TDLS_OFFCHANNEL  = 0x2000;  // Support for TDLS off channel
     /** @hide */
     public static final int WIFI_FEATURE_EPR              = 0x4000;  // Enhanced power reporting
+    /** @hide */
+    public static final int WIFI_FEATURE_AP_STA            = 0x8000;  // Support for AP STA Concurrency
+    /** @hide */
+    public static final int WIFI_FEATURE_LINK_LAYER_STATS  = 0x10000; // Link layer stats collection
+    /** @hide */
+    public static final int WIFI_FEATURE_LOGGER            = 0x20000; // WiFi Logger
+    /** @hide */
+    public static final int WIFI_FEATURE_HAL_EPNO          = 0x40000; // WiFi PNO enhanced
 
     private int getSupportedFeatures() {
         try {
@@ -972,7 +980,7 @@
      * @return true if this adapter supports advanced power/performance counters
      */
     public boolean isEnhancedPowerReportingSupported() {
-        return isFeatureSupported(WIFI_FEATURE_EPR);
+        return isFeatureSupported(WIFI_FEATURE_LINK_LAYER_STATS);
     }
 
     /**