Merge changes from topic 'sysui-tooltip' into oc-dev

* changes:
  Pass window token when creating a tooltip popup
  Revert "Use a PopupWindow to show tooltips"
diff --git a/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java b/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java
index c66a3a4..8296b7a 100644
--- a/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java
+++ b/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java
@@ -15,13 +15,13 @@
  */
 package android.hardware.camera2.dispatch;
 
+import static com.android.internal.util.Preconditions.checkNotNull;
+
 import android.hardware.camera2.utils.UncheckedThrow;
 
 import java.lang.reflect.Method;
 import java.util.concurrent.ConcurrentHashMap;
 
-import static com.android.internal.util.Preconditions.*;
-
 /**
  * Invoke a method on a dispatchable by its name (without knowing the {@code Method} ahead of time).
  *
@@ -31,6 +31,7 @@
 
     private final Dispatchable<T> mTarget;
     private final Class<T> mTargetClass;
+    private final Method[] mTargetClassMethods;
     private final ConcurrentHashMap<String, Method> mMethods =
             new ConcurrentHashMap<>();
 
@@ -42,6 +43,7 @@
      */
     public MethodNameInvoker(Dispatchable<T> target, Class<T> targetClass) {
         mTargetClass = targetClass;
+        mTargetClassMethods = targetClass.getMethods();
         mTarget = target;
     }
 
