Merge "Fork navbar layout for quickstep" into pi-dev
diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl
index 00d8711..9713527 100644
--- a/core/java/android/app/usage/IUsageStatsManager.aidl
+++ b/core/java/android/app/usage/IUsageStatsManager.aidl
@@ -36,6 +36,8 @@
             String callingPackage);
     UsageEvents queryEvents(long beginTime, long endTime, String callingPackage);
     UsageEvents queryEventsForPackage(long beginTime, long endTime, String callingPackage);
+    UsageEvents queryEventsForUser(long beginTime, long endTime, int userId, String callingPackage);
+    UsageEvents queryEventsForPackageForUser(long beginTime, long endTime, int userId, String pkg, String callingPackage);
     void setAppInactive(String packageName, boolean inactive, int userId);
     boolean isAppInactive(String packageName, int userId);
     void whitelistAppTemporarily(String packageName, long duration, int userId);
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index 503ca6c..3e90af3 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -399,16 +399,20 @@
      * {@hide}
      */
     public UsageEvents(Parcel in) {
-        mEventCount = in.readInt();
-        mIndex = in.readInt();
+        byte[] bytes = in.readBlob();
+        Parcel data = Parcel.obtain();
+        data.unmarshall(bytes, 0, bytes.length);
+        data.setDataPosition(0);
+        mEventCount = data.readInt();
+        mIndex = data.readInt();
         if (mEventCount > 0) {
-            mStringPool = in.createStringArray();
+            mStringPool = data.createStringArray();
 
-            final int listByteLength = in.readInt();
-            final int positionInParcel = in.readInt();
+            final int listByteLength = data.readInt();
+            final int positionInParcel = data.readInt();
             mParcel = Parcel.obtain();
             mParcel.setDataPosition(0);
-            mParcel.appendFrom(in, in.dataPosition(), listByteLength);
+            mParcel.appendFrom(data, data.dataPosition(), listByteLength);
             mParcel.setDataSize(mParcel.dataPosition());
             mParcel.setDataPosition(positionInParcel);
         }
@@ -586,10 +590,11 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mEventCount);
-        dest.writeInt(mIndex);
+        Parcel data = Parcel.obtain();
+        data.writeInt(mEventCount);
+        data.writeInt(mIndex);
         if (mEventCount > 0) {
-            dest.writeStringArray(mStringPool);
+            data.writeStringArray(mStringPool);
 
             if (mEventsToWrite != null) {
                 // Write out the events
@@ -604,31 +609,34 @@
                     final int listByteLength = p.dataPosition();
 
                     // Write the total length of the data.
-                    dest.writeInt(listByteLength);
+                    data.writeInt(listByteLength);
 
                     // Write our current position into the data.
-                    dest.writeInt(0);
+                    data.writeInt(0);
 
                     // Write the data.
-                    dest.appendFrom(p, 0, listByteLength);
+                    data.appendFrom(p, 0, listByteLength);
                 } finally {
                     p.recycle();
                 }
 
             } else if (mParcel != null) {
                 // Write the total length of the data.
-                dest.writeInt(mParcel.dataSize());
+                data.writeInt(mParcel.dataSize());
 
                 // Write out current position into the data.
-                dest.writeInt(mParcel.dataPosition());
+                data.writeInt(mParcel.dataPosition());
 
                 // Write the data.
-                dest.appendFrom(mParcel, 0, mParcel.dataSize());
+                data.appendFrom(mParcel, 0, mParcel.dataSize());
             } else {
                 throw new IllegalStateException(
                         "Either mParcel or mEventsToWrite must not be null");
             }
         }
