Merge "Import translations. DO NOT MERGE"
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index b830d1e..0d5600e3 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -680,30 +680,7 @@
     }
 
     /**
-     * Performs action based on user action to turn BT ON
-     * or OFF if BT is in BLE_ON state
-     */
-    private void notifyUserAction(boolean enable) {
-        try {
-            mServiceLock.readLock().lock();
-            if (mService == null) {
-                Log.e(TAG, "mService is null");
-                return;
-            }
-            if (enable) {
-                mService.onLeServiceUp(); //NA:TODO implementation pending
-            } else {
-                mService.onBrEdrDown(); //NA:TODO implementation pending
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "", e);
-        } finally {
-            mServiceLock.readLock().unlock();
-        }
-    }
-
-    /**
-     * Turns off Bluetooth LE which was earlier turned on by calling EnableBLE().
+     * Turns off Bluetooth LE which was earlier turned on by calling enableBLE().
      *
      * <p> If the internal Adapter state is STATE_BLE_ON, this would trigger the transition
      * to STATE_OFF and completely shut-down Bluetooth
@@ -733,61 +710,50 @@
         if (!isBleScanAlwaysAvailable()) return false;
 
         int state = getLeState();
-        if (state == BluetoothAdapter.STATE_ON) {
-            if (DBG) Log.d (TAG, "STATE_ON: shouldn't disable");
+        if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_BLE_ON) {
+            String packageName = ActivityThread.currentPackageName();
+            if (DBG) Log.d (TAG, "disableBLE(): de-registering " + packageName);
             try {
-                mManagerService.updateBleAppCount(mToken, false);
+                mManagerService.updateBleAppCount(mToken, false, packageName);
             } catch (RemoteException e) {
                 Log.e(TAG, "", e);
             }
             return true;
-
-        } else if (state == BluetoothAdapter.STATE_BLE_ON) {
-            if (DBG) Log.d (TAG, "STATE_BLE_ON");
-            int bleAppCnt = 0;
-            try {
-                bleAppCnt = mManagerService.updateBleAppCount(mToken, false);
-            } catch (RemoteException e) {
-                Log.e(TAG, "", e);
-            }
-            if (bleAppCnt == 0) {
-                // Disable only if there are no other clients
-                notifyUserAction(false);
-            }
-            return true;
         }
 
-        if (DBG) Log.d (TAG, "STATE_OFF: Already disabled");
+        if (DBG) Log.d (TAG, "disableBLE(): Already disabled");
         return false;
     }
 
     /**
-     * Special Applications who want to only turn on Bluetooth Low Energy (BLE) would
-     * EnableBLE, EnableBLE brings-up Bluetooth so that application can access
-     * only LE related feature (Bluetooth GATT layers interfaces using the respective class)
-     * EnableBLE in turn registers the existance of a special App which wants to
-     * turn on Bluetooth Low enrgy part without making it visible at the settings UI
-     * as Bluetooth ON.
-     * <p>Invoking EnableBLE when Bluetooth is already in ON state, would just registers
-     * the existance of special Application and doesn't do anything to current BT state.
-     * when user turn OFF Bluetooth from UI, if there is an existance of special app, Bluetooth
-     * would stay in BLE_ON state so that LE features are still acessible to the special
-     * Applications.
+     * Applications who want to only use Bluetooth Low Energy (BLE) can call enableBLE.
      *
-     * <p>This is an asynchronous call: it will return immediately, and
+     * enableBLE registers the existence of an app using only LE functions.
+     *
+     * enableBLE may enable Bluetooth to an LE only mode so that an app can use
+     * LE related features (BluetoothGatt or BluetoothGattServer classes)
+     *
+     * If the user disables Bluetooth while an app is registered to use LE only features,
+     * Bluetooth will remain on in LE only mode for the app.
+     *
+     * When Bluetooth is in LE only mode, it is not shown as ON to the UI.
+     *
+     * <p>This is an asynchronous call: it returns immediately, and
      * clients should listen for {@link #ACTION_BLE_STATE_CHANGED}
-     * to be notified of subsequent adapter state changes. If this call returns
-     * true, then the adapter state will immediately transition from {@link
-     * #STATE_OFF} to {@link #STATE_BLE_TURNING_ON}, and some time
-     * later transition to either {@link #STATE_OFF} or {@link
-     * #STATE_BLE_ON}. If this call returns false then there was an
-     * immediate problem that will prevent the adapter from being turned on -
-     * such as Airplane mode, or the adapter is already turned on.
-     * (@link #ACTION_BLE_STATE_CHANGED) returns the Bluetooth Adapter's various
+     * to be notified of adapter state changes.
+     *
+     * If this call returns * true, then the adapter state is either in a mode where
+     * LE is available, or will transition from {@link #STATE_OFF} to {@link #STATE_BLE_TURNING_ON},
+     * and some time later transition to either {@link #STATE_OFF} or {@link #STATE_BLE_ON}.
+     *
+     * If this call returns false then there was an immediate problem that prevents the
+     * adapter from being turned on - such as Airplane mode.
+     *
+     * {@link #ACTION_BLE_STATE_CHANGED} returns the Bluetooth Adapter's various
      * states, It includes all the classic Bluetooth Adapter states along with
      * internal BLE only states
      *
-     * @return true to indicate Bluetooth LE start-up has begun, or false on
+     * @return true to indicate Bluetooth LE will be available, or false on
      *         immediate error
      * @hide
      */