@@ -68,7 +70,7 @@
 
         Method targetMethod = mMethods.get(methodName);
         if (targetMethod == null) {
-            for (Method method : mTargetClass.getMethods()) {
+            for (Method method : mTargetClassMethods) {
                 // TODO future: match types of params if possible
                 if (method.getName().equals(methodName) &&
                         (params.length == method.getParameterTypes().length) ) {
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index bc96e43..fcf18eb 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -327,17 +327,6 @@
         }
 
         /**
-         * @deprecated Use {@link #setClientState(Bundle)} instead.
-         * @hide
-         */
-        @Deprecated
-        public Builder setExtras(@Nullable Bundle extras) {
-            throwIfDestroyed();
-            mCLientState = extras;
-            return this;
-        }
-
-        /**
          * Sets a {@link Bundle state} that will be passed to subsequent APIs that
          * manipulate this response. For example, they are passed to subsequent
          * calls to {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal,
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 7e8bc00..236c185 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -811,7 +811,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Confirmació de la navegació"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Surt d\'aquesta pàgina"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Queda\'t en aquesta pàgina"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nEstàs segur que vols sortir d\'aquesta pàgina?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nConfirmes que vols sortir d\'aquesta pàgina?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Confirma"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Consell: Pica dos cops per ampliar i per reduir."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Em. aut."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 320ffcb..3251771 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1575,8 +1575,8 @@
     <string name="mediasize_japanese_kahu" msgid="6872696027560065173">"Kahu"</string>
     <string name="mediasize_japanese_kaku2" msgid="2359077233775455405">"Kaku2"</string>
     <string name="mediasize_japanese_you4" msgid="2091777168747058008">"You4"</string>
-    <string name="mediasize_unknown_portrait" msgid="3088043641616409762">"Ukendt portrætformat"</string>
-    <string name="mediasize_unknown_landscape" msgid="4876995327029361552">"Ukendt landskabsformat"</string>
+    <string name="mediasize_unknown_portrait" msgid="3088043641616409762">"Ukendt stående format"</string>
+    <string name="mediasize_unknown_landscape" msgid="4876995327029361552">"Ukendt liggende format"</string>
     <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Annulleret"</string>
     <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Fejl ved skrivning af indhold"</string>
     <string name="reason_unknown" msgid="6048913880184628119">"ukendt"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 82c0f63..26f3f1d 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -90,7 +90,7 @@
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Η υπηρεσία δεν προβλέπεται."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Δεν μπορείτε να αλλάξετε τη ρύθμιση του αναγνωριστικού καλούντος."</string>
     <string name="RestrictedOnDataTitle" msgid="1322504692764166532">"Δεν υπάρχει υπηρεσία δεδομένων"</string>
-    <string name="RestrictedOnEmergencyTitle" msgid="3646729271176394091">"Αδυναμία πραγματοποίησης κλήσεων έκτακτης ανάγκης"</string>
+    <string name="RestrictedOnEmergencyTitle" msgid="3646729271176394091">"Δεν επιτρέπονται οι κλήσεις έκτακτης ανάγκης"</string>
     <string name="RestrictedOnNormalTitle" msgid="3179574012752700984">"Δεν υπάρχει φωνητική υπηρεσία"</string>
     <string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Δεν υπάρχει φωνητική υπηρεσία/υπηρεσία έκτακτης ανάγκης"</string>
     <string name="RestrictedStateContent" msgid="4278821484643362350">"Δεν προσφέρεται προσωρινά από το δίκτυο κινητής τηλεφωνίας στην τοποθεσία σας"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index a2b4499..b9b202f 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -90,7 +90,7 @@
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Ce service n\'est pas pris en charge."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Impossible de modifier le paramètre relatif au numéro de l\'appelant."</string>
     <string name="RestrictedOnDataTitle" msgid="1322504692764166532">"Aucun service de données"</string>
-    <string name="RestrictedOnEmergencyTitle" msgid="3646729271176394091">"Aucune appel d\'urgence"</string>
+    <string name="RestrictedOnEmergencyTitle" msgid="3646729271176394091">"Aucun appel d\'urgence"</string>
     <string name="RestrictedOnNormalTitle" msgid="3179574012752700984">"Aucun service vocal"</string>
     <string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Aucun service vocal ou d\'urgence"</string>
     <string name="RestrictedStateContent" msgid="4278821484643362350">"Ce service est temporairement non offert par le réseau cellulaire à l\'endroit où vous êtes"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index b03d6cc..bf04d8a 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1201,7 +1201,7 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"भाषा और लेआउट चुनने के लिए टैप करें"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="alert_windows_notification_channel_group_name" msgid="1463953341148606396">"दूसरे ऐप्लिकेशन पर प्रदर्शित करें"</string>
+    <string name="alert_windows_notification_channel_group_name" msgid="1463953341148606396">"दूसरे ऐप्लिकेशन के ऊपर दिखाएं"</string>
     <string name="alert_windows_notification_channel_name" msgid="3116610965549449803">"<xliff:g id="NAME">%s</xliff:g> अन्य ऐप्लिकेशन के ऊपर दिखाई दे रहा है"</string>
     <string name="alert_windows_notification_title" msgid="3697657294867638947">"<xliff:g id="NAME">%s</xliff:g> अन्य ऐप पर दिखाई दे रहा है"</string>
     <string name="alert_windows_notification_message" msgid="8917232109522912560">"अगर आप नहीं चाहते कि <xliff:g id="NAME">%s</xliff:g> इस सुविधा का उपयोग करे, तो सेटिंग खोलने और उसे बंद करने के लिए टैप करें."</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 7135060..ef34aa5 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -93,7 +93,7 @@
     <string name="RestrictedOnEmergencyTitle" msgid="3646729271176394091">"긴급 전화 차단됨"</string>
     <string name="RestrictedOnNormalTitle" msgid="3179574012752700984">"음성 서비스를 이용할 수 없음"</string>
     <string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"음성/긴급 서비스를 이용할 수 없음"</string>
-    <string name="RestrictedStateContent" msgid="4278821484643362350">"현재 위치에서 모바일 네트워크가 긴급 서비스 제공을 일시적으로 중단했습니다."</string>
+    <string name="RestrictedStateContent" msgid="4278821484643362350">"현재 위치에서 모바일 네트워크가 서비스 제공을 일시적으로 중단했습니다."</string>
     <string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"네트워크에 연결할 수 없습니다."</string>
     <string name="NetworkPreferenceSwitchSummary" msgid="4164230263214915351">"수신 상태를 개선하려면 시스템 &gt; 네트워크 및 인터넷 &gt; 모바일 네트워크 &gt; 기본 네트워크 유형에서 선택된 유형을 변경해 보세요."</string>
     <string name="notification_channel_network_alert" msgid="4427736684338074967">"알림"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 6daa7a7..db4d8fc 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1202,7 +1202,7 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ဘာသာစကားနှင့် အသွင်အပြင်ရွေးချယ်ရန် တို့ပါ"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="alert_windows_notification_channel_group_name" msgid="1463953341148606396">"အခြားအက်ပ်များအပေါ်တွင် ပြသခွင့် ပြုခြင်း"</string>
+    <string name="alert_windows_notification_channel_group_name" msgid="1463953341148606396">"အခြားအက်ပ်များအပေါ်တွင် ပြသခြင်း"</string>
     <string name="alert_windows_notification_channel_name" msgid="3116610965549449803">"<xliff:g id="NAME">%s</xliff:g> သည် အခြားအက်ပ်များအပေါ်တွင် ပြပါသည်"</string>
     <string name="alert_windows_notification_title" msgid="3697657294867638947">"<xliff:g id="NAME">%s</xliff:g> ကို အခြားအက်ပ်များပေါ်တွင် မြင်နေရပါသည်။"</string>
     <string name="alert_windows_notification_message" msgid="8917232109522912560">"<xliff:g id="NAME">%s</xliff:g> ကို ဤဝန်ဆောင်မှုအား အသုံးမပြုစေလိုလျှင် ဆက်တင်ကို တို့၍ ဖွင့်ပြီး ၎င်းကို ပိတ်လိုက်ပါ။"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index df8d6d2..f64719c 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -90,7 +90,7 @@
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"ਸੇਵਾ ਪ੍ਰਬੰਧਿਤ ਨਹੀਂ ਹੈ।"</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"ਤੁਸੀਂ ਕਾਲਰ ID ਸੈਟਿੰਗ ਨਹੀਂ ਬਦਲ ਸਕਦੇ।"</string>
     <string name="RestrictedOnDataTitle" msgid="1322504692764166532">"ਕੋਈ ਡੈਟਾ ਸੇਵਾ ਨਹੀਂ"</string>
-    <string name="RestrictedOnEmergencyTitle" msgid="3646729271176394091">"ਕੋਈ ਸੰਕਟਕਾਲੀਨ ਕਾਲਿੰਗ ਨਹੀਂ"</string>
+    <string name="RestrictedOnEmergencyTitle" msgid="3646729271176394091">"ਸੰਕਟਕਾਲ ਵਿੱਚ ਕੋਈ ਕਾਲ ਨਹੀਂ"</string>
     <string name="RestrictedOnNormalTitle" msgid="3179574012752700984">"ਕੋਈ ਆਵਾਜ਼ੀ ਸੇਵਾ ਨਹੀਂ"</string>
     <string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"ਕੋਈ ਆਵਾਜ਼ੀ/ਸੰਕਟਕਾਲੀਨ ਸੇਵਾ ਨਹੀਂ"</string>
     <string name="RestrictedStateContent" msgid="4278821484643362350">"ਤੁਹਾਡੇ ਟਿਕਾਣੇ \'ਤੇ ਅਸਥਾਈ ਤੌਰ \'ਤੇ ਮੋਬਾਈਲ ਨੈੱਟਵਰਕ ਵੱਲੋਂ ਉਪਲਬਧ ਨਹੀਂ ਕਰਵਾਈ ਗਈ"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 844dceb..ba1963f 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -90,7 +90,7 @@
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"సేవ కేటాయించబడలేదు."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"మీరు కాలర్ ID సెట్టింగ్‌ను మార్చలేరు."</string>
     <string name="RestrictedOnDataTitle" msgid="1322504692764166532">"డేటా సేవ లేదు"</string>
-    <string name="RestrictedOnEmergencyTitle" msgid="3646729271176394091">"అత్యవసర కాలింగ్ లేదు"</string>
+    <string name="RestrictedOnEmergencyTitle" msgid="3646729271176394091">"అత్యవసర కాలింగ్ సదుపాయం లేదు"</string>
     <string name="RestrictedOnNormalTitle" msgid="3179574012752700984">"వాయిస్ సేవ లేదు"</string>
     <string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"వాయిస్/అత్యవసర సేవ లేదు"</string>
     <string name="RestrictedStateContent" msgid="4278821484643362350">"మీ స్థానంలో మొబైల్ నెట్‌వర్క్ ద్వారా తాత్కాలికంగా అందించబడదు"</string>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index bb302bb..47c4692 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -92,6 +92,7 @@
     private boolean mLastBouncerShowing;
     private boolean mLastBouncerDismissible;
     protected boolean mLastRemoteInputActive;
+    private boolean mLastDeferScrimFadeOut;
 
     private OnDismissAction mAfterKeyguardGoneAction;
     private final ArrayList<Runnable> mAfterKeyguardGoneRunnables = new ArrayList<>();
@@ -367,7 +368,6 @@
             mStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration);
             mFingerprintUnlockController.startKeyguardFadingAway();
             mBouncer.hide(true /* destroyView */);
-            updateStates();
             if (wakeUnlockPulsing) {
                 mStatusBarWindowManager.setKeyguardFadingAway(true);
                 mStatusBar.fadeKeyguardWhilePulsing();
@@ -399,6 +399,7 @@
                     mFingerprintUnlockController.finishKeyguardFadingAway();
                 }
             }
+            updateStates();
             mStatusBarWindowManager.setKeyguardShowing(false);
             mViewMediatorCallback.keyguardGone();
         }