+        // Data can be too large for a transact. Write the data as a Blob, which will be written to
+        // ashmem if too large.
+        dest.writeBlob(data.marshall());
     }
 
     public static final Creator<UsageEvents> CREATOR = new Creator<UsageEvents>() {
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 4279b19..87c64cd 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -81,6 +81,15 @@
          *
          * @hide
          */
+        public Key(String name, String fallbackName, Class<T> type) {
+            mKey = new CameraMetadataNative.Key<T>(name,  fallbackName, type);
+        }
+
+        /**
+         * Visible for testing and vendor extensions only.
+         *
+         * @hide
+         */
         public Key(String name, Class<T> type) {
             mKey = new CameraMetadataNative.Key<T>(name,  type);
         }
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index c156616..6439338 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -87,6 +87,15 @@
          *
          * @hide
          */
+        public Key(String name, String fallbackName, Class<T> type) {
+            mKey = new CameraMetadataNative.Key<T>(name, fallbackName, type);
+        }
+
+       /**
+         * Visible for testing and vendor extensions only.
+         *
+         * @hide
+         */
         public Key(String name, Class<T> type) {
             mKey = new CameraMetadataNative.Key<T>(name, type);
         }
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index e4b1339..4baf263 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -84,6 +84,7 @@
         private final Class<T> mType;
         private final TypeReference<T> mTypeReference;
         private final String mName;
+        private final String mFallbackName;
         private final int mHash;
 
         /**
@@ -96,6 +97,7 @@
                 throw new NullPointerException("Type needs to be non-null");
             }
             mName = name;
+            mFallbackName = null;
             mType = type;
             mVendorId = vendorId;
             mTypeReference = TypeReference.createSpecializedTypeReference(type);
@@ -103,6 +105,22 @@
         }
 
         /**
+         * @hide
+         */
+        public Key(String name, String fallbackName, Class<T> type) {
+            if (name == null) {
+                throw new NullPointerException("Key needs a valid name");
+            } else if (type == null) {
+                throw new NullPointerException("Type needs to be non-null");
+            }
+            mName = name;
+            mFallbackName = fallbackName;
+            mType = type;
+            mTypeReference = TypeReference.createSpecializedTypeReference(type);
+            mHash = mName.hashCode() ^ mTypeReference.hashCode();
+        }
+
+        /**
          * Visible for testing only.
          *
          * <p>Use the CameraCharacteristics.Key, CaptureResult.Key, or CaptureRequest.Key
@@ -115,6 +133,7 @@
                 throw new NullPointerException("Type needs to be non-null");
             }
             mName = name;
+            mFallbackName = null;
             mType = type;
             mTypeReference = TypeReference.createSpecializedTypeReference(type);
             mHash = mName.hashCode() ^ mTypeReference.hashCode();
@@ -134,6 +153,7 @@
                 throw new NullPointerException("TypeReference needs to be non-null");
             }
             mName = name;
+            mFallbackName = null;
             mType = (Class<T>)typeReference.getRawType();
             mTypeReference = typeReference;
             mHash = mName.hashCode() ^ mTypeReference.hashCode();
@@ -494,7 +514,16 @@
         int tag = nativeGetTagFromKeyLocal(key.getName());
         byte[] values = readValues(tag);
         if (values == null) {
-            return null;
+            // If the key returns null, use the fallback key if exists.
+            // This is to support old key names for the newly published keys.
+            if (key.mFallbackName == null) {
+                return null;
+            }
+            tag = nativeGetTagFromKeyLocal(key.mFallbackName);
+            values = readValues(tag);
+            if (values == null) {
+                return null;
+            }
         }
 
         int nativeType = nativeGetTypeFromTagLocal(tag);
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index b13f831..2d8b4d4 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -43,6 +43,7 @@
         DEFAULT_FLAGS.put("settings_bluetooth_while_driving", "false");
         DEFAULT_FLAGS.put("settings_data_usage_v2", "true");
         DEFAULT_FLAGS.put("settings_audio_switcher", "true");
+        DEFAULT_FLAGS.put("settings_systemui_theme", "false");
     }
 
     /**
diff --git a/core/java/com/android/internal/app/SuspendedAppActivity.java b/core/java/com/android/internal/app/SuspendedAppActivity.java
index f42a195..a8edfb6 100644
--- a/core/java/com/android/internal/app/SuspendedAppActivity.java
+++ b/core/java/com/android/internal/app/SuspendedAppActivity.java
@@ -60,7 +60,7 @@
         if (resolvedInfo != null && resolvedInfo.activityInfo != null
                 && requiredPermission.equals(resolvedInfo.activityInfo.permission)) {
             moreDetailsIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, suspendedPackage)
-                    .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                    .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
             return moreDetailsIntent;
         }
         return null;
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index b49aace..a6b29c5 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -409,10 +409,9 @@
         }
         mBluetoothPowerCalculator.reset();
 
-        if (mSensorPowerCalculator == null) {
-            mSensorPowerCalculator = new SensorPowerCalculator(mPowerProfile,
-                    (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE));
-        }
+        mSensorPowerCalculator = new SensorPowerCalculator(mPowerProfile,
+                (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE),
+                mStats, rawRealtimeUs, statsType);
         mSensorPowerCalculator.reset();
 
         if (mCameraPowerCalculator == null) {
diff --git a/core/java/com/android/internal/os/SensorPowerCalculator.java b/core/java/com/android/internal/os/SensorPowerCalculator.java
index c98639b..04cb49a 100644
--- a/core/java/com/android/internal/os/SensorPowerCalculator.java
+++ b/core/java/com/android/internal/os/SensorPowerCalculator.java
@@ -20,20 +20,23 @@
 import android.os.BatteryStats;
 import android.util.SparseArray;
 
+import com.android.internal.location.gnssmetrics.GnssMetrics;
+
 import java.util.List;
 
 public class SensorPowerCalculator extends PowerCalculator {
     private final List<Sensor> mSensors;
-    private final double mGpsPowerOn;
+    private final double mGpsPower;
 
-    public SensorPowerCalculator(PowerProfile profile, SensorManager sensorManager) {
+    public SensorPowerCalculator(PowerProfile profile, SensorManager sensorManager,
+            BatteryStats stats, long rawRealtimeUs, int statsType) {
         mSensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
-        mGpsPowerOn = profile.getAveragePower(PowerProfile.POWER_GPS_ON);
+        mGpsPower = getAverageGpsPower(profile, stats, rawRealtimeUs, statsType);
     }
 
     @Override
     public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
-                             long rawUptimeUs, int statsType) {
+            long rawUptimeUs, int statsType) {
         // Process Sensor usage
         final SparseArray<? extends BatteryStats.Uid.Sensor> sensorStats = u.getSensorStats();
         final int NSE = sensorStats.size();
@@ -42,10 +45,11 @@
             final int sensorHandle = sensorStats.keyAt(ise);
             final BatteryStats.Timer timer = sensor.getSensorTime();
             final long sensorTime = timer.getTotalTimeLocked(rawRealtimeUs, statsType) / 1000;
+
             switch (sensorHandle) {
                 case BatteryStats.Uid.Sensor.GPS:
                     app.gpsTimeMs = sensorTime;
-                    app.gpsPowerMah = (app.gpsTimeMs * mGpsPowerOn) / (1000*60*60);
+                    app.gpsPowerMah = (app.gpsTimeMs * mGpsPower) / (1000*60*60);
                     break;
                 default:
                     final int sensorsCount = mSensors.size();
@@ -60,4 +64,26 @@
             }
         }
     }
+
+    private double getAverageGpsPower(PowerProfile profile, BatteryStats stats, long rawRealtimeUs,
+            int statsType) {
+        double averagePower =
+                profile.getAveragePowerOrDefault(PowerProfile.POWER_GPS_ON, -1);
+        if (averagePower != -1) {
+            return averagePower;
+        }
+        averagePower = 0;
+        long totalTime = 0;
+        double totalPower = 0;
+        for (int i = 0; i < GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS; i++) {
+            long timePerLevel = stats.getGpsSignalQualityTime(i, rawRealtimeUs, statsType);
+            totalTime += timePerLevel;
+            totalPower += profile.getAveragePower(PowerProfile.POWER_GPS_SIGNAL_QUALITY_BASED, i)
+                    * timePerLevel;
+        }
+        if (totalTime != 0) {
+            averagePower = totalPower / totalTime;
+        }
+        return averagePower;
+    }
 }
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
index 145e3c4..9c80ff8 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
@@ -76,13 +76,20 @@
     // apply a simple clip with a scissor or a complex clip with a stencil
     SkRegion clipRegion;
     canvas->temporary_internal_getRgnClip(&clipRegion);
+    canvas->flush();
+    glBindFramebuffer(GL_FRAMEBUFFER, 0);
+    glViewport(0, 0, info.width, info.height);
     if (CC_UNLIKELY(clipRegion.isComplex())) {
+        //TODO: move stencil clear and canvas flush to SkAndroidFrameworkUtils::clipWithStencil
         glDisable(GL_SCISSOR_TEST);
         glStencilMask(0x1);
         glClearStencil(0);
         glClear(GL_STENCIL_BUFFER_BIT);
+        // GL ops get inserted here if previous flush is missing, which could dirty the stencil
         bool stencilWritten = SkAndroidFrameworkUtils::clipWithStencil(canvas);
-        canvas->flush();
+        canvas->flush(); //need this flush for the single op that draws into the stencil
+        glBindFramebuffer(GL_FRAMEBUFFER, 0);
+        glViewport(0, 0, info.width, info.height);
         if (stencilWritten) {
             glStencilMask(0x1);
             glStencilFunc(GL_EQUAL, 0x1, 0x1);
@@ -93,11 +100,9 @@
             glDisable(GL_STENCIL_TEST);
         }
     } else if (clipRegion.isEmpty()) {
-        canvas->flush();
         glDisable(GL_STENCIL_TEST);
         glDisable(GL_SCISSOR_TEST);
     } else {
-        canvas->flush();
         glDisable(GL_STENCIL_TEST);
         glEnable(GL_SCISSOR_TEST);
         setScissor(info.height, clipRegion.getBounds());
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 16f6284..3490ff8 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -742,7 +742,12 @@
 
 void JMediaCodec::setVideoScalingMode(int mode) {
     if (mSurfaceTextureClient != NULL) {
+        // this works for components that queue to surface
         native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode);
+        // also signal via param for components that queue to IGBP
+        sp<AMessage> msg = new AMessage;
+        msg->setInt32("android._video-scaling", mode);
+        (void)mCodec->setParameters(msg);
     }
 }
 
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index eda22d5..5dd01b0 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -384,6 +384,9 @@
     process_media_player_call(
             env, thiz, mp->getBufferingSettings(&settings),
             "java/lang/IllegalStateException", "unexpected error");
+    if (env->ExceptionCheck()) {
+        return nullptr;
+    }
     ALOGV("getBufferingSettings:{%s}", settings.toString().string());
 
     return bp.asJobject(env, gBufferingParamsFields);
@@ -555,6 +558,9 @@
     process_media_player_call(
             env, thiz, mp->getPlaybackSettings(&audioRate),
             "java/lang/IllegalStateException", "unexpected error");
+    if (env->ExceptionCheck()) {
+        return nullptr;
+    }
     ALOGV("getPlaybackSettings: %f %f %d %d",
             audioRate.mSpeed, audioRate.mPitch, audioRate.mFallbackMode, audioRate.mStretchMode);
 
@@ -623,6 +629,9 @@
     process_media_player_call(
             env, thiz, mp->getSyncSettings(&scp.sync, &scp.frameRate),
             "java/lang/IllegalStateException", "unexpected error");
+    if (env->ExceptionCheck()) {
+        return nullptr;
+    }
 
     ALOGV("getSyncSettings: %d %d %f %f",
             scp.sync.mSource, scp.sync.mAudioAdjustMode, scp.sync.mTolerance, scp.frameRate);
diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp
index 918a375..6546cf0 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -495,6 +495,9 @@
     process_media_player_call(
             env, thiz, mp->getBufferingSettings(&settings),
             "java/lang/IllegalStateException", "unexpected error");
+    if (env->ExceptionCheck()) {
+        return nullptr;
+    }
     ALOGV("getBufferingSettings:{%s}", settings.toString().string());
 
     return bp.asJobject(env, gBufferingParamsFields);
@@ -662,6 +665,9 @@
     process_media_player_call(
             env, thiz, mp->getPlaybackSettings(&audioRate),
             "java/lang/IllegalStateException", "unexpected error");
+    if (env->ExceptionCheck()) {
+        return nullptr;
+    }
     ALOGV("getPlaybackSettings: %f %f %d %d",
             audioRate.mSpeed, audioRate.mPitch, audioRate.mFallbackMode, audioRate.mStretchMode);
 
@@ -730,6 +736,9 @@
     process_media_player_call(
             env, thiz, mp->getSyncSettings(&scp.sync, &scp.frameRate),
             "java/lang/IllegalStateException", "unexpected error");
+    if (env->ExceptionCheck()) {
+        return nullptr;
+    }
 
     ALOGV("getSyncSettings: %d %d %f %f",
             scp.sync.mSource, scp.sync.mAudioAdjustMode, scp.sync.mTolerance, scp.frameRate);
diff --git a/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml b/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml
index f34811e..8379dbb 100644
--- a/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml
+++ b/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml
@@ -23,15 +23,13 @@
     android:layout_height="wrap_content"
     android:layout_width="match_parent"
     android:orientation="vertical"
-    android:gravity="center"
-    >
+    android:gravity="center">
 
     <ImageView android:id="@+id/user_avatar"
         android:layout_width="@dimen/car_user_switcher_image_avatar_size"
         android:layout_height="@dimen/car_user_switcher_image_avatar_size"
         android:background="@drawable/car_button_ripple_background_inverse"
-        android:gravity="center"
-        />
+        android:gravity="center"/>
 
     <TextView android:id="@+id/user_name"
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml b/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml
index bf5f188..2e1487c 100644
--- a/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml
+++ b/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml
@@ -37,6 +37,7 @@
             android:id="@+id/user_grid"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
+            android:layout_marginTop="@dimen/car_user_switcher_margin_top"
             app:verticallyCenterListContent="true"
             app:dayNightStyle="force_night"
             app:showPagedListViewDivider="false"
diff --git a/packages/SystemUI/res/values/dimens_car.xml b/packages/SystemUI/res/values/dimens_car.xml
index 8e17b52..afbe176 100644
--- a/packages/SystemUI/res/values/dimens_car.xml
+++ b/packages/SystemUI/res/values/dimens_car.xml
@@ -21,6 +21,7 @@
     <dimen name="car_user_switcher_image_avatar_size">@dimen/car_large_avatar_size</dimen>
     <dimen name="car_user_switcher_vertical_spacing_between_users">@dimen/car_padding_5</dimen>
     <dimen name="car_user_switcher_vertical_spacing_between_name_and_avatar">@dimen/car_padding_4</dimen>
+    <dimen name="car_user_switcher_margin_top">@dimen/car_padding_4</dimen>
 
     <dimen name="car_navigation_button_width">64dp</dimen>
     <dimen name="car_navigation_bar_width">760dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
index bcc33d2..fec76f2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
@@ -48,7 +48,6 @@
 import android.os.SystemProperties;
 import android.os.UserManager;
 import android.os.RemoteException;
-import android.util.Log;
 import android.util.TypedValue;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -163,8 +162,8 @@
                         if (mHasDismissedSwipeUpTip) {
                             int hasDimissedSwipeUpOnboardingCount =
                                     getDismissedSwipeUpOnboardingCount();
-                            if (hasDimissedSwipeUpOnboardingCount > MAX_DISMISSAL_ON_SWIPE_UP_SHOW) {
-                                Log.d(TAG, "Should not be reached");
+                            if (hasDimissedSwipeUpOnboardingCount
+                                    > MAX_DISMISSAL_ON_SWIPE_UP_SHOW) {
                                 return;
                             }
                             final int swipeUpShowOnAppLauncherAfterDismiss =
@@ -216,9 +215,9 @@
                         setHasSeenSwipeUpOnboarding(true);
                     }
                     if (fromHome) {
-                        setOpenedOverviewFromHomeCount(getOpenedOverviewFromHomeCount() + 1);
+                        incrementOpenedOverviewFromHomeCount();
                     }
-                    setOpenedOverviewCount(getOpenedOverviewCount() + 1);
+                    incrementOpenedOverviewCount();
 
                     if (getOpenedOverviewCount() >= QUICK_SCRUB_SHOW_ON_OVERVIEW_OPENED_COUNT) {
                         if (mHasDismissedQuickScrubTip) {
@@ -245,15 +244,12 @@
             = new View.OnAttachStateChangeListener() {
         @Override
         public void onViewAttachedToWindow(View view) {
-            Log.d(TAG, "View attached");
             if (view == mLayout) {
                 mContext.registerReceiver(mReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
                 mLayoutAttachedToWindow = true;
                 if (view.getTag().equals(R.string.recents_swipe_up_onboarding)) {
-                    Log.d(TAG, "recents_swipe_up_onboarding tip attached");
                     mHasDismissedSwipeUpTip = false;
                 } else {
-                    Log.d(TAG, "recents_quick_scrub_onboarding tip attached");
                     mHasDismissedQuickScrubTip = false;
                 }
             }
@@ -261,11 +257,9 @@
 
         @Override
         public void onViewDetachedFromWindow(View view) {
-            Log.d(TAG, "View detached");
             if (view == mLayout) {
                 mLayoutAttachedToWindow = false;
                 if (view.getTag().equals(R.string.recents_quick_scrub_onboarding)) {
-                    Log.d(TAG, "recents_quick_scrub_onboarding tip detached");
                     mHasDismissedQuickScrubTip = true;
                     if (hasDismissedQuickScrubOnboardingOnce()) {
                         // If user dismisses the quick scrub tip twice, we consider user has seen it
@@ -353,29 +347,23 @@
             return;
         }
 
-        Log.d(TAG, "Connecting to launcher");
         if (!mOverviewProxyListenerRegistered) {
-            Log.d(TAG, "Registering mOverviewProxyListener");
             mOverviewProxyService.addCallback(mOverviewProxyListener);
             mOverviewProxyListenerRegistered = true;
         }
         if (!mTaskListenerRegistered) {
-            Log.d(TAG, "Registering mTaskListener");
             ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskListener);
             mTaskListenerRegistered = true;
         }
     }
 
     public void onDisconnectedFromLauncher() {
-        Log.d(TAG, "Disconnecting to launcher");
 
         if (mOverviewProxyListenerRegistered) {
-            Log.d(TAG, "Unregistering mOverviewProxyListener");
             mOverviewProxyService.removeCallback(mOverviewProxyListener);
             mOverviewProxyListenerRegistered = false;
         }
         if (mTaskListenerRegistered) {
-            Log.d(TAG, "Unregistering mTaskListener");
             ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTaskListener);
             mTaskListenerRegistered = false;
         }
@@ -403,8 +391,6 @@
         // Only show in portrait.
         int orientation = mContext.getResources().getConfiguration().orientation;
         if (!mLayoutAttachedToWindow && orientation == Configuration.ORIENTATION_PORTRAIT) {
-            Log.d(TAG, "Show " + (stringRes == R.string.recents_swipe_up_onboarding
-                    ? "recents_swipe_up_onboarding" : "recents_quick_scrub_onboarding") + " tip");
             mLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
 
             mWindowManager.addView(mLayout, getWindowLayoutParams());
@@ -433,7 +419,6 @@
 
     public void hide(boolean animate) {
         if (mLayoutAttachedToWindow) {
-            Log.d(TAG, "Hide tip, animated: " + animate);
             if (animate) {
                 mLayout.animate()
                         .alpha(0f)
@@ -495,7 +480,6 @@
     }
 
     private void setHasSeenSwipeUpOnboarding(boolean hasSeenSwipeUpOnboarding) {
-        Log.d(TAG, "setHasSeenSwipeUpOnboarding: " + hasSeenSwipeUpOnboarding);
         Prefs.putBoolean(mContext, HAS_SEEN_RECENTS_SWIPE_UP_ONBOARDING, hasSeenSwipeUpOnboarding);
         if (hasSeenSwipeUpOnboarding && hasSeenQuickScrubOnboarding()) {
             onDisconnectedFromLauncher();
@@ -507,7 +491,6 @@
     }
 
     private void setHasSeenQuickScrubOnboarding(boolean hasSeenQuickScrubOnboarding) {
-        Log.d(TAG, "setHasSeenQuickScrubOnboarding: " + hasSeenQuickScrubOnboarding);
         Prefs.putBoolean(mContext, HAS_SEEN_RECENTS_QUICK_SCRUB_ONBOARDING,
                 hasSeenQuickScrubOnboarding);
         if (hasSeenQuickScrubOnboarding && hasSeenSwipeUpOnboarding()) {
@@ -520,7 +503,6 @@
     }
 
     private void setDismissedSwipeUpOnboardingCount(int dismissedSwipeUpOnboardingCount) {
-        Log.d(TAG, "setDismissedSwipeUpOnboardingCount: " + dismissedSwipeUpOnboardingCount);
         Prefs.putInt(mContext, DISMISSED_RECENTS_SWIPE_UP_ONBOARDING_COUNT,
                 dismissedSwipeUpOnboardingCount);
     }
@@ -531,8 +513,6 @@
 
     private void setHasDismissedQuickScrubOnboardingOnce(
             boolean hasDismissedQuickScrubOnboardingOnce) {
-        Log.d(TAG,
-                "setHasDismissedQuickScrubOnboardingOnce: " + hasDismissedQuickScrubOnboardingOnce);
         Prefs.putBoolean(mContext, HAS_DISMISSED_RECENTS_QUICK_SCRUB_ONBOARDING_ONCE,
                 hasDismissedQuickScrubOnboardingOnce);
     }
@@ -541,8 +521,15 @@
         return Prefs.getInt(mContext, OVERVIEW_OPENED_FROM_HOME_COUNT, 0);
     }
 
+    private void incrementOpenedOverviewFromHomeCount() {
+        int openedOverviewFromHomeCount = getOpenedOverviewFromHomeCount();
+        if (openedOverviewFromHomeCount >= SWIPE_UP_SHOW_ON_OVERVIEW_OPENED_FROM_HOME_COUNT) {
+            return;
+        }
+        setOpenedOverviewFromHomeCount(openedOverviewFromHomeCount + 1);
+    }
+
     private void setOpenedOverviewFromHomeCount(int openedOverviewFromHomeCount) {
-        Log.d(TAG, "setOpenedOverviewFromHomeCount: " + openedOverviewFromHomeCount);
         Prefs.putInt(mContext, OVERVIEW_OPENED_FROM_HOME_COUNT, openedOverviewFromHomeCount);
     }
 
@@ -550,8 +537,15 @@
         return Prefs.getInt(mContext, OVERVIEW_OPENED_COUNT, 0);
     }
 
+    private void incrementOpenedOverviewCount() {
+        int openedOverviewCount = getOpenedOverviewCount();
+        if (openedOverviewCount >= QUICK_SCRUB_SHOW_ON_OVERVIEW_OPENED_COUNT) {
+            return;
+        }
+        setOpenedOverviewCount(openedOverviewCount + 1);
+    }
+
     private void setOpenedOverviewCount(int openedOverviewCount) {
-        Log.d(TAG, "setOpenedOverviewCount: " + openedOverviewCount);
         Prefs.putInt(mContext, OVERVIEW_OPENED_COUNT, openedOverviewCount);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 364ed80..6a38797 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -515,6 +515,13 @@
         }
     }
 
+    @Override
+    public void setDistanceToTopRoundness(float distanceToTopRoundness) {
+        super.setDistanceToTopRoundness(distanceToTopRoundness);
+        mBackgroundNormal.setDistanceToTopRoundness(distanceToTopRoundness);
+        mBackgroundDimmed.setDistanceToTopRoundness(distanceToTopRoundness);
+    }
+
     /**
      * Set an override tint color that is used for the background.
      *
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index d03da8f..f30fa6b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -2795,6 +2795,24 @@
     }
 
     @Override
+    public boolean topAmountNeedsClipping() {
+        if (isGroupExpanded()) {
+            return true;
+        }
+        if (isGroupExpansionChanging()) {
+            return true;
+        }
+        if (getShowingLayout().shouldClipToRounding(true /* topRounded */,
+                false /* bottomRounded */)) {
+            return true;
+        }
+        if (mGuts != null && mGuts.getAlpha() != 0.0f) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
     protected boolean childNeedsClipping(View child) {
         if (child instanceof NotificationContentView) {
             NotificationContentView contentView = (NotificationContentView) child;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
index 67268c0..edfa61b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
@@ -76,7 +76,7 @@
      * it is moved. Otherwise, the translation is set on the {@code ExpandableOutlineView} itself.
      */
     protected boolean mShouldTranslateContents;
-    private boolean mClipRoundedToClipTopAmount;
+    private boolean mTopAmountRounded;
     private float mDistanceToTopRoundness = -1;
     private float mExtraWidthForClipping;
     private int mMinimumHeightForClipping = 0;
@@ -85,7 +85,8 @@
         @Override
         public void getOutline(View view, Outline outline) {
             if (!mCustomOutline && mCurrentTopRoundness == 0.0f
-                    && mCurrentBottomRoundness == 0.0f && !mAlwaysRoundBothCorners) {
+                    && mCurrentBottomRoundness == 0.0f && !mAlwaysRoundBothCorners
+                    && !mTopAmountRounded) {
                 int translation = mShouldTranslateContents ? (int) getTranslation() : 0;
                 int left = Math.max(translation, 0);
                 int top = mClipTopAmount + mBackgroundTop;
@@ -145,9 +146,9 @@
             return EMPTY_PATH;
         }
         float topRoundness = mAlwaysRoundBothCorners
-                ? mOutlineRadius : mCurrentTopRoundness * mOutlineRadius;
+                ? mOutlineRadius : getCurrentBackgroundRadiusTop();
         float bottomRoundness = mAlwaysRoundBothCorners
-                ? mOutlineRadius : mCurrentBottomRoundness * mOutlineRadius;
+                ? mOutlineRadius : getCurrentBackgroundRadiusBottom();
         if (topRoundness + bottomRoundness > height) {
             float overShoot = topRoundness + bottomRoundness - height;
             topRoundness -= overShoot * mCurrentTopRoundness
@@ -203,7 +204,7 @@
     protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
         canvas.save();
         Path intersectPath = null;
-        if (mClipRoundedToClipTopAmount) {
+        if (mTopAmountRounded && topAmountNeedsClipping()) {
             int left = (int) (- mExtraWidthForClipping / 2.0f);
             int top = (int) (mClipTopAmount - mDistanceToTopRoundness);
             int right = getWidth() + (int) (mExtraWidthForClipping + left);
@@ -248,9 +249,9 @@
     public void setDistanceToTopRoundness(float distanceToTopRoundness) {
         super.setDistanceToTopRoundness(distanceToTopRoundness);
         if (distanceToTopRoundness != mDistanceToTopRoundness) {
-            mClipRoundedToClipTopAmount = distanceToTopRoundness >= 0;
+            mTopAmountRounded = distanceToTopRoundness >= 0;
             mDistanceToTopRoundness = distanceToTopRoundness;
-            invalidate();
+            applyRoundness();
         }
     }
 
@@ -258,9 +259,12 @@
         return false;
     }
 
+    public boolean topAmountNeedsClipping() {
+        return true;
+    }
+
     protected boolean isClippingNeeded() {
         return mAlwaysRoundBothCorners || mCustomOutline || getTranslation() != 0 ;
-
     }
 
     private void initDimens() {
@@ -296,6 +300,11 @@
     }
 
     public float getCurrentBackgroundRadiusTop() {
+        // If this view is top amount notification view, it should always has round corners on top.
+        // It will be applied with applyRoundness()
+        if (mTopAmountRounded) {
+            return mOutlineRadius;
+        }
         return mCurrentTopRoundness * mOutlineRadius;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
index 0ff4dde..969e9d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
@@ -53,6 +53,9 @@
     private int mDrawableAlpha = 255;
     private boolean mIsPressedAllowed;
 
+    private boolean mTopAmountRounded;
+    private float mDistanceToTopRoundness;
+
     public NotificationBackgroundView(Context context, AttributeSet attrs) {
         super(context, attrs);
         mDontModifyCorners = getResources().getBoolean(
@@ -74,6 +77,7 @@
 
     private void draw(Canvas canvas, Drawable drawable) {
         if (drawable != null) {
+            int top = mBackgroundTop;
             int bottom = mActualHeight;
             if (mBottomIsRounded && mBottomAmountClips && !mExpandAnimationRunning) {
                 bottom -= mClipBottomAmount;
@@ -84,7 +88,14 @@
                 left = (int) ((getWidth() - mActualWidth) / 2.0f);
                 right = (int) (left + mActualWidth);
             }
-            drawable.setBounds(left, mBackgroundTop, right, bottom);
+            if (mTopAmountRounded) {
+                int clipTop = (int) (mClipTopAmount - mDistanceToTopRoundness);
+                top += clipTop;
+                if (clipTop >= 0) {
+                    bottom += clipTop;
+                }
+            }
+            drawable.setBounds(left, top, right, bottom);
             drawable.draw(canvas);
         }
     }
@@ -165,6 +176,14 @@
         invalidate();
     }
 
+    public void setDistanceToTopRoundness(float distanceToTopRoundness) {
+        if (distanceToTopRoundness != mDistanceToTopRoundness) {
+            mTopAmountRounded = distanceToTopRoundness >= 0;
+            mDistanceToTopRoundness = distanceToTopRoundness;
+            invalidate();
+        }
+    }
+
     @Override
     public boolean hasOverlappingRendering() {
 
@@ -198,6 +217,9 @@
     }
 
     public void setRoundness(float topRoundness, float bottomRoundNess) {
+        if (topRoundness == mCornerRadii[0] && bottomRoundNess == mCornerRadii[4]) {
+            return;
+        }
         mBottomIsRounded = bottomRoundNess != 0.0f;
         mCornerRadii[0] = topRoundness;
         mCornerRadii[1] = topRoundness;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
index aaf1989..a49d507a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.car;
 
+import static android.content.DialogInterface.BUTTON_NEGATIVE;
 import static android.content.DialogInterface.BUTTON_POSITIVE;
 
 import android.app.AlertDialog;
@@ -27,7 +28,6 @@
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.os.AsyncTask;
-import android.os.UserHandle;
 import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
 import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
 import android.support.v7.widget.RecyclerView;
@@ -167,6 +167,9 @@
         private AlertDialog mDialog;
         // View that holds the add user button.  Used to enable/disable the view
         private View mAddUserView;
+        // User record for the add user.  Need to call notifyUserSelected only if the user
+        // confirms adding a user
+        private UserRecord mAddUserRecord;
 
         public UserAdapter(Context context, List<UserRecord> users) {
             mRes = context.getResources();
@@ -201,18 +204,16 @@
             circleIcon.setCircular(true);
             holder.mUserAvatarImageView.setImageDrawable(circleIcon);
             holder.mUserNameTextView.setText(userRecord.mInfo.name);
+
             holder.mView.setOnClickListener(v -> {
                 if (userRecord == null) {
                     return;
                 }
 
-                // Notify the listener which user was selected
-                if (mUserSelectionListener != null) {
-                    mUserSelectionListener.onUserSelected(userRecord);
-                }
 
                 // If the user selects Guest, start the guest session.
                 if (userRecord.mIsStartGuestSession) {
+                    notifyUserSelected(userRecord);
                     mUserManagerHelper.startNewGuestSession(mGuestName);
                     return;
                 }
@@ -228,6 +229,7 @@
                         .concat(System.getProperty("line.separator"))
                         .concat(mRes.getString(R.string.user_add_user_message_update));
 
+                    mAddUserRecord = userRecord;
                     mDialog = new Builder(mContext, R.style.Theme_Car_Dark_Dialog_Alert)
                         .setTitle(R.string.user_add_user_title)
                         .setMessage(message)
@@ -240,11 +242,19 @@
                     return;
                 }
                 // If the user doesn't want to be a guest or add a user, switch to the user selected
+                notifyUserSelected(userRecord);
                 mUserManagerHelper.switchToUser(userRecord.mInfo);
             });
 
         }
 
+        private void notifyUserSelected(UserRecord userRecord) {
+            // Notify the listener which user was selected
+            if (mUserSelectionListener != null) {
+                mUserSelectionListener.onUserSelected(userRecord);
+            }
+        }
+
         private Bitmap getUserRecordIcon(UserRecord userRecord) {
             if (userRecord.mIsStartGuestSession) {
                 return mUserManagerHelper.getGuestDefaultIcon();
@@ -260,12 +270,14 @@
 
         @Override
         public void onClick(DialogInterface dialog, int which) {
-            // Enable the add button
-            if (mAddUserView != null) {
-                mAddUserView.setEnabled(true);
-            }
             if (which == BUTTON_POSITIVE) {
+                notifyUserSelected(mAddUserRecord);
                 new AddNewUserTask().execute(mNewUserName);
+            } else if (which == BUTTON_NEGATIVE) {
+                // Enable the add button only if cancel
+                if (mAddUserView != null) {
+                    mAddUserView.setEnabled(true);
+                }
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 6011712..704e963 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -604,6 +604,7 @@
         }
 
         updateNavButtonIcons();
+        updateSlippery();
     }
 
     public void updateNavButtonIcons() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index a2b33fa..7410069 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -760,7 +760,9 @@
     }
 
     private void updateClippingToTopRoundedCorner() {
-        Float clipStart = (float) mTopPadding + mAmbientState.getExpandAnimationTopChange();
+        Float clipStart = (float) mTopPadding
+                                 + mStackTranslation
+                                 + mAmbientState.getExpandAnimationTopChange();
         Float clipEnd = clipStart + mCornerRadius;
         boolean first = true;
         for (int i = 0; i < getChildCount(); i++) {
@@ -769,8 +771,7 @@
                 continue;
             }
             float start = child.getTranslationY();
-            float end = start + Math.max(child.getActualHeight() - child.getClipBottomAmount(),
-                    0);
+            float end = start + child.getActualHeight();
             boolean clip = clipStart > start && clipStart < end
                     || clipEnd >= start && clipEnd <= end;
             clip &= !(first && mOwnScrollY == 0);
@@ -3292,6 +3293,16 @@
             if (!childWasSwipedOut) {
                 Rect clipBounds = child.getClipBounds();
                 childWasSwipedOut = clipBounds != null && clipBounds.height() == 0;
+
+                if (childWasSwipedOut && child instanceof ExpandableView) {
+                    // Clean up any potential transient views if the child has already been swiped
+                    // out, as we won't be animating it further (due to its height already being
+                    // clipped to 0.
+                    ViewGroup transientContainer = ((ExpandableView) child).getTransientContainer();
+                    if (transientContainer != null) {
+                        transientContainer.removeTransientView(child);
+                    }
+                }
             }
             int animationType = childWasSwipedOut
                     ? AnimationEvent.ANIMATION_TYPE_REMOVE_SWIPED_OUT
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index bf9ccb8..72f11e0 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -619,6 +619,9 @@
 
   // Number of RSSI polls with 'rssi'
   optional int32 count = 2;
+
+  // Beacon frequency of the channel in MHz
+  optional int32 frequency = 3;
 }
 
 // Number of occurrences of a specific alert reason value
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 67a16bd..c25f8ff 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -20548,7 +20548,7 @@
         IPackageManager pm = AppGlobals.getPackageManager();
         ApplicationInfo app = null;
         try {
-            app = pm.getApplicationInfo(packageName, 0, userId);
+            app = pm.getApplicationInfo(packageName, STOCK_PM_FLAGS, userId);
         } catch (RemoteException e) {
             // can't happen; package manager is process-local
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9886a07..d5f936b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -367,6 +367,7 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Predicate;
 
 /**
  * Keep track of all those APKs everywhere.
@@ -14258,28 +14259,50 @@
      * @param packageName The package holding {@link Manifest.permission#SUSPEND_APPS} permission
      * @param affectedUser The user for which the changes are taking place.
      */
-    void unsuspendForSuspendingPackage(String packageName, int affectedUser) {
+    void unsuspendForSuspendingPackage(final String packageName, int affectedUser) {
         final int[] userIds = (affectedUser == UserHandle.USER_ALL) ? sUserManager.getUserIds()
                 : new int[] {affectedUser};
         for (int userId : userIds) {
-            List<String> affectedPackages = new ArrayList<>();
-            synchronized (mPackages) {
-                for (PackageSetting ps : mSettings.mPackages.values()) {
-                    final PackageUserState pus = ps.readUserState(userId);
-                    if (pus.suspended && packageName.equals(pus.suspendingPackage)) {
-                        ps.setSuspended(false, null, null, null, null, userId);
-                        affectedPackages.add(ps.name);
-                    }
+            unsuspendForSuspendingPackages(packageName::equals, userId);
+        }
+    }
+
+    /**
+     * Immediately unsuspends any packages in the given users not suspended by the platform or root.
+     * To be called when a profile owner or a device owner is added.
+     *
+     * <p><b>Should not be used on a frequent code path</b> as it flushes state to disk
+     * synchronously
+     *
+     * @param userIds The users for which to unsuspend packages
+     */
+    void unsuspendForNonSystemSuspendingPackages(ArraySet<Integer> userIds) {
+        final int sz = userIds.size();
+        for (int i = 0; i < sz; i++) {
+            unsuspendForSuspendingPackages(
+                    (suspendingPackage) -> !PLATFORM_PACKAGE_NAME.equals(suspendingPackage),
+                    userIds.valueAt(i));
+        }
+    }
+
+    private void unsuspendForSuspendingPackages(Predicate<String> packagePredicate, int userId) {
+        final List<String> affectedPackages = new ArrayList<>();
+        synchronized (mPackages) {
+            for (PackageSetting ps : mSettings.mPackages.values()) {
+                final PackageUserState pus = ps.readUserState(userId);
+                if (pus.suspended && packagePredicate.test(pus.suspendingPackage)) {
+                    ps.setSuspended(false, null, null, null, null, userId);
+                    affectedPackages.add(ps.name);
                 }
             }
-            if (!affectedPackages.isEmpty()) {
-                final String[] packageArray = affectedPackages.toArray(
-                        new String[affectedPackages.size()]);
-                sendMyPackageSuspendedOrUnsuspended(packageArray, false, null, userId);
-                sendPackagesSuspendedForUser(packageArray, userId, false, null);
-                // Write package restrictions immediately to avoid an inconsistent state.
-                mSettings.writePackageRestrictionsLPr(userId);
-            }
+        }
+        if (!affectedPackages.isEmpty()) {
+            final String[] packageArray = affectedPackages.toArray(
+                    new String[affectedPackages.size()]);
+            sendMyPackageSuspendedOrUnsuspended(packageArray, false, null, userId);
+            sendPackagesSuspendedForUser(packageArray, userId, false, null);
+            // Write package restrictions immediately to avoid an inconsistent state.
+            mSettings.writePackageRestrictionsLPr(userId);
         }
     }
 
@@ -23977,6 +24000,18 @@
                 SparseArray<String> profileOwnerPackages) {
             mProtectedPackages.setDeviceAndProfileOwnerPackages(
                     deviceOwnerUserId, deviceOwnerPackage, profileOwnerPackages);
+
+            final ArraySet<Integer> usersWithPoOrDo = new ArraySet<>();
+            if (deviceOwnerPackage != null) {
+                usersWithPoOrDo.add(deviceOwnerUserId);
+            }
+            final int sz = profileOwnerPackages.size();
+            for (int i = 0; i < sz; i++) {
+                if (profileOwnerPackages.valueAt(i) != null) {
+                    usersWithPoOrDo.add(profileOwnerPackages.keyAt(i));
+                }
+            }
+            unsuspendForNonSystemSuspendingPackages(usersWithPoOrDo);
         }
 
         @Override
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 2ac9df9..a8efe81 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -70,7 +70,7 @@
     <uses-sdk android:minSdkVersion="1"
           android:targetSdkVersion="26"/>
 
-    <application>
+    <application android:testOnly="true">
         <uses-library android:name="android.test.runner" />
 
         <service android:name="com.android.server.accounts.TestAccountType1AuthenticatorService"
diff --git a/services/tests/servicestests/AndroidTest.xml b/services/tests/servicestests/AndroidTest.xml
index 8f989df..5ac68d4 100644
--- a/services/tests/servicestests/AndroidTest.xml
+++ b/services/tests/servicestests/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="test-suite-tag" value="apct-instrumentation" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
+        <option name="install-arg" value="-t" />
         <option name="test-file-name" value="FrameworksServicesTests.apk" />
         <option name="test-file-name" value="JobTestApp.apk" />
         <option name="test-file-name" value="ConnTestApp.apk" />
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 b8922eb..c186e48 100644
--- a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
@@ -22,6 +22,7 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
 
 import android.app.AppGlobals;
 import android.content.BroadcastReceiver;
@@ -59,6 +60,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.io.IOException;
 import java.util.Arrays;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.SynchronousQueue;
@@ -97,6 +99,9 @@
     private AppCommunicationReceiver mAppCommsReceiver;
     private StubbedCallback mTestCallback;
     private UiDevice mUiDevice;
+    private ComponentName mDeviceAdminComponent;
+    private boolean mPoSet;
+    private boolean mDoSet;
 
     private static final class AppCommunicationReceiver extends BroadcastReceiver {
         private Context context;
@@ -163,6 +168,8 @@
         mLauncherApps = (LauncherApps) mContext.getSystemService(Context.LAUNCHER_APPS_SERVICE);
         mReceiverHandler = new Handler(Looper.getMainLooper());
         mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+        mDeviceAdminComponent = new ComponentName(mContext,
+                "com.android.server.devicepolicy.DummyDeviceAdmins$Admin1");
         IPackageManager ipm = AppGlobals.getPackageManager();
         try {
             // Otherwise implicit broadcasts will not be delivered.
@@ -469,12 +476,83 @@
                 TEST_APP_PACKAGE_NAME, receivedPackageName);
     }
 
+    private boolean setProfileOwner() throws IOException {
+        final String result = mUiDevice.executeShellCommand("dpm set-profile-owner --user cur "
+                + mDeviceAdminComponent.flattenToString());
+        return mPoSet = result.trim().startsWith("Success");
+    }
+
+    private boolean setDeviceOwner() throws IOException {
+        final String result = mUiDevice.executeShellCommand("dpm set-device-owner --user cur "
+                + mDeviceAdminComponent.flattenToString());
+        return mDoSet = result.trim().startsWith("Success");
+    }
+
+    private void removeProfileOrDeviceOwner() throws IOException {
+        if (mPoSet || mDoSet) {
+            mUiDevice.executeShellCommand("dpm remove-active-admin --user cur "
+                    + mDeviceAdminComponent.flattenToString());
+            mPoSet = mDoSet = false;
+        }
+    }
+
+    @Test
+    public void testCannotSuspendWhenProfileOwner() throws IOException {
+        assumeTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN));
+        assertTrue("Profile-owner could not be set", setProfileOwner());
+        try {
+            suspendTestPackage(null, null, null);
+            fail("Suspend succeeded. Expected UnsupportedOperationException");
+        } catch (UnsupportedOperationException uex) {
+        }
+    }
+
+    @Test
+    public void testCannotSuspendWhenDeviceOwner() throws IOException {
+        assumeTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN));
+        assertTrue("Device-owner could not be set", setDeviceOwner());
+        try {
+            suspendTestPackage(null, null, null);
+            fail("Suspend succeeded. Expected UnsupportedOperationException");
+        } catch (UnsupportedOperationException uex) {
+        }
+    }
+
+    @Test
+    public void testPackageUnsuspendedOnAddingDeviceOwner() throws IOException {
+        assumeTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN));
+        mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_MY_PACKAGE_UNSUSPENDED,
+                ACTION_REPORT_MY_PACKAGE_SUSPENDED);
+        mAppCommsReceiver.drainPendingBroadcasts();
+        suspendTestPackage(null, null, null);
+        Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
+        assertEquals(ACTION_REPORT_MY_PACKAGE_SUSPENDED, intentFromApp.getAction());
+        assertTrue("Device-owner could not be set", setDeviceOwner());
+        intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
+        assertEquals(ACTION_REPORT_MY_PACKAGE_UNSUSPENDED, intentFromApp.getAction());
+    }
+
+    @Test
+    public void testPackageUnsuspendedOnAddingProfileOwner() throws IOException {
+        assumeTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN));
+        mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_MY_PACKAGE_UNSUSPENDED,
+                ACTION_REPORT_MY_PACKAGE_SUSPENDED);
+        mAppCommsReceiver.drainPendingBroadcasts();
+        suspendTestPackage(null, null, null);
+        Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
+        assertEquals(ACTION_REPORT_MY_PACKAGE_SUSPENDED, intentFromApp.getAction());
+        assertTrue("Profile-owner could not be set", setProfileOwner());
+        intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
+        assertEquals(ACTION_REPORT_MY_PACKAGE_UNSUSPENDED, intentFromApp.getAction());
+    }
+
     @After
-    public void tearDown() {
+    public void tearDown() throws IOException {
         mAppCommsReceiver.unregister();
         if (mTestCallback != null) {
             mLauncherApps.unregisterCallback(mTestCallback);
         }
+        removeProfileOrDeviceOwner();
         mContext.sendBroadcast(new Intent(ACTION_FINISH_TEST_ACTIVITY)
                 .setPackage(TEST_APP_PACKAGE_NAME));
     }
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 7d42eb3..6311127a 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -699,6 +699,29 @@
                     == PackageManager.PERMISSION_GRANTED;
         }
 
+        private void checkCallerIsSystemOrSameApp(String pkg) {
+            if (isCallingUidSystem()) {
+                return;
+            }
+            checkCallerIsSameApp(pkg);
+        }
+
+        private void checkCallerIsSameApp(String pkg) {
+            final int callingUid = Binder.getCallingUid();
+            final int callingUserId = UserHandle.getUserId(callingUid);
+
+            if (mPackageManagerInternal.getPackageUid(pkg, PackageManager.MATCH_ANY_USER,
+                    callingUserId) != callingUid) {
+                throw new SecurityException("Calling uid " + pkg + " cannot query events"
+                        + "for package " + pkg);
+            }
+        }
+
+        private boolean isCallingUidSystem() {
+            final int uid = Binder.getCallingUid();
+            return uid == Process.SYSTEM_UID;
+        }
+
         @Override
         public ParceledListSlice<UsageStats> queryUsageStats(int bucketType, long beginTime,
                 long endTime, String callingPackage) {
@@ -792,11 +815,7 @@
             final int callingUid = Binder.getCallingUid();
             final int callingUserId = UserHandle.getUserId(callingUid);
 
-            if (mPackageManagerInternal.getPackageUid(callingPackage, PackageManager.MATCH_ANY_USER,
-                    callingUserId) != callingUid) {
-                throw new SecurityException("Calling uid " + callingPackage + " cannot query events"
-                        + "for package " + callingPackage);
-            }
+            checkCallerIsSameApp(callingPackage);
             final long token = Binder.clearCallingIdentity();
             try {
                 return UsageStatsService.this.queryEventsForPackage(callingUserId, beginTime,
@@ -807,6 +826,53 @@
         }
 
         @Override
+        public UsageEvents queryEventsForUser(long beginTime, long endTime, int userId,
+                String callingPackage) {
+            if (!hasPermission(callingPackage)) {
+                return null;
+            }
+
+            if (userId != UserHandle.getCallingUserId()) {
+                getContext().enforceCallingPermission(
+                        Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                        "No permission to query usage stats for this user");
+            }
+
+            final boolean obfuscateInstantApps = shouldObfuscateInstantAppsForCaller(
+                    Binder.getCallingUid(), UserHandle.getCallingUserId());
+
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return UsageStatsService.this.queryEvents(userId, beginTime, endTime,
+                        obfuscateInstantApps);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public UsageEvents queryEventsForPackageForUser(long beginTime, long endTime,
+                int userId, String pkg, String callingPackage) {
+            if (!hasPermission(callingPackage)) {
+                return null;
+            }
+            if (userId != UserHandle.getCallingUserId()) {
+                getContext().enforceCallingPermission(
+                        Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                        "No permission to query usage stats for this user");
+            }
+            checkCallerIsSystemOrSameApp(pkg);
+
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return UsageStatsService.this.queryEventsForPackage(userId, beginTime,
+                        endTime, callingPackage);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
         public boolean isAppInactive(String packageName, int userId) {
             try {
                 userId = ActivityManager.getService().handleIncomingUser(Binder.getCallingPid(),