@@ -796,13 +762,14 @@
         if (!isBleScanAlwaysAvailable()) return false;
 
         try {
-            mManagerService.updateBleAppCount(mToken, true);
+            String packageName = ActivityThread.currentPackageName();
+            mManagerService.updateBleAppCount(mToken, true, packageName);
             if (isLeEnabled()) {
                 if (DBG) Log.d(TAG, "enableBLE(): Bluetooth already enabled");
                 return true;
             }
             if (DBG) Log.d(TAG, "enableBLE(): Calling enable");
-            return mManagerService.enable(ActivityThread.currentPackageName());
+            return mManagerService.enable(packageName);
         } catch (RemoteException e) {
             Log.e(TAG, "", e);
         }
@@ -1940,9 +1907,6 @@
         } else if (profile == BluetoothProfile.MAP_CLIENT) {
             BluetoothMapClient mapClient = new BluetoothMapClient(context, listener);
             return true;
-        } else if (profile == BluetoothProfile.INPUT_HOST) {
-            BluetoothInputHost iHost = new BluetoothInputHost(context, listener);
-            return true;
         } else {
             return false;
         }
@@ -2019,10 +1983,6 @@
                 BluetoothMapClient mapClient = (BluetoothMapClient)proxy;
                 mapClient.close();
                 break;
-            case BluetoothProfile.INPUT_HOST:
-                BluetoothInputHost iHost = (BluetoothInputHost) proxy;
-                iHost.close();
-                break;
         }
     }
 
@@ -2094,7 +2054,7 @@
             return true;
         }
         try {
-            return mManagerService.enableNoAutoConnect();
+            return mManagerService.enableNoAutoConnect(ActivityThread.currentPackageName());
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return false;
     }
diff --git a/core/java/android/bluetooth/IBluetoothManager.aidl b/core/java/android/bluetooth/IBluetoothManager.aidl
index 3af4a4d..2d5fc98 100644
--- a/core/java/android/bluetooth/IBluetoothManager.aidl
+++ b/core/java/android/bluetooth/IBluetoothManager.aidl
@@ -35,8 +35,8 @@
     void unregisterStateChangeCallback(in IBluetoothStateChangeCallback callback);
     boolean isEnabled();
     boolean enable(String packageName);