@@ -569,7 +570,7 @@
         mLastBouncerShowing = bouncerShowing;
         mLastBouncerDismissible = bouncerDismissible;
         mLastRemoteInputActive = remoteInputActive;
-
+        mLastDeferScrimFadeOut = mDeferScrimFadeOut;
         mStatusBar.onKeyguardViewManagerStatesUpdated();
     }
 
@@ -577,14 +578,16 @@
      * @return Whether the navigation bar should be made visible based on the current state.
      */
     protected boolean isNavBarVisible() {
-        return !(mShowing && !mOccluded) || mBouncer.isShowing() || mRemoteInputActive;
+        return (!(mShowing && !mOccluded) || mBouncer.isShowing() || mRemoteInputActive)
+                && !mDeferScrimFadeOut;
     }
 
     /**
      * @return Whether the navigation bar was made visible based on the last known state.
      */
     protected boolean getLastNavBarVisible() {
-        return !(mLastShowing && !mLastOccluded) || mLastBouncerShowing || mLastRemoteInputActive;
+        return (!(mLastShowing && !mLastOccluded) || mLastBouncerShowing || mLastRemoteInputActive)
+                && !mLastDeferScrimFadeOut;
     }
 
     public boolean shouldDismissOnMenuPressed() {
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index b0d76e8..b8fe884 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -524,7 +524,7 @@
                                             Slog.d(TAG, "Removing jobs for package " + pkgName
                                                     + " in user " + userId);
                                         }
