Merge "Throw on revoked location permission - framework" into pi-dev
diff --git a/api/current.txt b/api/current.txt
index d721936..052b7f8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -9905,6 +9905,8 @@
     field public static final java.lang.String ACTION_MEDIA_UNMOUNTABLE = "android.intent.action.MEDIA_UNMOUNTABLE";
     field public static final java.lang.String ACTION_MEDIA_UNMOUNTED = "android.intent.action.MEDIA_UNMOUNTED";
     field public static final java.lang.String ACTION_MY_PACKAGE_REPLACED = "android.intent.action.MY_PACKAGE_REPLACED";
+    field public static final java.lang.String ACTION_MY_PACKAGE_SUSPENDED = "android.intent.action.MY_PACKAGE_SUSPENDED";
+    field public static final java.lang.String ACTION_MY_PACKAGE_UNSUSPENDED = "android.intent.action.MY_PACKAGE_UNSUSPENDED";
     field public static final java.lang.String ACTION_NEW_OUTGOING_CALL = "android.intent.action.NEW_OUTGOING_CALL";
     field public static final java.lang.String ACTION_OPEN_DOCUMENT = "android.intent.action.OPEN_DOCUMENT";
     field public static final java.lang.String ACTION_OPEN_DOCUMENT_TREE = "android.intent.action.OPEN_DOCUMENT_TREE";
@@ -10065,6 +10067,7 @@
     field public static final java.lang.String EXTRA_SPLIT_NAME = "android.intent.extra.SPLIT_NAME";
     field public static final java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM";
     field public static final java.lang.String EXTRA_SUBJECT = "android.intent.extra.SUBJECT";
+    field public static final java.lang.String EXTRA_SUSPENDED_PACKAGE_EXTRAS = "android.intent.extra.SUSPENDED_PACKAGE_EXTRAS";
     field public static final java.lang.String EXTRA_TEMPLATE = "android.intent.extra.TEMPLATE";
     field public static final java.lang.String EXTRA_TEXT = "android.intent.extra.TEXT";
     field public static final java.lang.String EXTRA_TITLE = "android.intent.extra.TITLE";