-    boolean enableNoAutoConnect();
-    boolean disable( String packageName, boolean persist);
+    boolean enableNoAutoConnect(String packageName);
+    boolean disable(String packageName, boolean persist);
     int getState();
     IBluetoothGatt getBluetoothGatt();
 
@@ -47,7 +47,7 @@
     String getName();
 
     boolean isBleScanAlwaysAvailable();
-    int updateBleAppCount(IBinder b, boolean enable);
+    int updateBleAppCount(IBinder b, boolean enable, String packageName);
     boolean isBleAppPresent();
 }
 
diff --git a/packages/Keyguard/res/values-nl/strings.xml b/packages/Keyguard/res/values-nl/strings.xml
index c44381e..fe87df8 100644
--- a/packages/Keyguard/res/values-nl/strings.xml
+++ b/packages/Keyguard/res/values-nl/strings.xml
@@ -44,7 +44,7 @@
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Onbruikbare simkaart."</string>
     <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Je simkaart is permanent uitgeschakeld.\n Neem contact op met je mobiele serviceprovider voor een nieuwe simkaart."</string>
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"Simkaart is vergrendeld."</string>
-    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"Simkaart is vergrendeld met PUK-code."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"Simkaart is vergrendeld met pukcode."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Simkaart ontgrendelen…"</string>
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Gebied voor pincode"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Gebied voor sim-pincode"</string>
@@ -62,14 +62,14 @@
     <string name="kg_sim_pin_instructions_multi" msgid="7818515973197201434">"Voer de pincode in voor de simkaart van \'<xliff:g id="CARRIER">%1$s</xliff:g>\'"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Pincode opgeven"</string>
     <string name="kg_password_instructions" msgid="5753646556186936819">"Wachtwoord invoeren"</string>
-    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"De simkaart is nu uitgeschakeld. Geef de PUK-code op om door te gaan. Neem contact op met de provider voor informatie."</string>
-    <string name="kg_puk_enter_puk_hint_multi" msgid="363822494559783025">"Simkaart van \'<xliff:g id="CARRIER">%1$s</xliff:g>\' is nu uitgeschakeld. Voer de PUK-code in om door te gaan. Neem contact op met je provider voor meer informatie."</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"De simkaart is nu uitgeschakeld. Geef de pukcode op om door te gaan. Neem contact op met de provider voor informatie."</string>
+    <string name="kg_puk_enter_puk_hint_multi" msgid="363822494559783025">"Simkaart van \'<xliff:g id="CARRIER">%1$s</xliff:g>\' is nu uitgeschakeld. Voer de pukcode in om door te gaan. Neem contact op met je provider voor meer informatie."</string>
     <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Gewenste pincode opgeven"</string>
     <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Gewenste pincode bevestigen"</string>
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Simkaart ontgrendelen..."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Voer een pincode van 4 tot 8 cijfers in."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"De PUK-code is minimaal acht nummers lang."</string>
-    <string name="kg_invalid_puk" msgid="3638289409676051243">"Geef de juiste PUK-code opnieuw op. Bij herhaalde pogingen wordt de simkaart permanent uitgeschakeld."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"De pukcode is minimaal acht nummers lang."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Geef de juiste pukcode opnieuw op. Bij herhaalde pogingen wordt de simkaart permanent uitgeschakeld."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Pincodes komen niet overeen"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Te veel patroonpogingen"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Je hebt je pincode <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getypt. \n\nProbeer het opnieuw over <xliff:g id="NUMBER_1">%2$d</xliff:g> seconden."</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 0f2e6d4..89d7fab 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -325,7 +325,7 @@
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Ingesteld door beheerder"</string>
     <string name="enabled_by_admin" msgid="2386503803463071894">"Ingeschakeld door beheerder"</string>
     <string name="disabled_by_admin" msgid="3669999613095206948">"Uitgeschakeld door beheerder"</string>