-                                        cancelJobsForUid(pkgUid);
+                                        cancelJobsForUid(pkgUid, "app package state changed");
                                     }
                                 } catch (RemoteException|IllegalArgumentException e) {
                                     /*
@@ -553,7 +553,7 @@
                     if (DEBUG) {
                         Slog.d(TAG, "Removing jobs for uid: " + uidRemoved);
                     }
-                    cancelJobsForUid(uidRemoved);
+                    cancelJobsForUid(uidRemoved, "app uninstalled");
                 }
             } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
                 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
@@ -611,7 +611,7 @@
         @Override public void onUidGone(int uid, boolean disabled) throws RemoteException {
             updateUidState(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
             if (disabled) {
-                cancelJobsForUid(uid);
+                cancelJobsForUid(uid, "uid gone");
             }
         }
 
@@ -620,7 +620,7 @@
 
         @Override public void onUidIdle(int uid, boolean disabled) throws RemoteException {
             if (disabled) {
-                cancelJobsForUid(uid);
+                cancelJobsForUid(uid, "app uid idle");
             }
         }
     };
@@ -689,7 +689,7 @@
             jobStatus.prepareLocked(ActivityManager.getService());
 
             if (toCancel != null) {
-                cancelJobImplLocked(toCancel, jobStatus);
+                cancelJobImplLocked(toCancel, jobStatus, "job rescheduled by app");
             }
             if (work != null) {
                 // If work has been supplied, enqueue it into the new job.
@@ -747,7 +747,7 @@
             final List<JobStatus> jobsForUser = mJobs.getJobsByUser(userHandle);
             for (int i=0; i<jobsForUser.size(); i++) {
                 JobStatus toRemove = jobsForUser.get(i);
-                cancelJobImplLocked(toRemove, null);
+                cancelJobImplLocked(toRemove, null, "user removed");
             }
         }
     }
@@ -765,7 +765,7 @@
             for (int i = jobsForUid.size() - 1; i >= 0; i--) {
                 final JobStatus job = jobsForUid.get(i);
                 if (job.getSourcePackageName().equals(pkgName)) {
-                    cancelJobImplLocked(job, null);
+                    cancelJobImplLocked(job, null, "app force stopped");
                 }
             }
         }
@@ -778,12 +778,12 @@
      * @param uid Uid to check against for removal of a job.
      *
      */
-    public void cancelJobsForUid(int uid) {
+    public void cancelJobsForUid(int uid, String reason) {
         synchronized (mLock) {
             final List<JobStatus> jobsForUid = mJobs.getJobsByUid(uid);
             for (int i=0; i<jobsForUid.size(); i++) {
                 JobStatus toRemove = jobsForUid.get(i);
-                cancelJobImplLocked(toRemove, null);
+                cancelJobImplLocked(toRemove, null, reason);
             }
         }
     }
@@ -800,12 +800,12 @@
         synchronized (mLock) {
             toCancel = mJobs.getJobByUidAndJobId(uid, jobId);
             if (toCancel != null) {
-                cancelJobImplLocked(toCancel, null);
+                cancelJobImplLocked(toCancel, null, "cancel() called by app");
             }
         }
     }
 
-    private void cancelJobImplLocked(JobStatus cancelled, JobStatus incomingJob) {
+    private void cancelJobImplLocked(JobStatus cancelled, JobStatus incomingJob, String reason) {
         if (DEBUG) Slog.d(TAG, "CANCEL: " + cancelled.toShortString());
         cancelled.unprepareLocked(ActivityManager.getService());
         stopTrackingJobLocked(cancelled, incomingJob, true /* writeBack */);
@@ -814,7 +814,7 @@
             mJobPackageTracker.noteNonpending(cancelled);
         }
         // Cancel if running.
-        stopJobOnServiceContextLocked(cancelled, JobParameters.REASON_CANCELED);
+        stopJobOnServiceContextLocked(cancelled, JobParameters.REASON_CANCELED, reason);
         reportActiveLocked();
     }
 
@@ -844,7 +844,8 @@
                     final JobStatus executing = jsc.getRunningJobLocked();
                     if (executing != null
                             && (executing.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) == 0) {
-                        jsc.cancelExecutingJobLocked(JobParameters.REASON_DEVICE_IDLE);
+                        jsc.cancelExecutingJobLocked(JobParameters.REASON_DEVICE_IDLE,
+                                "cancelled due to doze");
                     }
                 }
             } else {
@@ -1023,12 +1024,12 @@
         return removed;
     }
 
-    private boolean stopJobOnServiceContextLocked(JobStatus job, int reason) {
+    private boolean stopJobOnServiceContextLocked(JobStatus job, int reason, String debugReason) {
         for (int i=0; i<mActiveServices.size(); i++) {
             JobServiceContext jsc = mActiveServices.get(i);
             final JobStatus executing = jsc.getRunningJobLocked();
             if (executing != null && executing.matches(job.getUid(), job.getJobId())) {
-                jsc.cancelExecutingJobLocked(reason);
+                jsc.cancelExecutingJobLocked(reason, debugReason);
                 return true;
             }
         }
@@ -1270,7 +1271,8 @@
                         queueReadyJobsForExecutionLocked();
                         break;
                     case MSG_STOP_JOB:
-                        cancelJobImplLocked((JobStatus) message.obj, null);
+                        cancelJobImplLocked((JobStatus) message.obj, null,
+                                "app no longer allowed to run");
                         break;
                 }
                 maybeRunPendingJobsLocked();
@@ -1286,7 +1288,8 @@
             final JobStatus running = serviceContext.getRunningJobLocked();
             if (running != null && !running.isReady()) {
                 serviceContext.cancelExecutingJobLocked(
-                        JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED);
+                        JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED,
+                        "cancelled due to unsatisfied constraints");
             }
         }
     }