@@ -11178,7 +11181,7 @@
     method public abstract android.content.res.Resources getResourcesForApplication(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.pm.ServiceInfo getServiceInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibraries(int);
-    method public android.os.PersistableBundle getSuspendedPackageAppExtras();
+    method public android.os.Bundle getSuspendedPackageAppExtras();
     method public abstract android.content.pm.FeatureInfo[] getSystemAvailableFeatures();
     method public abstract java.lang.String[] getSystemSharedLibraryNames();
     method public abstract java.lang.CharSequence getText(java.lang.String, int, android.content.pm.ApplicationInfo);
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index f38c80c..a68136b 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -2167,15 +2167,16 @@
     @Override
     public PersistableBundle getSuspendedPackageAppExtras(String packageName) {
         try {
-            return mPM.getPackageSuspendedAppExtras(packageName, mContext.getUserId());
+            return mPM.getSuspendedPackageAppExtras(packageName, mContext.getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     @Override
-    public PersistableBundle getSuspendedPackageAppExtras() {
-        return getSuspendedPackageAppExtras(mContext.getOpPackageName());
+    public Bundle getSuspendedPackageAppExtras() {
+        final PersistableBundle extras = getSuspendedPackageAppExtras(mContext.getOpPackageName());
+        return extras != null ? new Bundle(extras.deepCopy()) : null;
     }
 
     @Override
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 99efecd..3bb87a3 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -322,12 +322,14 @@
     /**
      * Informs ActivityManagerService that the keyguard is showing.
      *
-     * @param showing True if the keyguard is showing, false otherwise.
+     * @param showingKeyguard True if the keyguard is showing, false otherwise.
+     * @param showingAod True if AOD is showing, false otherwise.
      * @param secondaryDisplayShowing The displayId of the secondary display on which the keyguard
      *        is showing, or INVALID_DISPLAY if there is no such display. Only meaningful if
      *        showing is true.
      */
-    void setLockScreenShown(boolean showing, int secondaryDisplayShowing);
+    void setLockScreenShown(boolean showingKeyguard, boolean showingAod,
+            int secondaryDisplayShowing);
     boolean finishActivityAffinity(in IBinder token);
     // This is not public because you need to be very careful in how you
     // manage your activity to make sure it is always the uid you expect.
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index a6e42cf..465340f 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -441,6 +441,9 @@
             synchronized (this) {
                 mCachedWallpaper = null;
                 mCachedWallpaperUserId = 0;
+                if (mDefaultWallpaper != null) {
+                    mDefaultWallpaper.recycle();
+                }
                 mDefaultWallpaper = null;
             }
         }
diff --git a/core/java/android/app/usage/TimeSparseArray.java b/core/java/android/app/usage/TimeSparseArray.java
index 5764fa8..9ef88e4 100644
--- a/core/java/android/app/usage/TimeSparseArray.java
+++ b/core/java/android/app/usage/TimeSparseArray.java
@@ -81,12 +81,17 @@
     @Override
     public void put(long key, E value) {
         final long origKey = key;
-        while (indexOfKey(key) >= 0) {
-            key++;
-        }
-        if (origKey != key) {
-            Slog.w(TAG, "Value " + value + " supposed to be inserted at " + origKey
-                    + " displaced to " + key);
+        int keyIndex = indexOfKey(key);
+        if (keyIndex >= 0) {
+            final long sz = size();
+            while (keyIndex < sz && keyAt(keyIndex) == key) {
+                key++;
+                keyIndex++;
+            }
+            if (key >= origKey + 10) {
+                Slog.w(TAG, "Value " + value + " supposed to be inserted at " + origKey
+                        + " displaced to " + key);
+            }
         }
         super.put(key, value);
     }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index ce32278..02f0ded 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1814,6 +1814,17 @@
     public static final String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
 
     /**
+     * Intent extra: A {@link Bundle} of extras for a package being suspended. Will be sent with
+     * {@link #ACTION_MY_PACKAGE_SUSPENDED}.
+     *
+     * @see #ACTION_MY_PACKAGE_SUSPENDED
+     * @see #ACTION_MY_PACKAGE_UNSUSPENDED
+     * @see PackageManager#isPackageSuspended()
+     * @see PackageManager#getSuspendedPackageAppExtras()
+     */
+    public static final String EXTRA_SUSPENDED_PACKAGE_EXTRAS = "android.intent.extra.SUSPENDED_PACKAGE_EXTRAS";
+
+    /**
      * Intent extra: An app split name.
      * <p>
      * Type: String
@@ -2237,6 +2248,43 @@
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_PACKAGES_UNSUSPENDED = "android.intent.action.PACKAGES_UNSUSPENDED";
+
+    /**
+     * Broadcast Action: Sent to a package that has been suspended by the system. This is sent
+     * whenever a package is put into a suspended state or any of it's app extras change while
+     * in the suspended state.
+     * <p> Optionally includes the following extras:
+     * <ul>
+     *     <li> {@link #EXTRA_SUSPENDED_PACKAGE_EXTRAS} which is a {@link Bundle} which will contain
+     *     useful information for the app being suspended.
+     * </ul>
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system. <em>This will be delivered to {@link BroadcastReceiver} components declared in
+     * the manifest.</em>
+     *
+     * @see #ACTION_MY_PACKAGE_UNSUSPENDED
+     * @see #EXTRA_SUSPENDED_PACKAGE_EXTRAS
+     * @see PackageManager#isPackageSuspended()
+     * @see PackageManager#getSuspendedPackageAppExtras()
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_MY_PACKAGE_SUSPENDED = "android.intent.action.MY_PACKAGE_SUSPENDED";
+
+    /**
+     * Broadcast Action: Sent to a package that has been unsuspended.
+     *
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system. <em>This will be delivered to {@link BroadcastReceiver} components declared in
+     * the manifest.</em>
+     *
+     * @see #ACTION_MY_PACKAGE_SUSPENDED
+     * @see #EXTRA_SUSPENDED_PACKAGE_EXTRAS
+     * @see PackageManager#isPackageSuspended()
+     * @see PackageManager#getSuspendedPackageAppExtras()
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_MY_PACKAGE_UNSUSPENDED = "android.intent.action.MY_PACKAGE_UNSUSPENDED";
+
     /**
      * Broadcast Action: A user ID has been removed from the system.  The user
      * ID number is stored in the extra data under {@link #EXTRA_UID}.
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index d43d80f..1352b5e 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -278,7 +278,7 @@
 
     boolean isPackageSuspendedForUser(String packageName, int userId);
 
-    PersistableBundle getPackageSuspendedAppExtras(String pacakgeName, int userId);
+    PersistableBundle getSuspendedPackageAppExtras(String packageName, int userId);
 
     void setSuspendedPackageAppExtras(String packageName, in PersistableBundle appExtras,
             int userId);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 314eb98..491f0af 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -5513,7 +5513,7 @@
      * Puts the package in a suspended state, where attempts at starting activities are denied.
      *
      * <p>It doesn't remove the data or the actual package file. The application's notifications
-     * will be hidden, any of the it's started activities will be stopped and it will not be able to
+     * will be hidden, any of its started activities will be stopped and it will not be able to
      * show toasts or dialogs or ring the device. When the user tries to launch a suspended app, a
      * system dialog with the given {@code dialogMessage} will be shown instead.</p>
      *
@@ -5577,11 +5577,26 @@
     }
 
     /**
-     * Apps can query this to know if they have been suspended.
+     * Apps can query this to know if they have been suspended. A system app with the permission
+     * {@code android.permission.SUSPEND_APPS} can put any app on the device into a suspended state.
+     *
+     * <p>While in this state, the application's notifications will be hidden, any of its started
+     * activities will be stopped and it will not be able to show toasts or dialogs or ring the
+     * device. When the user tries to launch a suspended app, the system will, instead, show a
+     * dialog to the user informing them that they cannot use this app while it is suspended.
+     *
+     * <p>When an app is put into this state, the broadcast action
+     * {@link Intent#ACTION_MY_PACKAGE_SUSPENDED} will be delivered to any of its broadcast
+     * receivers that included this action in their intent-filters, <em>including manifest
+     * receivers.</em> Similarly, a broadcast action {@link Intent#ACTION_MY_PACKAGE_UNSUSPENDED}
+     * is delivered when a previously suspended app is taken out of this state.
+     * </p>
      *
      * @return {@code true} if the calling package has been suspended, {@code false} otherwise.
      *
      * @see #getSuspendedPackageAppExtras()
+     * @see Intent#ACTION_MY_PACKAGE_SUSPENDED
+     * @see Intent#ACTION_MY_PACKAGE_UNSUSPENDED
      */
     public boolean isPackageSuspended() {
         throw new UnsupportedOperationException("isPackageSuspended not implemented");
@@ -5602,7 +5617,7 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.SUSPEND_APPS)
-    public PersistableBundle getSuspendedPackageAppExtras(String packageName) {
+    public @Nullable PersistableBundle getSuspendedPackageAppExtras(String packageName) {
         throw new UnsupportedOperationException("getSuspendedPackageAppExtras not implemented");
     }
 
@@ -5631,15 +5646,17 @@
      * Returns any extra information supplied as {@code appExtras} to the system when the calling
      * app was suspended.
      *
-     * <p> Note: This just returns whatever {@link PersistableBundle} was passed to the system via
-     * {@code setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle,
-     * String)} when suspending the package, <em> which might be {@code null}. </em></p>
+     * <p>Note: If no extras were supplied to the system, this method will return {@code null}, even
+     * when the calling app has been suspended.</p>
      *
-     * @return A {@link PersistableBundle} containing the extras for the app, or {@code null} if the
+     * @return A {@link Bundle} containing the extras for the app, or {@code null} if the
      * package is not currently suspended.
+     *
      * @see #isPackageSuspended()
+     * @see Intent#ACTION_MY_PACKAGE_UNSUSPENDED
+     * @see Intent#ACTION_MY_PACKAGE_SUSPENDED
      */
-    public @Nullable PersistableBundle getSuspendedPackageAppExtras() {
+    public @Nullable Bundle getSuspendedPackageAppExtras() {
         throw new UnsupportedOperationException("getSuspendedPackageAppExtras not implemented");
     }
 
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index d3b1e5c..df81a31 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -250,6 +250,18 @@
     }
 
     /**
+     * Destroys the HwuiContext without completely
+     * releasing the Surface.
+     * @hide
+     */
+    public void hwuiDestroy() {
+        if (mHwuiContext != null) {
+            mHwuiContext.destroy();
+            mHwuiContext = null;
+        }
+    }
+
+    /**
      * Returns true if this object holds a valid surface.
      *
      * @return True if it holds a physical surface, so lockCanvas() will succeed.
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 7b1acb1..39755aa 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -12474,9 +12474,8 @@
                         + " before=" + before + " after=" + after + ": " + buffer);
             }
 
-            if (AccessibilityManager.getInstance(mContext).isEnabled()
-                    && !isPasswordInputType(getInputType()) && !hasPasswordTransformationMethod()) {
-                mBeforeText = buffer.toString();
+            if (AccessibilityManager.getInstance(mContext).isEnabled() && (mTransformed != null)) {
+                mBeforeText = mTransformed.toString();
             }
 
             TextView.this.sendBeforeTextChanged(buffer, start, before, after);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 3fb52dc..1c3448b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -89,6 +89,8 @@
     <protected-broadcast android:name="android.intent.action.OVERLAY_REMOVED" />
     <protected-broadcast android:name="android.intent.action.OVERLAY_PRIORITY_CHANGED" />
     <protected-broadcast android:name="android.intent.action.USER_ACTIVITY_NOTIFICATION" />
+    <protected-broadcast android:name="android.intent.action.MY_PACKAGE_SUSPENDED" />
+    <protected-broadcast android:name="android.intent.action.MY_PACKAGE_UNSUSPENDED" />
 
     <protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGED" />
     <protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGING" />
diff --git a/libs/hwui/PathParser.cpp b/libs/hwui/PathParser.cpp
index a48fdfc..47fcca9 100644
--- a/libs/hwui/PathParser.cpp
+++ b/libs/hwui/PathParser.cpp
@@ -156,10 +156,63 @@
     return;
 }
 
-bool PathParser::isVerbValid(char verb) {
-    verb = tolower(verb);
-    return verb == 'a' || verb == 'c' || verb == 'h' || verb == 'l' || verb == 'm' || verb == 'q' ||
-           verb == 's' || verb == 't' || verb == 'v' || verb == 'z';
+void PathParser::validateVerbAndPoints(char verb, size_t points, PathParser::ParseResult* result) {
+    size_t numberOfPointsExpected = -1;
+    switch (verb) {
+        case 'z':
+        case 'Z':
+            numberOfPointsExpected = 0;
+            break;
+        case 'm':
+        case 'l':
+        case 't':
+        case 'M':
+        case 'L':
+        case 'T':
+            numberOfPointsExpected = 2;
+            break;
+        case 'h':
+        case 'v':
+        case 'H':
+        case 'V':
+            numberOfPointsExpected = 1;
+            break;
+        case 'c':
+        case 'C':
+            numberOfPointsExpected = 6;
+            break;
+        case 's':
+        case 'q':
+        case 'S':
+        case 'Q':
+            numberOfPointsExpected = 4;
+            break;
+        case 'a':
+        case 'A':
+            numberOfPointsExpected = 7;
+            break;
+        default:
+            result->failureOccurred = true;
+            result->failureMessage += verb;
+            result->failureMessage += " is not a valid verb. ";
+            return;
+    }
+    if (numberOfPointsExpected == 0 && points == 0) {
+        return;
+    }
+    if (numberOfPointsExpected > 0 && points % numberOfPointsExpected == 0) {
+        return;
+    }
+
+    result->failureOccurred = true;
+    result->failureMessage += verb;
+    result->failureMessage += " needs to be followed by ";
+    if (numberOfPointsExpected > 0) {
+        result->failureMessage += "a multiple of ";
+    }
+    result->failureMessage += std::to_string(numberOfPointsExpected)
+            + " floats. However, " + std::to_string(points)
+            + " float(s) are found. ";
 }
 
 void PathParser::getPathDataFromAsciiString(PathData* data, ParseResult* result,
@@ -186,13 +239,11 @@
         end = nextStart(pathStr, strLen, end);
         std::vector<float> points;
         getFloats(&points, result, pathStr, start, end);
-        if (!isVerbValid(pathStr[start])) {
-            result->failureOccurred = true;
-            result->failureMessage = "Invalid pathData. Failure occurred at position " +
-                                     std::to_string(start) + " of path: " + pathStr;
-        }
-        // If either verb or points is not valid, return immediately.
+        validateVerbAndPoints(pathStr[start], points.size(), result);
         if (result->failureOccurred) {
+            // If either verb or points is not valid, return immediately.
+            result->failureMessage += "Failure occurred at position " +
+                                     std::to_string(start) + " of path: " + pathStr;
             return;
         }
         data->verbs.push_back(pathStr[start]);
@@ -203,9 +254,10 @@
     }
 
     if ((end - start) == 1 && start < strLen) {
-        if (!isVerbValid(pathStr[start])) {
-            result->failureOccurred = true;
-            result->failureMessage = "Invalid pathData. Failure occurred at position " +
+        validateVerbAndPoints(pathStr[start], 0, result);
+        if (result->failureOccurred) {
+            // If either verb or points is not valid, return immediately.
+            result->failureMessage += "Failure occurred at position " +
                                      std::to_string(start) + " of path: " + pathStr;
             return;
         }
diff --git a/libs/hwui/PathParser.h b/libs/hwui/PathParser.h
index e4ec7be..474eb97 100644
--- a/libs/hwui/PathParser.h
+++ b/libs/hwui/PathParser.h
@@ -43,7 +43,7 @@
     ANDROID_API static void getPathDataFromAsciiString(PathData* outData, ParseResult* result,
                                                        const char* pathStr, size_t strLength);
     static void dump(const PathData& data);
-    static bool isVerbValid(char verb);
+    static void validateVerbAndPoints(char verb, size_t points, ParseResult* result);
 };
 
 };      // namespace uirenderer
diff --git a/libs/hwui/tests/unit/VectorDrawableTests.cpp b/libs/hwui/tests/unit/VectorDrawableTests.cpp
index e7496f7..02f740c 100644
--- a/libs/hwui/tests/unit/VectorDrawableTests.cpp
+++ b/libs/hwui/tests/unit/VectorDrawableTests.cpp
@@ -242,7 +242,8 @@
         {"\n \t   z", true},   // Valid path data with leading spaces
         {"1-2e34567", false},  // Not starting with a verb and ill-formatted float
         {"f 4 5", false},      // Invalid verb
-        {"\r      ", false}    // Empty string
+        {"\r      ", false},   // Empty string
+        {"L1,0 L1,1 L0,1 z M1000", false}    // Not enough floats following verb M.
 };
 
 static bool hasSameVerbs(const PathData& from, const PathData& to) {
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index a59c97e..a4f8d8c 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -24,11 +24,13 @@
 import android.graphics.RectF;
 import android.graphics.Region.Op;
 import android.os.AsyncTask;
+import android.os.Handler;
 import android.os.Trace;
 import android.service.wallpaper.WallpaperService;
 import android.util.Log;
 import android.view.Display;
 import android.view.DisplayInfo;
+import android.view.Surface;
 import android.view.SurfaceHolder;
 import android.view.WindowManager;
 
@@ -45,6 +47,7 @@
     private static final String GL_LOG_TAG = "ImageWallpaperGL";
     private static final boolean DEBUG = false;
     private static final String PROPERTY_KERNEL_QEMU = "ro.kernel.qemu";
+    private static final long DELAY_FORGET_WALLPAPER = 5000;
 
     private WallpaperManager mWallpaperManager;
     private DrawableEngine mEngine;
@@ -69,6 +72,10 @@
     }
 
     class DrawableEngine extends Engine {
+        private final Runnable mUnloadWallpaperCallback = () -> {
+            unloadWallpaper(false /* forgetSize */);
+        };
+
         Bitmap mBackground;
         int mBackgroundWidth = -1, mBackgroundHeight = -1;
         int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
@@ -331,6 +338,7 @@
                 }
 
                 drawWallpaperWithCanvas(sh, availw, availh, xPixels, yPixels);
+                scheduleUnloadWallpaper();
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
             }
@@ -433,6 +441,9 @@
                 mBackgroundHeight = -1;
             }
 