-    <string name="home" msgid="3256884684164448244">"Startpagina voor instellingen"</string>
+    <string name="home" msgid="3256884684164448244">"Homepage voor instellingen"</string>
   <string-array name="battery_labels">
     <item msgid="8494684293649631252">"0%"</item>
     <item msgid="8934126114226089439">"50%"</item>
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
index 493e618..34c0c64 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
@@ -424,7 +424,7 @@
                                              final ReferenceCountedTrigger postAnimationTrigger) {
         TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm();
 
-        int offscreenXOffset = mStackView.getMeasuredWidth() - stackLayout.mTaskRect.left;
+        int offscreenXOffset = mStackView.getMeasuredWidth() - stackLayout.getTaskRect().left;
 
         int taskViewCount = taskViews.size();
         for (int i = taskViewCount - 1; i >= 0; i--) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index be1844d..3499dfd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -1319,6 +1319,13 @@
         mFrontOfStackTransform.visible = true;
     }
 
+    /**
+     * Returns the proper task rectangle according to the current grid state.
+     */
+    public Rect getTaskRect() {
+        return mGridState.useGridLayout() ? mTaskGridLayoutAlgorithm.getTaskGridRect() : mTaskRect;
+    }
+
     public void dump(String prefix, PrintWriter writer) {
         String innerPrefix = prefix + "  ";
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 375f01e..760bf54 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -1268,8 +1268,8 @@
         if (tv.getBackground() != null) {
             tv.getBackground().getPadding(padding);
         }
-        mTmpRect.set(mStableLayoutAlgorithm.mTaskRect);
-        mTmpRect.union(mLayoutAlgorithm.mTaskRect);
+        mTmpRect.set(mStableLayoutAlgorithm.getTaskRect());
+        mTmpRect.union(mLayoutAlgorithm.getTaskRect());
         tv.measure(
                 MeasureSpec.makeMeasureSpec(mTmpRect.width() + padding.left + padding.right,
                         MeasureSpec.EXACTLY),
@@ -1314,8 +1314,8 @@
             if (tv.getBackground() != null) {
                 tv.getBackground().getPadding(padding);
             }
-            mTmpRect.set(mStableLayoutAlgorithm.mTaskRect);
-            mTmpRect.union(mLayoutAlgorithm.mTaskRect);
+            mTmpRect.set(mStableLayoutAlgorithm.getTaskRect());
+            mTmpRect.union(mLayoutAlgorithm.getTaskRect());
             tv.cancelTransformAnimation();
             tv.layout(mTmpRect.left - padding.left, mTmpRect.top - padding.top,
                     mTmpRect.right + padding.right, mTmpRect.bottom + padding.bottom);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
index 714b6fb..be3af040 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
@@ -195,4 +195,8 @@
         buttonRect.bottom = buttonRect.top + mPaddingTopBottom;
         return buttonRect;
     }
+
+    public Rect getTaskGridRect() {
+        return mTaskGridRect;
+    }
 }
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 1af400e..b8a2340 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -58,14 +58,16 @@
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.util.Slog;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
 import java.util.HashMap;
+import java.util.LinkedList;
 import java.util.Map;
 