@@ -1960,7 +1963,7 @@
 
             long ident = Binder.clearCallingIdentity();
             try {
-                JobSchedulerService.this.cancelJobsForUid(uid);
+                JobSchedulerService.this.cancelJobsForUid(uid, "cancelAll() called by app");
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -2357,7 +2360,14 @@
                 pw.print("  Slot #"); pw.print(i); pw.print(": ");
                 final JobStatus job = jsc.getRunningJobLocked();
                 if (job == null) {
-                    pw.println("inactive");
+                    if (jsc.mStoppedReason != null) {
+                        pw.print("inactive since ");
+                        TimeUtils.formatDuration(jsc.mStoppedTime, nowElapsed, pw);
+                        pw.print(", stopped because: ");
+                        pw.println(jsc.mStoppedReason);
+                    } else {
+                        pw.println("inactive");
+                    }
                     continue;
                 } else {
                     pw.println(job.toShortString());
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index ff39baf..637db11 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -38,6 +38,7 @@
 import android.os.UserHandle;
 import android.os.WorkSource;
 import android.util.Slog;
+import android.util.TimeUtils;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -126,6 +127,12 @@
     /** Track when job will timeout. */
     private long mTimeoutElapsed;
 
+    // Debugging: reason this job was last stopped.
+    public String mStoppedReason;
+
+    // Debugging: time this job was last stopped.
+    public long mStoppedTime;
+
     JobServiceContext(JobSchedulerService service, IBatteryStats batteryStats,
             JobPackageTracker tracker, Looper looper) {
         this(service.getContext(), service.getLock(), batteryStats, tracker, service, looper);
@@ -204,6 +211,8 @@
             }
             mJobPackageTracker.noteActive(job);
             mAvailable = false;
+            mStoppedReason = null;
+            mStoppedTime = 0;
             return true;
         }
     }
@@ -216,12 +225,12 @@
     }
 
     /** Called externally when a job that was scheduled for execution should be cancelled. */
-    void cancelExecutingJobLocked(int reason) {
-        doCancelLocked(reason);
+    void cancelExecutingJobLocked(int reason, String debugReason) {
+        doCancelLocked(reason, debugReason);
     }
 
     void preemptExecutingJobLocked() {
-        doCancelLocked(JobParameters.REASON_PREEMPT);
+        doCancelLocked(JobParameters.REASON_PREEMPT, "cancelled due to preemption");
     }
 
     int getPreferredUid() {
@@ -247,7 +256,7 @@
                 && (!matchJobId || jobId == executing.getJobId())) {
             if (mVerb == VERB_EXECUTING) {
                 mParams.setStopReason(JobParameters.REASON_TIMEOUT);
-                sendStopMessageLocked();
+                sendStopMessageLocked("force timeout from shell");
                 return true;
             }
         }
@@ -256,17 +265,17 @@
 
     @Override
     public void jobFinished(int jobId, boolean reschedule) {
-        doCallback(reschedule);
+        doCallback(reschedule, "app called jobFinished");
     }
 
     @Override
     public void acknowledgeStopMessage(int jobId, boolean reschedule) {
-        doCallback(reschedule);
+        doCallback(reschedule, null);
     }
 
     @Override
     public void acknowledgeStartMessage(int jobId, boolean ongoing) {
-        doCallback(ongoing);
+        doCallback(ongoing, "finished start");
     }
 
     @Override
@@ -275,14 +284,11 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized (mLock) {
-                if (!verifyCallingUidLocked(callingUid)) {
-                    throw new SecurityException("Bad calling uid: " + callingUid);
-                }
-
+                assertCallingUidLocked(callingUid);
                 final JobWorkItem work = mRunningJob.dequeueWorkLocked();
                 if (work == null && !mRunningJob.hasExecutingWorkLocked()) {
                     // This will finish the job.
-                    doCallbackLocked(false);
+                    doCallbackLocked(false, "last work dequeued");
                 }
                 return work;
             }
@@ -297,9 +303,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized (mLock) {
-                if (!verifyCallingUidLocked(callingUid)) {
-                    throw new SecurityException("Bad calling uid: " + callingUid);
-                }
+                assertCallingUidLocked(callingUid);
                 return mRunningJob.completeWorkLocked(ActivityManager.getService(), workId);
             }
         } finally {
@@ -324,7 +328,8 @@
             runningJob = mRunningJob;
 
             if (runningJob == null || !name.equals(runningJob.getServiceComponent())) {
-                closeAndCleanupJobLocked(true /* needsReschedule */);
+                closeAndCleanupJobLocked(true /* needsReschedule */,
+                        "connected for different component");
                 return;
             }
             this.service = IJobService.Stub.asInterface(service);
@@ -355,7 +360,7 @@
     @Override
     public void onServiceDisconnected(ComponentName name) {
         synchronized (mLock) {
-            closeAndCleanupJobLocked(true /* needsReschedule */);
+            closeAndCleanupJobLocked(true /* needsReschedule */, "unexpectedly disconnected");
         }
     }
 
@@ -374,6 +379,21 @@
         return true;
     }
 
+    private void assertCallingUidLocked(final int callingUid) {
+        if (!verifyCallingUidLocked(callingUid)) {
+            StringBuilder sb = new StringBuilder(128);
+            sb.append("Bad calling uid ");
+            sb.append(callingUid);
+            if (mStoppedReason != null) {
+                sb.append(", last stopped ");
+                TimeUtils.formatDuration(SystemClock.elapsedRealtime() - mStoppedTime, sb);
+                sb.append(" because: ");
+                sb.append(mStoppedReason);
+            }
+            throw new SecurityException(sb.toString());
+        }
+    }
+
     /**
      * Scheduling of async messages (basically timeouts at this point).
      */