+            final Surface surface = getSurfaceHolder().getSurface();
+            surface.hwuiDestroy();
+
             mLoader = new AsyncTask<Void, Void, Bitmap>() {
                 @Override
                 protected Bitmap doInBackground(Void... params) {
@@ -442,6 +453,12 @@
             }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
         }
 
+        private void scheduleUnloadWallpaper() {
+            Handler handler = getMainThreadHandler();
+            handler.removeCallbacks(mUnloadWallpaperCallback);
+            handler.postDelayed(mUnloadWallpaperCallback, DELAY_FORGET_WALLPAPER);
+        }
+
         @Override
         protected void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args) {
             super.dump(prefix, fd, out, args);
diff --git a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java
index 4b15fbc..f2eea26 100644
--- a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java
@@ -147,6 +147,9 @@
 
     private void handleFingerprintAuthenticated() {
         if (DEBUG) Log.d(TAG, "handleFingerprintAuthenticated");
+        mDialogView.announceForAccessibility(
+                mContext.getResources().getText(
+                        com.android.internal.R.string.fingerprint_authenticated));
         handleHideDialog(false /* userCanceled */);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index a1b17e4..d6e59c7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -27,7 +27,6 @@
 
 import android.app.ActivityManager;
 import android.app.AlarmManager;
-import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.StatusBarManager;
 import android.app.trust.TrustManager;
@@ -235,6 +234,9 @@
     // answer whether the input should be restricted)
     private boolean mShowing;
 
+    // AOD is enabled and status bar is in AOD state.
+    private boolean mAodShowing;
+
     // display id of the secondary display on which we have put a keyguard window
     private int mSecondaryDisplayShowing = INVALID_DISPLAY;
 
@@ -664,7 +666,7 @@
         @Override
         public void onSecondaryDisplayShowingChanged(int displayId) {
             synchronized (KeyguardViewMediator.this) {
-                setShowingLocked(mShowing, displayId, false);
+                setShowingLocked(mShowing, mAodShowing, displayId, false);
             }
         }
     };
@@ -707,10 +709,10 @@
             setShowingLocked(!shouldWaitForProvisioning()
                     && !mLockPatternUtils.isLockScreenDisabled(
                             KeyguardUpdateMonitor.getCurrentUser()),
-                    mSecondaryDisplayShowing, true /* forceCallbacks */);
+                    mAodShowing, mSecondaryDisplayShowing, true /* forceCallbacks */);
         } else {
             // The system's keyguard is disabled or missing.
-            setShowingLocked(false, mSecondaryDisplayShowing, true);
+            setShowingLocked(false, mAodShowing, mSecondaryDisplayShowing, true);
         }
 
         mStatusBarKeyguardViewManager =
@@ -1311,7 +1313,7 @@
             if (mLockPatternUtils.checkVoldPassword(KeyguardUpdateMonitor.getCurrentUser())) {
                 if (DEBUG) Log.d(TAG, "Not showing lock screen since just decrypted");
                 // Without this, settings is not enabled until the lock screen first appears
-                setShowingLocked(false);
+                setShowingLocked(false, mAodShowing);
                 hideLocked();
                 return;
             }
@@ -1713,10 +1715,12 @@
         playSound(mTrustedSoundId);
     }
 
-    private void updateActivityLockScreenState(boolean showing, int secondaryDisplayShowing) {
+    private void updateActivityLockScreenState(boolean showing, boolean aodShowing,
+            int secondaryDisplayShowing) {
         mUiOffloadThread.submit(() -> {
             try {
-                ActivityManager.getService().setLockScreenShown(showing, secondaryDisplayShowing);
+                ActivityManager.getService().setLockScreenShown(showing, aodShowing,
+                        secondaryDisplayShowing);
             } catch (RemoteException e) {
             }
         });
@@ -1740,7 +1744,7 @@
                 if (DEBUG) Log.d(TAG, "handleShow");
             }
 
-            setShowingLocked(true);
+            setShowingLocked(true, mAodShowing);
             mStatusBarKeyguardViewManager.show(options);
             mHiding = false;
             mWakeAndUnlocking = false;
@@ -1849,7 +1853,7 @@
             }
 
             mWakeAndUnlocking = false;
-            setShowingLocked(false);
+            setShowingLocked(false, mAodShowing);
             mDismissCallbackRegistry.notifyDismissSucceeded();
             mStatusBarKeyguardViewManager.hide(startTime, fadeoutDuration);
             resetKeyguardDonePendingLocked();
@@ -1909,7 +1913,7 @@
         Trace.beginSection("KeyguardViewMediator#handleVerifyUnlock");
         synchronized (KeyguardViewMediator.this) {
             if (DEBUG) Log.d(TAG, "handleVerifyUnlock");
-            setShowingLocked(true);
+            setShowingLocked(true, mAodShowing);
             mStatusBarKeyguardViewManager.dismissAndCollapse();
         }
         Trace.endSection();
@@ -2064,6 +2068,10 @@
         pw.print("  mDrawnCallback: "); pw.println(mDrawnCallback);
     }
 