+
 class BluetoothManagerService extends IBluetoothManager.Stub {
     private static final String TAG = "BluetoothManagerService";
     private static final boolean DBG = true;
@@ -138,16 +140,46 @@
         new ReentrantReadWriteLock();
     private boolean mBinding;
     private boolean mUnbinding;
+
     // used inside handler thread
     private boolean mQuietEnable = false;
-    // configuarion from external IBinder call which is used to
+    private boolean mEnable;
+
+    /**
+     * Used for tracking apps that enabled / disabled Bluetooth.
+     */
+    private class ActiveLog {
+        private String mPackageName;
+        private boolean mEnable;
+        private long mTimestamp;
+
+        public ActiveLog(String packageName, boolean enable, long timestamp) {
+            mPackageName = packageName;
+            mEnable = enable;
+            mTimestamp = timestamp;
+        }
+
+        public long getTime() {
+            return mTimestamp;
+        }
+
+        public String toString() {
+            return android.text.format.DateFormat.format("MM-dd hh:mm:ss ", mTimestamp) +
+                    (mEnable ? "  Enabled " : " Disabled ") + " by " + mPackageName;
+        }
+
+    }
+
+    private LinkedList<ActiveLog> mActiveLogs;
+
+    // configuration from external IBinder call which is used to
     // synchronize with broadcast receiver.
     private boolean mQuietEnableExternal;
-    // configuarion from external IBinder call which is used to
-    // synchronize with broadcast receiver.
     private boolean mEnableExternal;
-    // used inside handler thread
-    private boolean mEnable;
+
+    // Map of apps registered to keep BLE scanning on.
+    private Map<IBinder, ClientDeathRecipient> mBleApps = new ConcurrentHashMap<IBinder, ClientDeathRecipient>();
+
     private int mState;
     private final BluetoothHandler mHandler;
     private int mErrorRecoveryRetryCounter;
@@ -173,7 +205,7 @@
         }
     }
 
-    private final IBluetoothCallback mBluetoothCallback =  new IBluetoothCallback.Stub() {
+    private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() {
         @Override
         public void onBluetoothStateChange(int prevState, int newState) throws RemoteException  {
             Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState);
@@ -253,12 +285,12 @@
                         } else if (st == BluetoothAdapter.STATE_ON){
                             // disable without persisting the setting
                             Slog.d(TAG, "Calling disable");
-                            sendDisableMsg();
+                            sendDisableMsg("airplane mode");
                         }
                     } else if (mEnableExternal) {
                         // enable without persisting the setting
                         Slog.d(TAG, "Calling enable");
-                        sendEnableMsg(mQuietEnableExternal);
+                        sendEnableMsg(mQuietEnableExternal, "airplane mode");
                     }
                 }
             }
@@ -273,6 +305,7 @@
         mPermissionReviewRequired = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_permissionReviewRequired);
 
+        mActiveLogs = new LinkedList<ActiveLog>();
         mBluetooth = null;
         mBluetoothBinder = null;
         mBluetoothGatt = null;
@@ -300,15 +333,15 @@
             mEnableExternal = true;
         }
 
-        int sysUiUid = -1;
+        int systemUiUid = -1;
         try {
-            sysUiUid = mContext.getPackageManager().getPackageUidAsUser("com.android.systemui",
+            systemUiUid = mContext.getPackageManager().getPackageUidAsUser("com.android.systemui",
                     PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
         } catch (PackageManager.NameNotFoundException e) {
             // Some platforms, such as wearables do not have a system ui.
             Slog.w(TAG, "Unable to resolve SystemUI's UID.", e);
         }
-        mSystemUiUid = sysUiUid;
+        mSystemUiUid = systemUiUid;
     }
 
     /**
@@ -488,8 +521,14 @@
     }
 
     class ClientDeathRecipient implements IBinder.DeathRecipient {
+        private String mPackageName;
+
+        public ClientDeathRecipient(String packageName) {
+            mPackageName = packageName;
+        }
+
         public void binderDied() {
-            if (DBG) Slog.d(TAG, "Binder is dead - unregister Ble App");
+            if (DBG) Slog.d(TAG, "Binder is dead - unregister " + mPackageName);
             if (isBleAppPresent()) {
               // Nothing to do, another app is here.
               return;
@@ -508,10 +547,11 @@
                 mBluetoothLock.readLock().unlock();
             }
         }
-    }
 
-    /** Internal death rec list */
-    Map<IBinder, ClientDeathRecipient> mBleApps = new ConcurrentHashMap<IBinder, ClientDeathRecipient>();
+        public String getPackageName() {
+            return mPackageName;
+        }
+    }
 
     @Override
     public boolean isBleScanAlwaysAvailable() {
@@ -569,28 +609,22 @@
         }
     }
 