@@ -401,7 +421,7 @@
         handleServiceBoundLocked();
     }
 
-    void doCallback(boolean reschedule) {
+    void doCallback(boolean reschedule, String reason) {
         final int callingUid = Binder.getCallingUid();
         final long ident = Binder.clearCallingIdentity();
         try {
@@ -409,14 +429,14 @@
                 if (!verifyCallingUidLocked(callingUid)) {
                     return;
                 }
-                doCallbackLocked(reschedule);
+                doCallbackLocked(reschedule, reason);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
     }
 
-    void doCallbackLocked(boolean reschedule) {
+    void doCallbackLocked(boolean reschedule, String reason) {
         if (DEBUG) {
             Slog.d(TAG, "doCallback of : " + mRunningJob
                     + " v:" + VERB_STRINGS[mVerb]);
@@ -427,7 +447,7 @@
             handleStartedLocked(reschedule);
         } else if (mVerb == VERB_EXECUTING ||
                 mVerb == VERB_STOPPING) {
-            handleFinishedLocked(reschedule);
+            handleFinishedLocked(reschedule, reason);
         } else {
             if (DEBUG) {
                 Slog.d(TAG, "Unrecognised callback: " + mRunningJob);
@@ -435,7 +455,7 @@
         }
     }
 
-    void doCancelLocked(int arg1) {
+    void doCancelLocked(int arg1, String debugReason) {
         if (mVerb == VERB_FINISHED) {
             if (DEBUG) {
                 Slog.d(TAG,
@@ -448,7 +468,7 @@
             mPreferredUid = mRunningJob != null ? mRunningJob.getUid() :
                     NO_PREFERRED_UID;
         }
-        handleCancelLocked();
+        handleCancelLocked(debugReason);
     }
 
     /** Start the job on the service. */
@@ -459,7 +479,7 @@
         if (mVerb != VERB_BINDING) {
             Slog.e(TAG, "Sending onStartJob for a job that isn't pending. "
                     + VERB_STRINGS[mVerb]);
-            closeAndCleanupJobLocked(false /* reschedule */);
+            closeAndCleanupJobLocked(false /* reschedule */, "started job not pending");
             return;
         }
         if (mCancelled) {
@@ -467,7 +487,7 @@
                 Slog.d(TAG, "Job cancelled while waiting for bind to complete. "
                         + mRunningJob);
             }
-            closeAndCleanupJobLocked(true /* reschedule */);
+            closeAndCleanupJobLocked(true /* reschedule */, "cancelled while waiting for bind");
             return;
         }
         try {
@@ -496,7 +516,7 @@
                 mVerb = VERB_EXECUTING;
                 if (!workOngoing) {
                     // Job is finished already so fast-forward to handleFinished.
-                    handleFinishedLocked(false);
+                    handleFinishedLocked(false, "onStartJob returned false");
                     return;
                 }
                 if (mCancelled) {
@@ -504,7 +524,7 @@
                         Slog.d(TAG, "Job cancelled while waiting for onStartJob to complete.");
                     }
                     // Cancelled *while* waiting for acknowledgeStartMessage from client.
-                    handleCancelLocked();
+                    handleCancelLocked(null);
                     return;
                 }
                 scheduleOpTimeOutLocked();
@@ -522,11 +542,11 @@
      *     _STARTING   -> Error
      *     _PENDING    -> Error
      */
-    private void handleFinishedLocked(boolean reschedule) {
+    private void handleFinishedLocked(boolean reschedule, String reason) {
         switch (mVerb) {
             case VERB_EXECUTING:
             case VERB_STOPPING:
-                closeAndCleanupJobLocked(reschedule);
+                closeAndCleanupJobLocked(reschedule, reason);
                 break;
             default:
                 Slog.e(TAG, "Got an execution complete message for a job that wasn't being" +
@@ -544,7 +564,7 @@
      *                      in the message queue.
      *     _ENDING     -> No point in doing anything here, so we ignore.
      */
-    private void handleCancelLocked() {
+    private void handleCancelLocked(String reason) {
         if (JobSchedulerService.DEBUG) {
             Slog.d(TAG, "Handling cancel for: " + mRunningJob.getJobId() + " "
                     + VERB_STRINGS[mVerb]);
@@ -553,9 +573,10 @@
             case VERB_BINDING:
             case VERB_STARTING:
                 mCancelled = true;
+                applyStoppedReasonLocked(reason);
                 break;
             case VERB_EXECUTING:
-                sendStopMessageLocked();
+                sendStopMessageLocked(reason);
                 break;
             case VERB_STOPPING:
                 // Nada.
@@ -572,7 +593,7 @@
             case VERB_BINDING:
                 Slog.e(TAG, "Time-out while trying to bind " + mRunningJob.toShortString() +
                         ", dropping.");
-                closeAndCleanupJobLocked(false /* needsReschedule */);
+                closeAndCleanupJobLocked(false /* needsReschedule */, "timed out while binding");
                 break;
             case VERB_STARTING:
                 // Client unresponsive - wedged or failed to respond in time. We don't really
@@ -580,25 +601,25 @@
                 // FINISHED/NO-RETRY.
                 Slog.e(TAG, "No response from client for onStartJob '" +
                         mRunningJob.toShortString());
-                closeAndCleanupJobLocked(false /* needsReschedule */);
+                closeAndCleanupJobLocked(false /* needsReschedule */, "timed out while starting");
                 break;
             case VERB_STOPPING:
                 // At least we got somewhere, so fail but ask the JobScheduler to reschedule.
                 Slog.e(TAG, "No response from client for onStopJob, '" +
                         mRunningJob.toShortString());
-                closeAndCleanupJobLocked(true /* needsReschedule */);
+                closeAndCleanupJobLocked(true /* needsReschedule */, "timed out while stopping");
                 break;
             case VERB_EXECUTING:
                 // Not an error - client ran out of time.
                 Slog.i(TAG, "Client timed out while executing (no jobFinished received)." +
                         " sending onStop. "  + mRunningJob.toShortString());
                 mParams.setStopReason(JobParameters.REASON_TIMEOUT);
-                sendStopMessageLocked();
+                sendStopMessageLocked("timeout while executing");
                 break;
             default:
                 Slog.e(TAG, "Handling timeout for an invalid job state: " +
                         mRunningJob.toShortString() + ", dropping.");
-                closeAndCleanupJobLocked(false /* needsReschedule */);
+                closeAndCleanupJobLocked(false /* needsReschedule */, "invalid timeout");
         }
     }
 
@@ -606,11 +627,11 @@
      * Already running, need to stop. Will switch {@link #mVerb} from VERB_EXECUTING ->
      * VERB_STOPPING.
      */
-    private void sendStopMessageLocked() {
+    private void sendStopMessageLocked(String reason) {
         removeOpTimeOutLocked();
         if (mVerb != VERB_EXECUTING) {
             Slog.e(TAG, "Sending onStopJob for a job that isn't started. " + mRunningJob);
-            closeAndCleanupJobLocked(false /* reschedule */);
+            closeAndCleanupJobLocked(false /* reschedule */, reason);
             return;
         }
         try {
@@ -620,7 +641,7 @@
         } catch (RemoteException e) {
             Slog.e(TAG, "Error sending onStopJob to client.", e);
             // The job's host app apparently crashed during the job, so we should reschedule.
-            closeAndCleanupJobLocked(true /* reschedule */);
+            closeAndCleanupJobLocked(true /* reschedule */, "host crashed when trying to stop");
         }
     }
 
@@ -630,11 +651,12 @@
      * or from acknowledging the stop message we sent. Either way, we're done tracking it and
      * we want to clean up internally.
      */
-    private void closeAndCleanupJobLocked(boolean reschedule) {
+    private void closeAndCleanupJobLocked(boolean reschedule, String reason) {
         final JobStatus completedJob;
         if (mVerb == VERB_FINISHED) {
             return;
         }
+        applyStoppedReasonLocked(reason);
         completedJob = mRunningJob;
         mJobPackageTracker.noteInactive(completedJob);
         try {
@@ -658,6 +680,13 @@
         mCompletedListener.onJobCompletedLocked(completedJob, reschedule);
     }
 
+    private void applyStoppedReasonLocked(String reason) {
+        if (reason != null && mStoppedReason == null) {
+            mStoppedReason = reason;
+            mStoppedTime = SystemClock.elapsedRealtime();
+        }
+    }
+
     /**
      * Called when sending a message to the client, over whose execution we have no control. If
      * we haven't received a response in a certain amount of time, we want to give up and carry
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index c2c9123..01eabd8 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3072,13 +3072,18 @@
         if (PRINT_ANIM) Log.i(TAG, "selectAnimation in " + win
               + ": transit=" + transit);
         if (win == mStatusBar) {
-            boolean isKeyguard = (win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
+            final boolean isKeyguard = (win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
+            final boolean expanded = win.getAttrs().height == MATCH_PARENT
+                    && win.getAttrs().width == MATCH_PARENT;
+            if (isKeyguard || expanded) {
+                return -1;
+            }
             if (transit == TRANSIT_EXIT
                     || transit == TRANSIT_HIDE) {
-                return isKeyguard ? -1 : R.anim.dock_top_exit;
+                return R.anim.dock_top_exit;
             } else if (transit == TRANSIT_ENTER
                     || transit == TRANSIT_SHOW) {
-                return isKeyguard ? -1 : R.anim.dock_top_enter;
+                return R.anim.dock_top_enter;
             }
         } else if (win == mNavigationBar) {
             if (win.getAttrs().windowAnimations != 0) {
@@ -6803,7 +6808,9 @@
 
     @Override
     public boolean isScreenOn() {
-        return mScreenOnFully;
+        synchronized (mLock) {
+            return mScreenOnEarly;
+        }
     }
 
     /** {@inheritDoc} */
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index 1aa952cd..520b0e8 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -191,7 +191,7 @@
             // Process existing model first.
             if (model != null && !model.getModelId().equals(soundModel.uuid)) {
                 // The existing model has a different UUID, should be replaced.
-                int status = cleanUpExistingKeyphraseModel(model);
+                int status = cleanUpExistingKeyphraseModelLocked(model);
                 if (status != STATUS_OK) {
                     return status;
                 }
@@ -210,7 +210,7 @@
         }
     }
 
-    private int cleanUpExistingKeyphraseModel(ModelData modelData) {
+    private int cleanUpExistingKeyphraseModelLocked(ModelData modelData) {
         // Stop and clean up a previous ModelData if one exists. This usually is used when the
         // previous model has a different UUID for the same keyphrase ID.
         int status = tryStopAndUnloadLocked(modelData, true /* stop */, true /* unload */);
@@ -616,7 +616,7 @@
         try {
             callback.onGenericSoundTriggerDetected((GenericRecognitionEvent) event);
         } catch (DeadObjectException e) {
-            forceStopAndUnloadModel(model, e);
+            forceStopAndUnloadModelLocked(model, e);
             return;
         } catch (RemoteException e) {
             Slog.w(TAG, "RemoteException in onGenericSoundTriggerDetected", e);
@@ -706,7 +706,7 @@
             try {
                 modelData.getCallback().onRecognitionPaused();
             } catch (DeadObjectException e) {
-                forceStopAndUnloadModel(modelData, e);
+                forceStopAndUnloadModelLocked(modelData, e);
             } catch (RemoteException e) {
                 Slog.w(TAG, "RemoteException in onRecognitionPaused", e);
             }
@@ -717,7 +717,7 @@
         Slog.w(TAG, "Recognition failure");
         MetricsLogger.count(mContext, "sth_recognition_failure_event", 1);
         try {
-            sendErrorCallbacksToAll(STATUS_ERROR);
+            sendErrorCallbacksToAllLocked(STATUS_ERROR);
         } finally {
             internalClearModelStateLocked();
             internalClearGlobalStateLocked();
@@ -759,7 +759,7 @@
         try {
             modelData.getCallback().onKeyphraseDetected((KeyphraseRecognitionEvent) event);
         } catch (DeadObjectException e) {
-            forceStopAndUnloadModel(modelData, e);
+            forceStopAndUnloadModelLocked(modelData, e);
             return;
         } catch (RemoteException e) {
             Slog.w(TAG, "RemoteException in onKeyphraseDetected", e);
@@ -778,7 +778,9 @@
 
     private void updateAllRecognitionsLocked(boolean notify) {
         boolean isAllowed = isRecognitionAllowed();
-        for (ModelData modelData : mModelDataMap.values()) {
+        // updateRecognitionLocked can possibly update the list of models
+        ArrayList<ModelData> modelDatas = new ArrayList<ModelData>(mModelDataMap.values());
+        for (ModelData modelData : modelDatas) {
             updateRecognitionLocked(modelData, isAllowed, notify);
         }
     }
@@ -800,7 +802,7 @@
     private void onServiceDiedLocked() {
         try {
             MetricsLogger.count(mContext, "sth_service_died", 1);
-            sendErrorCallbacksToAll(SoundTrigger.STATUS_DEAD_OBJECT);
+            sendErrorCallbacksToAllLocked(SoundTrigger.STATUS_DEAD_OBJECT);
         } finally {
             internalClearModelStateLocked();
             internalClearGlobalStateLocked();
@@ -885,21 +887,21 @@
     }
 
     // Sends an error callback to all models with a valid registered callback.
-    private void sendErrorCallbacksToAll(int errorCode) {
+    private void sendErrorCallbacksToAllLocked(int errorCode) {
         for (ModelData modelData : mModelDataMap.values()) {
             IRecognitionStatusCallback callback = modelData.getCallback();
             if (callback != null) {
                 try {
                     callback.onError(errorCode);
                 } catch (RemoteException e) {
-                    Slog.w(TAG, "RemoteException sendErrorCallbacksToAll for model handle " +
+                    Slog.w(TAG, "RemoteException sendErrorCallbacksToAllLocked for model handle " +
                             modelData.getHandle(), e);
                 }
             }
         }
     }
 
-    private void forceStopAndUnloadModel(ModelData modelData, Exception exception) {
+    private void forceStopAndUnloadModelLocked(ModelData modelData, Exception exception) {
         if (exception != null) {
           Slog.e(TAG, "forceStopAndUnloadModel", exception);
         }
@@ -1020,7 +1022,7 @@
                 try {
                     callback.onError(status);
                 } catch (DeadObjectException e) {
-                    forceStopAndUnloadModel(modelData, e);
+                    forceStopAndUnloadModelLocked(modelData, e);
                 } catch (RemoteException e) {
                     Slog.w(TAG, "RemoteException in onError", e);
                 }
@@ -1034,7 +1036,7 @@
                 try {
                     callback.onRecognitionResumed();
                 } catch (DeadObjectException e) {
-                    forceStopAndUnloadModel(modelData, e);
+                    forceStopAndUnloadModelLocked(modelData, e);
                 } catch (RemoteException e) {
                     Slog.w(TAG, "RemoteException in onRecognitionResumed", e);
                 }
@@ -1061,7 +1063,7 @@
                 try {
                     callback.onError(status);
                 } catch (DeadObjectException e) {
-                    forceStopAndUnloadModel(modelData, e);
+                    forceStopAndUnloadModelLocked(modelData, e);
                 } catch (RemoteException e) {
                     Slog.w(TAG, "RemoteException in onError", e);
                 }
@@ -1074,7 +1076,7 @@
                 try {
                     callback.onRecognitionPaused();
                 } catch (DeadObjectException e) {
-                    forceStopAndUnloadModel(modelData, e);
+                    forceStopAndUnloadModelLocked(modelData, e);
                 } catch (RemoteException e) {
                     Slog.w(TAG, "RemoteException in onRecognitionPaused", e);
                 }