+    public void setAodShowing(boolean aodShowing) {
+        setShowingLocked(mShowing, aodShowing);
+    }
+
     private static class StartKeyguardExitAnimParams {
 
         long startTime;
@@ -2075,20 +2083,23 @@
         }
     }
 
-    private void setShowingLocked(boolean showing) {
-        setShowingLocked(showing, mSecondaryDisplayShowing, false /* forceCallbacks */);
+    private void setShowingLocked(boolean showing, boolean aodShowing) {
+        setShowingLocked(showing, aodShowing, mSecondaryDisplayShowing,
+                false /* forceCallbacks */);
     }
 
-    private void setShowingLocked(
-            boolean showing, int secondaryDisplayShowing, boolean forceCallbacks) {
-        final boolean notifyDefaultDisplayCallbacks = showing != mShowing || forceCallbacks;
+    private void setShowingLocked(boolean showing, boolean aodShowing, int secondaryDisplayShowing,
+            boolean forceCallbacks) {
+        final boolean notifyDefaultDisplayCallbacks = showing != mShowing
+                || aodShowing != mAodShowing || forceCallbacks;
         if (notifyDefaultDisplayCallbacks || secondaryDisplayShowing != mSecondaryDisplayShowing) {
             mShowing = showing;
+            mAodShowing = aodShowing;
             mSecondaryDisplayShowing = secondaryDisplayShowing;
             if (notifyDefaultDisplayCallbacks) {
                 notifyDefaultDisplayCallbacks(showing);
             }
-            updateActivityLockScreenState(showing, secondaryDisplayShowing);
+            updateActivityLockScreenState(showing, aodShowing, secondaryDisplayShowing);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index ddb67df..b8325fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -408,6 +408,7 @@
     protected NotificationEntryManager mEntryManager;
     protected NotificationViewHierarchyManager mViewHierarchyManager;
     protected AppOpsListener mAppOpsListener;
+    protected KeyguardViewMediator mKeyguardViewMediator;
     private ZenModeController mZenController;
 
     /**
@@ -632,6 +633,7 @@
         mAppOpsListener = Dependency.get(AppOpsListener.class);
         mAppOpsListener.setUpWithPresenter(this, mEntryManager);
         mZenController = Dependency.get(ZenModeController.class);
+        mKeyguardViewMediator = getComponent(KeyguardViewMediator.class);
 
         mColorExtractor = Dependency.get(SysuiColorExtractor.class);
         mColorExtractor.addOnColorsChangedListener(this);
@@ -4628,6 +4630,7 @@
         boolean dozing = mDozingRequested && mState == StatusBarState.KEYGUARD
                 || mFingerprintUnlockController.getMode()
                         == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
+        final boolean alwaysOn = DozeParameters.getInstance(mContext).getAlwaysOn();
         // When in wake-and-unlock we may not have received a change to mState
         // but we still should not be dozing, manually set to false.
         if (mFingerprintUnlockController.getMode() ==
@@ -4635,6 +4638,7 @@
             dozing = false;
         }
         mDozing = dozing;
+        mKeyguardViewMediator.setAodShowing(mDozing && alwaysOn);
         mStatusBarWindowManager.setDozing(mDozing);
         mStatusBarKeyguardViewManager.setDozing(mDozing);
         if (mAmbientIndicationContainer instanceof DozeReceiver) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index 309a1a7..2437c51 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -143,7 +143,9 @@
 
         final boolean scrimsOccludingWallpaper =
                 state.scrimsVisibility == ScrimController.VISIBILITY_FULLY_OPAQUE;
-        if (state.keyguardShowing && !state.backdropShowing && !scrimsOccludingWallpaper) {
+        final boolean keyguardOrAod = state.keyguardShowing
+                || (state.dozing && mDozeParameters.getAlwaysOn());
+        if (keyguardOrAod && !state.backdropShowing && !scrimsOccludingWallpaper) {
             mLpChanged.flags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
         } else {
             mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index f81ffd8..4a66bb7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -70,6 +70,7 @@
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.assist.AssistManager;
+import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.statusbar.ActivatableNotificationView;
@@ -132,6 +133,7 @@
     @Mock private NotificationViewHierarchyManager mViewHierarchyManager;
     @Mock private VisualStabilityManager mVisualStabilityManager;
     @Mock private NotificationListener mNotificationListener;
+    @Mock private KeyguardViewMediator mKeyguardViewMediator;
 
     private TestableStatusBar mStatusBar;
     private FakeMetricsLogger mMetricsLogger;
@@ -200,7 +202,7 @@
                 mPowerManager, mNotificationPanelView, mBarService, mNotificationListener,
                 mNotificationLogger, mVisualStabilityManager, mViewHierarchyManager,
                 mEntryManager, mScrimController, mFingerprintUnlockController,
-                mock(ActivityLaunchAnimator.class));
+                mock(ActivityLaunchAnimator.class), mKeyguardViewMediator);
         mStatusBar.mContext = mContext;
         mStatusBar.mComponents = mContext.getComponents();
         mEntryManager.setUpForTest(mStatusBar, mStackScroller, mStatusBar, mHeadsUpManager,
@@ -638,7 +640,7 @@
                 NotificationViewHierarchyManager viewHierarchyManager,
                 TestableNotificationEntryManager entryManager, ScrimController scrimController,
                 FingerprintUnlockController fingerprintUnlockController,
-                ActivityLaunchAnimator launchAnimator) {
+                ActivityLaunchAnimator launchAnimator, KeyguardViewMediator keyguardViewMediator) {
             mStatusBarKeyguardViewManager = man;
             mUnlockMethodCache = unlock;
             mKeyguardIndicationController = key;
@@ -656,6 +658,7 @@
             mScrimController = scrimController;
             mFingerprintUnlockController = fingerprintUnlockController;
             mActivityLaunchAnimator = launchAnimator;
+            mKeyguardViewMediator = keyguardViewMediator;
             mClearAllEnabled = true;
         }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1037561..25d5832 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -820,7 +820,7 @@
 
     public boolean canShowErrorDialogs() {
         return mShowDialogs && !mSleeping && !mShuttingDown
-                && !mKeyguardController.isKeyguardShowing(DEFAULT_DISPLAY)
+                && !mKeyguardController.isKeyguardOrAodShowing(DEFAULT_DISPLAY)
                 && !mUserController.hasUserRestriction(UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS,
                         mUserController.getCurrentUserId())
                 && !(UserManager.isDeviceInDemoMode(mContext)
@@ -10605,8 +10605,8 @@
                         intent.addFlags(Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS);
                     }
                 }
-                final ActivityInfo ainfo = AppGlobals.getPackageManager().getActivityInfo(comp, 0,
-                        UserHandle.getUserId(callingUid));
+                final ActivityInfo ainfo = AppGlobals.getPackageManager().getActivityInfo(comp,
+                        STOCK_PM_FLAGS, UserHandle.getUserId(callingUid));
                 if (ainfo.applicationInfo.uid != callingUid) {
                     throw new SecurityException(
                             "Can't add task for another application: target uid="
@@ -13223,7 +13223,8 @@
     }
 
     @Override
-    public void setLockScreenShown(boolean showing, int secondaryDisplayShowing) {
+    public void setLockScreenShown(boolean keyguardShowing, boolean aodShowing,
+            int secondaryDisplayShowing) {
         if (checkCallingPermission(android.Manifest.permission.DEVICE_POWER)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Requires permission "
@@ -13233,13 +13234,14 @@
         synchronized(this) {
             long ident = Binder.clearCallingIdentity();
             try {
-                mKeyguardController.setKeyguardShown(showing, secondaryDisplayShowing);
+                mKeyguardController.setKeyguardShown(keyguardShowing, aodShowing,
+                        secondaryDisplayShowing);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
         }
 
-        mHandler.obtainMessage(DISPATCH_SCREEN_KEYGUARD_MSG, showing ? 1 : 0, 0)
+        mHandler.obtainMessage(DISPATCH_SCREEN_KEYGUARD_MSG, keyguardShowing ? 1 : 0, 0)
                 .sendToTarget();
     }
 
@@ -21211,7 +21213,7 @@
                         ApplicationInfo aInfo = null;
                         try {
                             aInfo = AppGlobals.getPackageManager()
-                                    .getApplicationInfo(ssp, 0 /*flags*/, userId);
+                                    .getApplicationInfo(ssp, STOCK_PM_FLAGS, userId);
                         } catch (RemoteException ignore) {}
                         if (aInfo == null) {
                             Slog.w(TAG, "Dropping ACTION_PACKAGE_REPLACED for non-existent pkg:"
@@ -21236,7 +21238,7 @@
 
                         try {
                             ApplicationInfo ai = AppGlobals.getPackageManager().
-                                    getApplicationInfo(ssp, 0, 0);
+                                    getApplicationInfo(ssp, STOCK_PM_FLAGS, 0);
                             mBatteryStatsService.notePackageInstalled(ssp,
                                     ai != null ? ai.versionCode : 0);
                         } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index ccc17a3..1af4114 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -236,7 +236,8 @@
     final IApplicationToken.Stub appToken; // window manager token
     AppWindowContainerController mWindowContainerController;
     final ActivityInfo info; // all about me
-    final ApplicationInfo appInfo; // information about activity's app
+    // TODO: This is duplicated state already contained in info.applicationInfo - remove
+    ApplicationInfo appInfo; // information about activity's app
     final int launchedFromPid; // always the pid who started the activity.
     final int launchedFromUid; // always the uid who started the activity.
     final String launchedFromPackage; // always the package who started the activity.
@@ -605,6 +606,11 @@
         }
     }
 
+    void updateApplicationInfo(ApplicationInfo aInfo) {
+        appInfo = aInfo;
+        info.applicationInfo = aInfo;
+    }
+
     private boolean crossesHorizontalSizeThreshold(int firstDp, int secondDp) {
         return crossesSizeThreshold(mHorizontalSizeConfigurations, firstDp, secondDp);
     }
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index aa462ec..00ebcbd 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1324,7 +1324,7 @@
                 final ActivityRecord ar = activities.get(activityNdx);
 
                 if ((userId == ar.userId) && packageName.equals(ar.packageName)) {
-                    ar.info.applicationInfo = aInfo;
+                    ar.updateApplicationInfo(aInfo);
                 }
             }
         }