-    public int updateBleAppCount(IBinder token, boolean enable) {
-        if (enable) {
-            ClientDeathRecipient r = mBleApps.get(token);
-            if (r == null) {
-                ClientDeathRecipient deathRec = new ClientDeathRecipient();
-                try {
-                    token.linkToDeath(deathRec, 0);
-                } catch (RemoteException ex) {
-                    throw new IllegalArgumentException("Wake lock is already dead.");
-                }
-                mBleApps.put(token, deathRec);
-                if (DBG) Slog.d(TAG, "Registered for death Notification");
+    public int updateBleAppCount(IBinder token, boolean enable, String packageName) {
+        ClientDeathRecipient r = mBleApps.get(token);
+        if (r == null && enable) {
+            ClientDeathRecipient deathRec = new ClientDeathRecipient(packageName);
+            try {
+                token.linkToDeath(deathRec, 0);
+            } catch (RemoteException ex) {
+                throw new IllegalArgumentException("BLE app (" + packageName + ") already dead!");
             }
-
-        } else  {
-            ClientDeathRecipient r = mBleApps.get(token);
-            if (r != null) {
-                // Unregister death recipient as the app goes away.
-                token.unlinkToDeath(r, 0);
-                mBleApps.remove(token);
-                if (DBG) Slog.d(TAG, "Unregistered for death Notification");
-            }
+            mBleApps.put(token, deathRec);
+            if (DBG) Slog.d(TAG, "Registered for death of " + packageName);
+        } else if (!enable && r != null) {
+            // Unregister death recipient as the app goes away.
+            token.unlinkToDeath(r, 0);
+            mBleApps.remove(token);
+            if (DBG) Slog.d(TAG, "Unregistered for death of " + packageName);
         }
         int appCount = mBleApps.size();
         if (DBG) Slog.d(TAG, appCount + " registered Ble Apps");
@@ -605,7 +639,7 @@
         mBleApps.clear();
     }
 
-    /** @hide*/
+    /** @hide */
     public boolean isBleAppPresent() {
         if (DBG) Slog.d(TAG, "isBleAppPresent() count: " + mBleApps.size());
         return mBleApps.size() > 0;
@@ -671,7 +705,7 @@
         }
     }
 
-    public boolean enableNoAutoConnect()
+    public boolean enableNoAutoConnect(String packageName)
     {
         if (isBluetoothDisallowed()) {
             if (DBG) {
@@ -696,7 +730,7 @@
         synchronized(mReceiver) {
             mQuietEnableExternal = true;
             mEnableExternal = true;
-            sendEnableMsg(true);
+            sendEnableMsg(true, packageName);
         }
         return true;
     }
@@ -729,7 +763,7 @@
         }
 
         if (DBG) {
-            Slog.d(TAG,"enable():  mBluetooth =" + mBluetooth +
+            Slog.d(TAG,"enable(" + packageName + "):  mBluetooth =" + mBluetooth +
                     " mBinding = " + mBinding + " mState = " +
                     BluetoothAdapter.nameForState(mState));
         }
@@ -738,7 +772,7 @@
             mQuietEnableExternal = false;
             mEnableExternal = true;
             // waive WRITE_SECURE_SETTINGS permission check
-            sendEnableMsg(false);
+            sendEnableMsg(false, packageName);
         }
         if (DBG) Slog.d(TAG, "enable returning");
         return true;
@@ -774,7 +808,7 @@
                 persistBluetoothSetting(BLUETOOTH_OFF);
             }
             mEnableExternal = false;
-            sendDisableMsg();
+            sendDisableMsg(packageName);
         }
         return true;
     }