@@ -2019,8 +2019,9 @@
      * @return true if {@param r} is visible taken Keyguard state into account, false otherwise
      */
     boolean checkKeyguardVisibility(ActivityRecord r, boolean shouldBeVisible, boolean isTop) {
-        final boolean keyguardShowing = mStackSupervisor.getKeyguardController().isKeyguardShowing(
-                mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY);
+        final int displayId = mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY;
+        final boolean keyguardOrAodShowing = mStackSupervisor.getKeyguardController()
+                .isKeyguardOrAodShowing(displayId);
         final boolean keyguardLocked = mStackSupervisor.getKeyguardController().isKeyguardLocked();
         final boolean showWhenLocked = r.canShowWhenLocked();
         final boolean dismissKeyguard = r.hasDismissKeyguardWindows();
@@ -2041,10 +2042,9 @@
                 return true;
             }
         }
-        if (keyguardShowing) {
-
+        if (keyguardOrAodShowing) {
             // If keyguard is showing, nothing is visible, except if we are able to dismiss Keyguard
-            // right away.
+            // right away and AOD isn't visible.
             return shouldBeVisible && mStackSupervisor.getKeyguardController()
                     .canShowActivityWhileKeyguardShowing(r, dismissKeyguard);
         } else if (keyguardLocked) {
@@ -3987,7 +3987,8 @@
             } else {
                 try {
                     ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo(
-                            destIntent.getComponent(), 0, srec.userId);
+                            destIntent.getComponent(), ActivityManagerService.STOCK_PM_FLAGS,
+                            srec.userId);
                     // TODO(b/64750076): Check if calling pid should really be -1.
                     final int res = mService.getActivityStartController()
                             .obtainStarter(destIntent, "navigateUpTo")
@@ -5139,8 +5140,9 @@
                 mService, taskId, info, intent, voiceSession, voiceInteractor);
         // add the task to stack first, mTaskPositioner might need the stack association
         addTask(task, toTop, "createTaskRecord");
+        final int displayId = mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY;
         final boolean isLockscreenShown = mService.mStackSupervisor.getKeyguardController()
-                .isKeyguardShowing(mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY);
+                .isKeyguardOrAodShowing(displayId);
         if (!mStackSupervisor.getLaunchParamsController()
                 .layoutTask(task, info.windowLayout, activity, source, options)
                 && !matchParentBounds() && task.isResizeable() && !isLockscreenShown) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 265e4fa..d5dfdcf 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -3382,8 +3382,8 @@
                     stack.goToSleepIfPossible(false /* shuttingDown */);
                 } else {
                     stack.awakeFromSleepingLocked();
-                    if (isFocusedStack(stack)
-                            && !getKeyguardController().isKeyguardShowing(display.mDisplayId)) {
+                    if (isFocusedStack(stack) && !getKeyguardController().isKeyguardOrAodShowing(
+                            display.mDisplayId)) {
                         // If the keyguard is unlocked - resume immediately.
                         // It is possible that the display will not be awake at the time we
                         // process the keyguard going away, which can happen before the sleep token
diff --git a/services/core/java/com/android/server/am/ActivityStartController.java b/services/core/java/com/android/server/am/ActivityStartController.java
index 868f90d..fb78838 100644
--- a/services/core/java/com/android/server/am/ActivityStartController.java
+++ b/services/core/java/com/android/server/am/ActivityStartController.java
@@ -198,9 +198,10 @@
 
             // See if we should be showing the platform update setup UI.
             final Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
-            final List<ResolveInfo> ris = mService.mContext.getPackageManager()
-                    .queryIntentActivities(intent,
-                            PackageManager.MATCH_SYSTEM_ONLY | PackageManager.GET_META_DATA);
+            final List<ResolveInfo> ris =
+                    mService.mContext.getPackageManager().queryIntentActivities(intent,
+                            PackageManager.MATCH_SYSTEM_ONLY | PackageManager.GET_META_DATA
+                                    | ActivityManagerService.STOCK_PM_FLAGS);
             if (!ris.isEmpty()) {
                 final ResolveInfo ri = ris.get(0);
                 String vers = ri.activityInfo.metaData != null
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index b67dd0d..1b7f75b 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -62,6 +62,7 @@
     private final ActivityStackSupervisor mStackSupervisor;
     private WindowManagerService mWindowManager;
     private boolean mKeyguardShowing;
+    private boolean mAodShowing;
     private boolean mKeyguardGoingAway;
     private boolean mOccluded;
     private boolean mDismissalRequested;
@@ -82,6 +83,15 @@
     }
 
     /**
+     * @return true if either Keyguard or AOD are showing, not going away, and not being occluded
+     *         on the given display, false otherwise
+     */
+    boolean isKeyguardOrAodShowing(int displayId) {
+        return (mKeyguardShowing || mAodShowing) && !mKeyguardGoingAway &&
+                (displayId == DEFAULT_DISPLAY ? !mOccluded : displayId == mSecondaryDisplayShowing);
+    }
+
+    /**
      * @return true if Keyguard is showing, not going away, and not being occluded on the given
      *         display, false otherwise
      */
@@ -108,17 +118,19 @@
     /**
      * Update the Keyguard showing state.
      */
-    void setKeyguardShown(boolean showing, int secondaryDisplayShowing) {
-        boolean showingChanged = showing != mKeyguardShowing;
+    void setKeyguardShown(boolean keyguardShowing, boolean aodShowing,
+            int secondaryDisplayShowing) {
+        boolean showingChanged = keyguardShowing != mKeyguardShowing || aodShowing != mAodShowing;
         if (!showingChanged && secondaryDisplayShowing == mSecondaryDisplayShowing) {
             return;
         }
-        mKeyguardShowing = showing;
+        mKeyguardShowing = keyguardShowing;
+        mAodShowing = aodShowing;
         mSecondaryDisplayShowing = secondaryDisplayShowing;
         if (showingChanged) {
             dismissDockedStackIfNeeded();
             setKeyguardGoingAway(false);
-            if (showing) {
+            if (keyguardShowing) {
                 mDismissalRequested = false;
             }
         }
@@ -230,8 +242,8 @@
         // Allow to show it when we are about to dismiss Keyguard. This isn't allowed if r is
         // already the dismissing activity, in which case we don't allow it to repeatedly dismiss
         // Keyguard.
-        return dismissKeyguard && canDismissKeyguard() &&
-                (mDismissalRequested || r != mDismissingKeyguardActivity);
+        return dismissKeyguard && canDismissKeyguard() && !mAodShowing
+                && (mDismissalRequested || r != mDismissingKeyguardActivity);
     }
 
     /**
@@ -369,9 +381,9 @@
     }
 
     private void updateKeyguardSleepToken() {
-        if (mSleepToken == null && isKeyguardShowing(DEFAULT_DISPLAY)) {
+        if (mSleepToken == null && isKeyguardOrAodShowing(DEFAULT_DISPLAY)) {
             mSleepToken = mService.acquireSleepToken("Keyguard", DEFAULT_DISPLAY);
-        } else if (mSleepToken != null && !isKeyguardShowing(DEFAULT_DISPLAY)) {
+        } else if (mSleepToken != null && !isKeyguardOrAodShowing(DEFAULT_DISPLAY)) {
             mSleepToken.release();
             mSleepToken = null;
         }
@@ -380,6 +392,7 @@
     void dump(PrintWriter pw, String prefix) {
         pw.println(prefix + "KeyguardController:");
         pw.println(prefix + "  mKeyguardShowing=" + mKeyguardShowing);
+        pw.println(prefix + "  mAodShowing=" + mAodShowing);
         pw.println(prefix + "  mKeyguardGoingAway=" + mKeyguardGoingAway);
         pw.println(prefix + "  mOccluded=" + mOccluded);
         pw.println(prefix + "  mDismissingKeyguardActivity=" + mDismissingKeyguardActivity);
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index efd81538..fcf00ce 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -600,7 +600,8 @@
                         // activities that are fully runnable based on
                         // current system state.
                         ai = pm.getActivityInfo(task.realActivity,
-                                PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userId);
+                                PackageManager.MATCH_DEBUG_TRIAGED_MISSING
+                                        | ActivityManagerService.STOCK_PM_FLAGS, userId);
                     } catch (RemoteException e) {
                         // Will never happen.
                         continue;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9b67bbd..2ae337d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -92,6 +92,7 @@
 import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT;
 import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME;
 import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
+import static com.android.internal.util.ArrayUtils.appendElement;
 import static com.android.internal.util.ArrayUtils.appendInt;
 import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
 import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
@@ -778,8 +779,14 @@
             return PackageManagerService.this.hasSystemFeature(feature, 0);
         }
 
-        final List<PackageParser.Package> getStaticOverlayPackagesLocked(
+        final List<PackageParser.Package> getStaticOverlayPackages(
                 Collection<PackageParser.Package> allPackages, String targetPackageName) {
+            if ("android".equals(targetPackageName)) {
+                // Static RROs targeting to "android", ie framework-res.apk, are already applied by
+                // native AssetManager.
+                return null;
+            }
+
             List<PackageParser.Package> overlayPackages = null;
             for (PackageParser.Package p : allPackages) {
                 if (targetPackageName.equals(p.mOverlayTarget) && p.mOverlayIsStatic) {
@@ -800,16 +807,8 @@
             return overlayPackages;
         }
 
-        @GuardedBy("mInstallLock")
-        final String[] getStaticOverlayPathsLocked(Collection<PackageParser.Package> allPackages,
-                String targetPackageName, String targetPath) {
-            if ("android".equals(targetPackageName)) {
-                // Static RROs targeting to "android", ie framework-res.apk, are already applied by
-                // native AssetManager.
-                return null;
-            }
-            List<PackageParser.Package> overlayPackages =
-                    getStaticOverlayPackagesLocked(allPackages, targetPackageName);
+        final String[] getStaticOverlayPaths(List<PackageParser.Package> overlayPackages,
+                String targetPath) {
             if (overlayPackages == null || overlayPackages.isEmpty()) {
                 return null;
             }
@@ -829,9 +828,11 @@
                     //
                     // OverlayManagerService will update each of them with a correct gid from its
                     // target package app id.
-                    mInstaller.idmap(targetPath, overlayPackage.baseCodePath,
-                            UserHandle.getSharedAppGid(
-                                    UserHandle.getUserGid(UserHandle.USER_SYSTEM)));
+                    synchronized (mInstallLock) {
+                        mInstaller.idmap(targetPath, overlayPackage.baseCodePath,
+                                UserHandle.getSharedAppGid(
+                                        UserHandle.getUserGid(UserHandle.USER_SYSTEM)));
+                    }
                     if (overlayPathList == null) {
                         overlayPathList = new ArrayList<String>();
                     }
@@ -845,10 +846,14 @@
         }
 
         String[] getStaticOverlayPaths(String targetPackageName, String targetPath) {
+            List<PackageParser.Package> overlayPackages;
             synchronized (mPackages) {
-                return getStaticOverlayPathsLocked(
-                        mPackages.values(), targetPackageName, targetPath);
+                overlayPackages = getStaticOverlayPackages(
+                        mPackages.values(), targetPackageName);
             }
+            // It is safe to keep overlayPackages without holding mPackages because static overlay
+            // packages can't be uninstalled or disabled.
+            return getStaticOverlayPaths(overlayPackages, targetPath);
         }
 
         @Override public final String[] getOverlayApks(String targetPackageName) {
@@ -883,7 +888,9 @@
             // can't happen while running parallel parsing.
             // Moreover holding mPackages on each parsing thread causes dead-lock.
             return mOverlayPackages == null ? null :
-                    getStaticOverlayPathsLocked(mOverlayPackages, targetPackageName, targetPath);
+                    getStaticOverlayPaths(
+                            getStaticOverlayPackages(mOverlayPackages, targetPackageName),
+                            targetPath);
         }
     }
 
@@ -13987,18 +13994,15 @@
             return packageNames;
         }
 
-        // List of package names for whom the suspended state has changed.
-        final List<String> changedPackages = new ArrayList<>(packageNames.length);
-        // List of package names for whom the suspended state is not set as requested in this
-        // method.
+        final List<String> changedPackagesList = new ArrayList<>(packageNames.length);
         final List<String> unactionedPackages = new ArrayList<>(packageNames.length);
         final long callingId = Binder.clearCallingIdentity();
         try {
             synchronized (mPackages) {
                 for (int i = 0; i < packageNames.length; i++) {
                     final String packageName = packageNames[i];
-                    if (packageName == callingPackage) {
-                        Slog.w(TAG, "Calling package: " + callingPackage + "trying to "
+                    if (callingPackage.equals(packageName)) {
+                        Slog.w(TAG, "Calling package: " + callingPackage + " trying to "
                                 + (suspended ? "" : "un") + "suspend itself. Ignoring");
                         unactionedPackages.add(packageName);
                         continue;
@@ -14018,17 +14022,18 @@
                         }
                         pkgSetting.setSuspended(suspended, callingPackage, appExtras,
                                 launcherExtras, userId);
-                        changedPackages.add(packageName);
+                        changedPackagesList.add(packageName);
                     }
                 }
             }
         } finally {
             Binder.restoreCallingIdentity(callingId);
         }
-        // TODO (b/75036698): Also send each package a broadcast when suspended state changed
-        if (!changedPackages.isEmpty()) {
-            sendPackagesSuspendedForUser(changedPackages.toArray(
-                    new String[changedPackages.size()]), userId, suspended);
+        if (!changedPackagesList.isEmpty()) {
+            final String[] changedPackages = changedPackagesList.toArray(
+                    new String[changedPackagesList.size()]);
+            sendPackagesSuspendedForUser(changedPackages, userId, suspended);
+            sendMyPackageSuspendedOrUnsuspended(changedPackages, suspended, appExtras, userId);
             synchronized (mPackages) {
                 scheduleWritePackageRestrictionsLocked(userId);
             }
@@ -14038,7 +14043,7 @@
     }
 
     @Override
-    public PersistableBundle getPackageSuspendedAppExtras(String packageName, int userId) {
+    public PersistableBundle getSuspendedPackageAppExtras(String packageName, int userId) {
         final int callingUid = Binder.getCallingUid();
         if (getPackageUid(packageName, 0, userId) != callingUid) {
             mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS, null);
@@ -14049,7 +14054,10 @@
                 throw new IllegalArgumentException("Unknown target package: " + packageName);
             }
             final PackageUserState packageUserState = ps.readUserState(userId);
-            return packageUserState.suspended ? packageUserState.suspendedAppExtras : null;
+            if (packageUserState.suspended) {
+                return packageUserState.suspendedAppExtras;
+            }
+            return null;
         }
     }
 
@@ -14065,12 +14073,49 @@
             }
             final PackageUserState packageUserState = ps.readUserState(userId);
             if (packageUserState.suspended) {
-                // TODO (b/75036698): Also send this package a broadcast with the new app extras
                 packageUserState.suspendedAppExtras = appExtras;
+                sendMyPackageSuspendedOrUnsuspended(new String[] {packageName}, true, appExtras,
+                        userId);
             }
         }
     }
 
+    private void sendMyPackageSuspendedOrUnsuspended(String[] affectedPackages, boolean suspended,
+            PersistableBundle appExtras, int userId) {
+        final String action;
+        final Bundle intentExtras = new Bundle();
+        if (suspended) {
+            action = Intent.ACTION_MY_PACKAGE_SUSPENDED;
+            if (appExtras != null) {
+                final Bundle bundledAppExtras = new Bundle(appExtras.deepCopy());
+                intentExtras.putBundle(Intent.EXTRA_SUSPENDED_PACKAGE_EXTRAS, bundledAppExtras);
+            }
+        } else {
+            action = Intent.ACTION_MY_PACKAGE_UNSUSPENDED;
+        }
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    final IActivityManager am = ActivityManager.getService();
+                    if (am == null) {
+                        Slog.wtf(TAG, "IActivityManager null. Cannot send MY_PACKAGE_ "
+                                + (suspended ? "" : "UN") + "SUSPENDED broadcasts");
+                        return;
+                    }
+                    final int[] targetUserIds = new int[] {userId};
+                    for (String packageName : affectedPackages) {
+                        doSendBroadcast(am, action, null, intentExtras,
+                                Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, packageName, null,
+                                targetUserIds, false);
+                    }
+                } catch (RemoteException ex) {
+                    // Shouldn't happen as AMS is in the same process.
+                }
+            }
+        });
+    }
+
     @Override
     public boolean isPackageSuspendedForUser(String packageName, int userId) {
         final int callingUid = Binder.getCallingUid();
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 062b154..81a8c55 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -213,7 +213,8 @@
                     // There are no longer any keyguard windows on secondary displays, so pass
                     // INVALID_DISPLAY. All that means is that showWhenLocked activities on
                     // secondary displays now get to show.
-                    ActivityManager.getService().setLockScreenShown(true, INVALID_DISPLAY);
+                    ActivityManager.getService().setLockScreenShown(true /* keyguardShowing */,
+                            false /* aodShowing */, INVALID_DISPLAY);
                 } catch (RemoteException e) {
                     // Local call.
                 }
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
index b452ea5..cda968a7 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
@@ -240,7 +240,7 @@
 
         doReturn(displayShouldSleep).when(display).shouldSleep();
         doReturn(displaySleeping).when(display).isSleeping();
-        doReturn(keyguardShowing).when(keyguard).isKeyguardShowing(anyInt());
+        doReturn(keyguardShowing).when(keyguard).isKeyguardOrAodShowing(anyInt());
 
         mSupervisor.mFocusedStack = isFocusedStack ? stack : null;
         mSupervisor.applySleepTokensLocked(true);
diff --git a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
index d702318..ee0ad39 100644
--- a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
@@ -16,55 +16,129 @@
 
 package com.android.server.pm;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
+import android.app.AppGlobals;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.os.BaseBundle;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.PersistableBundle;
+import android.os.RemoteException;
 import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.MediumTest;
+import android.support.test.filters.LargeTest;
 import android.support.test.runner.AndroidJUnit4;
 
 import com.android.servicestests.apps.suspendtestapp.SuspendTestReceiver;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.SynchronousQueue;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
 
 @RunWith(AndroidJUnit4.class)
-@MediumTest
+@LargeTest
 public class SuspendPackagesTest {
     private static final String TEST_APP_PACKAGE_NAME = SuspendTestReceiver.PACKAGE_NAME;
     private static final String[] PACKAGES_TO_SUSPEND = new String[]{TEST_APP_PACKAGE_NAME};
 
+    public static final String INSTRUMENTATION_PACKAGE = "com.android.frameworks.servicestests";
+    public static final String ACTION_REPORT_MY_PACKAGE_SUSPENDED =
+            INSTRUMENTATION_PACKAGE + ".action.REPORT_MY_PACKAGE_SUSPENDED";
+    public static final String ACTION_REPORT_MY_PACKAGE_UNSUSPENDED =
+            INSTRUMENTATION_PACKAGE + ".action.REPORT_MY_PACKAGE_UNSUSPENDED";
+
     private Context mContext;
     private PackageManager mPackageManager;
     private Handler mReceiverHandler;
     private ComponentName mTestReceiverComponent;
+    private AppCommunicationReceiver mAppCommsReceiver;
+
+    private static final class AppCommunicationReceiver extends BroadcastReceiver {
+        private Context context;
+        private boolean registered;
+        private SynchronousQueue<Intent> intentQueue = new SynchronousQueue<>();
+
+        AppCommunicationReceiver(Context context) {
+            this.context = context;
+        }
+
+        void register(Handler handler) {
+            registered = true;
+            final IntentFilter intentFilter = new IntentFilter();
+            intentFilter.addAction(ACTION_REPORT_MY_PACKAGE_SUSPENDED);
+            intentFilter.addAction(ACTION_REPORT_MY_PACKAGE_UNSUSPENDED);
+            context.registerReceiver(this, intentFilter, null, handler);
+        }
+
+        void unregister() {
+            if (registered) {
+                context.unregisterReceiver(this);
+            }
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            try {
+                intentQueue.offer(intent, 5, TimeUnit.SECONDS);
+            } catch (InterruptedException ie) {
+                throw new RuntimeException("Receiver thread interrupted", ie);
+            }
+        }
+
+        Intent receiveIntentFromApp() {
+            if (!registered) {
+                throw new IllegalStateException("Receiver not registered");
+            }
+            final Intent intent;
+            try {
+                intent = intentQueue.poll(5, TimeUnit.SECONDS);
+            } catch (InterruptedException ie) {
+                throw new RuntimeException("Interrupted while waiting for app broadcast", ie);
+            }
+            assertNotNull("No intent received from app within 5 seconds", intent);
+            return intent;
+        }
+    }
 
     @Before
     public void setUp() {
         mContext = InstrumentationRegistry.getTargetContext();
         mPackageManager = mContext.getPackageManager();
-        mPackageManager.setPackagesSuspended(PACKAGES_TO_SUSPEND, false, null, null, null);
         mReceiverHandler = new Handler(Looper.getMainLooper());
         mTestReceiverComponent = new ComponentName(TEST_APP_PACKAGE_NAME,
                 SuspendTestReceiver.class.getCanonicalName());
+        IPackageManager ipm = AppGlobals.getPackageManager();
+        try {
+            // Otherwise implicit broadcasts will not be delivered.
+            ipm.setPackageStoppedState(TEST_APP_PACKAGE_NAME, false, mContext.getUserId());
+        } catch (RemoteException e) {
+            e.rethrowAsRuntimeException();
+        }
+        unsuspendTestPackage();
+        mAppCommsReceiver = new AppCommunicationReceiver(mContext);
     }
 
+    /**
+     * Care should be taken when used with {@link #mAppCommsReceiver} in the same test as both use
+     * the same handler.
+     */
     private Bundle requestAppAction(String action) throws InterruptedException {
         final AtomicReference<Bundle> result = new AtomicReference<>();
         final CountDownLatch receiverLatch = new CountDownLatch(1);
@@ -98,6 +172,24 @@
         assertTrue("setPackagesSuspended returned non-empty list", unchangedPackages.length == 0);
     }
 
+    private void unsuspendTestPackage() {
+        final String[] unchangedPackages = mPackageManager.setPackagesSuspended(
+                PACKAGES_TO_SUSPEND, false, null, null, null);
+        assertTrue("setPackagesSuspended returned non-empty list", unchangedPackages.length == 0);
+    }
+
+
+    private static void assertSameExtras(String message, BaseBundle expected, BaseBundle received) {
+        if (expected != null) {
+            expected.get(""); // hack to unparcel the bundles.
+        }
+        if (received != null) {
+            received.get("");
+        }
+        assertTrue(message + ": [expected: " + expected + "; received: " + received + "]",
+                BaseBundle.kindofEquals(expected, received));
+    }
+
     @Test
     public void testIsPackageSuspended() {
         suspendTestPackage(null, null);
@@ -109,19 +201,73 @@
     public void testSuspendedStateFromApp() throws Exception {
         Bundle resultFromApp = requestAppAction(SuspendTestReceiver.ACTION_GET_SUSPENDED_STATE);
         assertFalse(resultFromApp.getBoolean(SuspendTestReceiver.EXTRA_SUSPENDED, true));
-        assertNull(resultFromApp.getParcelable(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
+        assertNull(resultFromApp.getBundle(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
 
-        final PersistableBundle appExtras = getExtras("appExtras", 20, "20", 0.2);
+        final PersistableBundle appExtras = getExtras("testSuspendedStateFromApp", 20, "20", 0.2);
         suspendTestPackage(appExtras, null);
 
         resultFromApp = requestAppAction(SuspendTestReceiver.ACTION_GET_SUSPENDED_STATE);
         assertTrue("resultFromApp:suspended is false",
                 resultFromApp.getBoolean(SuspendTestReceiver.EXTRA_SUSPENDED));
-        final PersistableBundle receivedAppExtras =
-                resultFromApp.getParcelable(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS);
-        receivedAppExtras.get(""); // hack to unparcel the bundles
-        appExtras.get("");
-        assertTrue("Received app extras " + receivedAppExtras + " different to the ones supplied",
-                BaseBundle.kindofEquals(appExtras, receivedAppExtras));
+        final Bundle receivedAppExtras =
+                resultFromApp.getBundle(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS);
+        assertSameExtras("Received app extras different to the ones supplied",
+                appExtras, receivedAppExtras);
+    }
+
+    @Test
+    public void testMyPackageSuspendedUnsuspended() {
+        mAppCommsReceiver.register(mReceiverHandler);
+        final PersistableBundle appExtras = getExtras("testMyPackageSuspendBroadcasts", 1, "1", .1);
+        suspendTestPackage(appExtras, null);
+        Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
+        assertTrue("MY_PACKAGE_SUSPENDED delivery not reported",
+                ACTION_REPORT_MY_PACKAGE_SUSPENDED.equals(intentFromApp.getAction()));
+        assertSameExtras("Received app extras different to the ones supplied", appExtras,
+                intentFromApp.getBundleExtra(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
+        unsuspendTestPackage();
+        intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
+        assertTrue("MY_PACKAGE_UNSUSPENDED delivery not reported",
+                ACTION_REPORT_MY_PACKAGE_UNSUSPENDED.equals(intentFromApp.getAction()));
+    }
+
+    @Test
+    public void testUpdatingAppExtras() {
+        mAppCommsReceiver.register(mReceiverHandler);
+        final PersistableBundle extras1 = getExtras("testMyPackageSuspendedOnChangingExtras", 1,
+                "1", 0.1);
+        suspendTestPackage(extras1, null);
+        Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
+        assertTrue("MY_PACKAGE_SUSPENDED delivery not reported",
+                ACTION_REPORT_MY_PACKAGE_SUSPENDED.equals(intentFromApp.getAction()));
+        assertSameExtras("Received app extras different to the ones supplied", extras1,
+                intentFromApp.getBundleExtra(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
+        final PersistableBundle extras2 = getExtras("testMyPackageSuspendedOnChangingExtras", 2,
+                "2", 0.2);
+        mPackageManager.setSuspendedPackageAppExtras(TEST_APP_PACKAGE_NAME, extras2);
+        intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
+        assertTrue("MY_PACKAGE_SUSPENDED delivery not reported",
+                ACTION_REPORT_MY_PACKAGE_SUSPENDED.equals(intentFromApp.getAction()));
+        assertSameExtras("Received app extras different to the updated extras", extras2,
+                intentFromApp.getBundleExtra(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
+    }
+
+    @Test
+    public void testCannotSuspendSelf() {
+        final String[] unchangedPkgs = mPackageManager.setPackagesSuspended(
+                new String[]{mContext.getOpPackageName()}, true, null, null, null);
+        assertTrue(unchangedPkgs.length == 1);
+        assertEquals(mContext.getOpPackageName(), unchangedPkgs[0]);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mAppCommsReceiver.unregister();
+        Thread.sleep(250); // To prevent any race with the next registerReceiver
+    }
+
+    @FunctionalInterface
+    interface Condition {
+        boolean isTrue();
     }
 }
diff --git a/services/tests/servicestests/test-apps/SuspendTestApp/Android.mk b/services/tests/servicestests/test-apps/SuspendTestApp/Android.mk
index 40a34b9..afdde72 100644
--- a/services/tests/servicestests/test-apps/SuspendTestApp/Android.mk
+++ b/services/tests/servicestests/test-apps/SuspendTestApp/Android.mk
@@ -17,14 +17,18 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := current
 
 LOCAL_COMPATIBILITY_SUITE := device-tests
 
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_SRC_FILES += ../../src/com/android/server/pm/SuspendPackagesTest.java
 
 LOCAL_PACKAGE_NAME := SuspendTestApp
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 
+LOCAL_PRIVATE_PLATFORM_APIS := true
+
 include $(BUILD_PACKAGE)
\ No newline at end of file
diff --git a/services/tests/servicestests/test-apps/SuspendTestApp/AndroidManifest.xml b/services/tests/servicestests/test-apps/SuspendTestApp/AndroidManifest.xml
index 70a1fd0..ce6a27a 100644
--- a/services/tests/servicestests/test-apps/SuspendTestApp/AndroidManifest.xml
+++ b/services/tests/servicestests/test-apps/SuspendTestApp/AndroidManifest.xml
@@ -21,7 +21,12 @@
         <activity android:name=".SuspendTestActivity"
                   android:exported="true" />
         <receiver android:name=".SuspendTestReceiver"
-                  android:exported="true" />
+                  android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MY_PACKAGE_SUSPENDED" />
+                <action android:name="android.intent.action.MY_PACKAGE_UNSUSPENDED" />
+            </intent-filter>
+        </receiver>
     </application>
 
 </manifest>
\ No newline at end of file
diff --git a/services/tests/servicestests/test-apps/SuspendTestApp/src/com/android/servicestests/apps/suspendtestapp/SuspendTestReceiver.java b/services/tests/servicestests/test-apps/SuspendTestApp/src/com/android/servicestests/apps/suspendtestapp/SuspendTestReceiver.java
index 6f353a0..90a9f01 100644
--- a/services/tests/servicestests/test-apps/SuspendTestApp/src/com/android/servicestests/apps/suspendtestapp/SuspendTestReceiver.java
+++ b/services/tests/servicestests/test-apps/SuspendTestApp/src/com/android/servicestests/apps/suspendtestapp/SuspendTestReceiver.java
@@ -16,12 +16,15 @@
 
 package com.android.servicestests.apps.suspendtestapp;
 
+import static com.android.server.pm.SuspendPackagesTest.ACTION_REPORT_MY_PACKAGE_SUSPENDED;
+import static com.android.server.pm.SuspendPackagesTest.ACTION_REPORT_MY_PACKAGE_UNSUSPENDED;
+import static com.android.server.pm.SuspendPackagesTest.INSTRUMENTATION_PACKAGE;
+
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.os.Bundle;
-import android.os.PersistableBundle;
 import android.util.Log;
 
 public class SuspendTestReceiver extends BroadcastReceiver {
@@ -34,21 +37,33 @@
     public static final String EXTRA_SUSPENDED_APP_EXTRAS =
             PACKAGE_NAME + ".extra.SUSPENDED_APP_EXTRAS";
 
-    private PackageManager mPm;
-
     @Override
     public void onReceive(Context context, Intent intent) {
-        mPm = context.getPackageManager();
-        Log.d(TAG, "Received request action " + intent.getAction());
+        final PackageManager packageManager = context.getPackageManager();
+        Log.d(TAG, "Received action " + intent.getAction());
+        final Bundle appExtras;
         switch (intent.getAction()) {
             case ACTION_GET_SUSPENDED_STATE:
                 final Bundle result = new Bundle();
-                final boolean suspended = mPm.isPackageSuspended();
-                final PersistableBundle appExtras = mPm.getSuspendedPackageAppExtras();
+                final boolean suspended = packageManager.isPackageSuspended();
+                appExtras = packageManager.getSuspendedPackageAppExtras();
                 result.putBoolean(EXTRA_SUSPENDED, suspended);
-                result.putParcelable(EXTRA_SUSPENDED_APP_EXTRAS, appExtras);
+                result.putBundle(EXTRA_SUSPENDED_APP_EXTRAS, appExtras);
                 setResult(0, null, result);
                 break;
+            case Intent.ACTION_MY_PACKAGE_SUSPENDED:
+                appExtras = intent.getBundleExtra(Intent.EXTRA_SUSPENDED_PACKAGE_EXTRAS);
+                final Intent reportSuspendIntent = new Intent(ACTION_REPORT_MY_PACKAGE_SUSPENDED)
+                        .putExtra(EXTRA_SUSPENDED_APP_EXTRAS, appExtras)
+                        .setPackage(INSTRUMENTATION_PACKAGE);
+                context.sendBroadcast(reportSuspendIntent);
+                break;
+            case Intent.ACTION_MY_PACKAGE_UNSUSPENDED:
+                final Intent reportUnsuspendIntent =
+                        new Intent(ACTION_REPORT_MY_PACKAGE_UNSUSPENDED)
+                        .setPackage(INSTRUMENTATION_PACKAGE);
+                context.sendBroadcast(reportUnsuspendIntent);
+                break;
             default:
                 Log.e(TAG, "Unknown action: " + intent.getAction());
         }