@@ -928,7 +962,7 @@
         }
         if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) {
             if (DBG) Slog.d(TAG, "Auto-enabling Bluetooth.");
-            sendEnableMsg(mQuietEnableExternal);
+            sendEnableMsg(mQuietEnableExternal, "system boot");
         } else if (!isNameAndAddressSet()) {
             if (DBG) Slog.d(TAG, "Getting adapter name and address");
             Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
@@ -1897,13 +1931,24 @@
         return false;
     }
 
-    private void sendDisableMsg() {
+    private void sendDisableMsg(String packageName) {
         mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE));
+        addActiveLog(packageName, false);
     }
 
-    private void sendEnableMsg(boolean quietMode) {
+    private void sendEnableMsg(boolean quietMode, String packageName) {
         mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
                              quietMode ? 1 : 0, 0));
+        addActiveLog(packageName, true);
+    }
+
+    private void addActiveLog(String packageName, boolean enable) {
+        synchronized (mActiveLogs) {
+            if (mActiveLogs.size() > 10) {
+                mActiveLogs.remove();
+            }
+            mActiveLogs.add(new ActiveLog(packageName, enable, System.currentTimeMillis()));
+        }
     }
 
     private void recoverBluetoothServiceFromError(boolean clearBle) {
@@ -1974,19 +2019,50 @@
     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
         String errorMsg = null;
+
+        boolean protoOut = (args.length > 0) && args[0].startsWith("--proto");
+
+        if (!protoOut) {
+            writer.println("Bluetooth Status");
+            writer.println("  enabled: " + isEnabled());
+            writer.println("  state: " + BluetoothAdapter.nameForState(mState));
+            writer.println("  address: " + mAddress);
+            writer.println("  name: " + mName);
+            if (mEnable) {
+                long onDuration = System.currentTimeMillis() - mActiveLogs.getLast().getTime();
+                String onDurationString = String.format("%02d:%02d:%02d.%03d",
+                                          (int)(onDuration / (1000 * 60 * 60)),
+                                          (int)((onDuration / (1000 * 60)) % 60),
+                                          (int)((onDuration / 1000) % 60),
+                                          (int)(onDuration % 1000));
+                writer.println("  time since enabled: " + onDurationString + "\n");
+            }
+
+            writer.println("Enable log:");
+            for (ActiveLog log : mActiveLogs) {
+                writer.println(log);
+            }
+
+            writer.println("\n" + mBleApps.size() + " BLE Apps registered:");
+            for (ClientDeathRecipient app : mBleApps.values()) {
+                writer.println(app.getPackageName());
+            }
+
+            writer.flush();
+        }
+
         if (mBluetoothBinder == null) {
             errorMsg = "Bluetooth Service not connected";
         } else {
             try {
                 mBluetoothBinder.dump(fd, args);
             } catch (RemoteException re) {
-                errorMsg = "RemoteException while calling Bluetooth Service";
+                errorMsg = "RemoteException while dumping Bluetooth Service";
             }
         }
         if (errorMsg != null) {
             // Silently return if we are extracting metrics in Protobuf format
-            if ((args.length > 0) && args[0].startsWith("--proto"))
-                return;
+            if (protoOut) return;
             writer.println(errorMsg);
         }
     }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 0f16750..2ade924 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -4831,6 +4831,10 @@
                 + (altOrientation ? " (alt)" : "") + " from " + mRotation
                 + (mAltOrientation ? " (alt)" : "") + ", lastOrientation=" + mLastOrientation);
 
+        if (DisplayContent.deltaRotation(rotation, mRotation) != 2) {
+            mWaitingForConfig = true;
+        }
+
         mRotation = rotation;
         mAltOrientation = altOrientation;
         mPolicy.setRotationLw(mRotation);
@@ -4838,7 +4842,7 @@
         mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
         mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
         mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, WINDOW_FREEZE_TIMEOUT_DURATION);
-        mWaitingForConfig = true;
+
         dc.setLayoutNeeded();
         final int[] anim = new int[2];
         if (dc.isDimming()) {