Merge "IBatteryPropertiesRegistrar: remove unused functions" into stage-aosp-master
am: b9fa97dff7

Change-Id: I55e25e25612cbb11cec025ba21b6577d635f1df9
diff --git a/Android.bp b/Android.bp
index ec5cbc3..c315fb4 100644
--- a/Android.bp
+++ b/Android.bp
@@ -771,6 +771,24 @@
     dxflags: ["--core-library"],
 }
 
+// ====  java proto host library  ==============================
+java_library_host {
+    name: "platformprotos",
+    srcs: [
+        "cmds/am/proto/instrumentation_data.proto",
+        "core/proto/**/*.proto",
+        "libs/incident/proto/**/*.proto",
+        "cmds/statsd/src/**/*.proto",
+    ],
+    proto: {
+        include_dirs: ["external/protobuf/src"],
+        type: "full",
+    },
+    errorprone: {
+        javacflags: ["-Xep:MissingOverride:OFF"],  // b/72714520
+    },
+}
+
 // ====  c++ proto device library  ==============================
 cc_library {
     name: "libplatformprotos",
@@ -1229,11 +1247,6 @@
 doc_defaults {
     name: "metalava-framework-docs-default",
     srcs: [
-        // test mock src files.
-        "test-mock/src/android/test/mock/**/*.java",
-        // test runner excluding mock src files.
-        "test-runner/src/**/*.java",
-        "test-base/src/**/*.java",
         ":opt-telephony-srcs",
         ":opt-net-voip-srcs",
         ":openjdk_javadoc_files",
diff --git a/Android.mk b/Android.mk
index 46c1201..7890983 100644
--- a/Android.mk
+++ b/Android.mk
@@ -670,23 +670,6 @@
 
 include $(BUILD_DROIDDOC)
 
-# ====  java proto host library  ==============================
-include $(CLEAR_VARS)
-LOCAL_MODULE := platformprotos
-LOCAL_PROTOC_OPTIMIZE_TYPE := full
-LOCAL_PROTOC_FLAGS := \
-    -Iexternal/protobuf/src
-LOCAL_SOURCE_FILES_ALL_GENERATED := true
-LOCAL_SRC_FILES := \
-    cmds/am/proto/instrumentation_data.proto \
-    cmds/statsd/src/perfetto/perfetto_config.proto \
-    $(call all-proto-files-under, core/proto) \
-    $(call all-proto-files-under, libs/incident/proto) \
-    $(call all-proto-files-under, cmds/statsd/src)
-# b/72714520
-LOCAL_ERROR_PRONE_FLAGS := -Xep:MissingOverride:OFF
-include $(BUILD_HOST_JAVA_LIBRARY)
-
 # ====  java proto device library (for test only)  ==============================
 include $(CLEAR_VARS)
 LOCAL_MODULE := platformprotosnano
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index fda4f4b..cbbe915 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -137,6 +137,7 @@
 Landroid/app/ActivityManager$StackInfo;->visible:Z
 Landroid/app/ActivityManager$TaskDescription;->getBackgroundColor()I
 Landroid/app/ActivityManager$TaskDescription;->getInMemoryIcon()Landroid/graphics/Bitmap;
+Landroid/app/ActivityManager$TaskDescription;->setIcon(Landroid/graphics/Bitmap;)V
 Landroid/app/ActivityManager$TaskSnapshot;->getContentInsets()Landroid/graphics/Rect;
 Landroid/app/ActivityManager$TaskSnapshot;->getOrientation()I
 Landroid/app/ActivityManager$TaskSnapshot;->getScale()F
@@ -904,6 +905,7 @@
 Landroid/app/SearchableInfo$ActionKeyInfo;->getQueryActionMsg()Ljava/lang/String;
 Landroid/app/SearchableInfo$ActionKeyInfo;->getSuggestActionMsg()Ljava/lang/String;
 Landroid/app/SearchableInfo$ActionKeyInfo;->getSuggestActionMsgColumn()Ljava/lang/String;
+Landroid/app/SearchableInfo;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;Landroid/content/ComponentName;)V
 Landroid/app/SearchableInfo;->findActionKey(I)Landroid/app/SearchableInfo$ActionKeyInfo;
 Landroid/app/SearchableInfo;->getActivityContext(Landroid/content/Context;)Landroid/content/Context;
 Landroid/app/SearchableInfo;->getIconId()I
@@ -1243,6 +1245,7 @@
 Landroid/bluetooth/IBluetooth$Stub;-><init>()V
 Landroid/bluetooth/IBluetooth$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetooth;
 Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_enable:I
+Landroid/bluetooth/IBluetooth;->fetchRemoteUuids(Landroid/bluetooth/BluetoothDevice;)Z
 Landroid/bluetooth/IBluetooth;->getAddress()Ljava/lang/String;
 Landroid/bluetooth/IBluetooth;->getRemoteAlias(Landroid/bluetooth/BluetoothDevice;)Ljava/lang/String;
 Landroid/bluetooth/IBluetooth;->isEnabled()Z
@@ -1514,8 +1517,11 @@
 Landroid/content/pm/IPackageInstallObserver2;->onPackageInstalled(Ljava/lang/String;ILjava/lang/String;Landroid/os/Bundle;)V
 Landroid/content/pm/IPackageInstallObserver2;->onUserActionRequired(Landroid/content/Intent;)V
 Landroid/content/pm/IPackageManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+Landroid/content/pm/IPackageManager$Stub$Proxy;->checkUidPermission(Ljava/lang/String;I)I
+Landroid/content/pm/IPackageManager$Stub$Proxy;->getAppOpPermissionPackages(Ljava/lang/String;)[Ljava/lang/String;
 Landroid/content/pm/IPackageManager$Stub$Proxy;->getInstalledPackages(II)Landroid/content/pm/ParceledListSlice;
 Landroid/content/pm/IPackageManager$Stub$Proxy;->getInstallLocation()I
+Landroid/content/pm/IPackageManager$Stub$Proxy;->getLastChosenActivity(Landroid/content/Intent;Ljava/lang/String;I)Landroid/content/pm/ResolveInfo;
 Landroid/content/pm/IPackageManager$Stub$Proxy;->getPackageInfo(Ljava/lang/String;II)Landroid/content/pm/PackageInfo;
 Landroid/content/pm/IPackageManager$Stub$Proxy;->getPackagesForUid(I)[Ljava/lang/String;
 Landroid/content/pm/IPackageManager$Stub$Proxy;->getSystemSharedLibraryNames()[Ljava/lang/String;
@@ -1534,6 +1540,7 @@
 Landroid/content/pm/IPackageManager;->deleteApplicationCacheFiles(Ljava/lang/String;Landroid/content/pm/IPackageDataObserver;)V
 Landroid/content/pm/IPackageManager;->enterSafeMode()V
 Landroid/content/pm/IPackageManager;->getApplicationEnabledSetting(Ljava/lang/String;I)I
+Landroid/content/pm/IPackageManager;->getAppOpPermissionPackages(Ljava/lang/String;)[Ljava/lang/String;
 Landroid/content/pm/IPackageManager;->getBlockUninstallForUser(Ljava/lang/String;I)Z
 Landroid/content/pm/IPackageManager;->getComponentEnabledSetting(Landroid/content/ComponentName;I)I
 Landroid/content/pm/IPackageManager;->getFlagsForUid(I)I
@@ -1745,6 +1752,7 @@
 Landroid/content/pm/PackageParser;->collectCertificates(Landroid/content/pm/PackageParser$Package;Ljava/io/File;Z)V
 Landroid/content/pm/PackageParser;->collectCertificates(Landroid/content/pm/PackageParser$Package;Z)V
 Landroid/content/pm/PackageParser;->generateActivityInfo(Landroid/content/pm/PackageParser$Activity;ILandroid/content/pm/PackageUserState;I)Landroid/content/pm/ActivityInfo;
+Landroid/content/pm/PackageParser;->generateApplicationInfo(Landroid/content/pm/PackageParser$Package;ILandroid/content/pm/PackageUserState;)Landroid/content/pm/ApplicationInfo;
 Landroid/content/pm/PackageParser;->generateApplicationInfo(Landroid/content/pm/PackageParser$Package;ILandroid/content/pm/PackageUserState;I)Landroid/content/pm/ApplicationInfo;
 Landroid/content/pm/PackageParser;->generateInstrumentationInfo(Landroid/content/pm/PackageParser$Instrumentation;I)Landroid/content/pm/InstrumentationInfo;
 Landroid/content/pm/PackageParser;->generatePackageInfo(Landroid/content/pm/PackageParser$Package;[IIJJLjava/util/Set;Landroid/content/pm/PackageUserState;)Landroid/content/pm/PackageInfo;
@@ -1756,6 +1764,7 @@
 Landroid/content/pm/PackageParser;->mCallback:Landroid/content/pm/PackageParser$Callback;
 Landroid/content/pm/PackageParser;->NEW_PERMISSIONS:[Landroid/content/pm/PackageParser$NewPermissionInfo;
 Landroid/content/pm/PackageParser;->parseBaseApk(Ljava/lang/String;Landroid/content/res/Resources;Landroid/content/res/XmlResourceParser;I[Ljava/lang/String;)Landroid/content/pm/PackageParser$Package;
+Landroid/content/pm/PackageParser;->parseBaseApplication(Landroid/content/pm/PackageParser$Package;Landroid/content/res/Resources;Landroid/content/res/XmlResourceParser;I[Ljava/lang/String;)Z
 Landroid/content/pm/PackageParser;->parseMonolithicPackage(Ljava/io/File;I)Landroid/content/pm/PackageParser$Package;
 Landroid/content/pm/PackageParser;->parsePackage(Ljava/io/File;I)Landroid/content/pm/PackageParser$Package;
 Landroid/content/pm/PackageParser;->parsePackage(Ljava/io/File;IZ)Landroid/content/pm/PackageParser$Package;
@@ -1803,6 +1812,7 @@
 Landroid/content/pm/VerifierInfo;-><init>(Ljava/lang/String;Ljava/security/PublicKey;)V
 Landroid/content/pm/XmlSerializerAndParser;->createFromXml(Lorg/xmlpull/v1/XmlPullParser;)Ljava/lang/Object;
 Landroid/content/pm/XmlSerializerAndParser;->writeAsXml(Ljava/lang/Object;Lorg/xmlpull/v1/XmlSerializer;)V
+Landroid/content/res/ApkAssets;->getAssetPath()Ljava/lang/String;
 Landroid/content/res/AssetFileDescriptor;->mFd:Landroid/os/ParcelFileDescriptor;
 Landroid/content/res/AssetFileDescriptor;->mLength:J
 Landroid/content/res/AssetFileDescriptor;->mStartOffset:J
@@ -1814,6 +1824,7 @@
 Landroid/content/res/AssetManager;->addOverlayPath(Ljava/lang/String;)I
 Landroid/content/res/AssetManager;->applyStyle(JIILandroid/content/res/XmlBlock$Parser;[IJJ)V
 Landroid/content/res/AssetManager;->createTheme()J
+Landroid/content/res/AssetManager;->getApkAssets()[Landroid/content/res/ApkAssets;
 Landroid/content/res/AssetManager;->getAssignedPackageIdentifiers()Landroid/util/SparseArray;
 Landroid/content/res/AssetManager;->getGlobalAssetCount()I
 Landroid/content/res/AssetManager;->getGlobalAssetManagerCount()I
@@ -1837,6 +1848,7 @@
 Landroid/content/res/AssetManager;->setConfiguration(IILjava/lang/String;IIIIIIIIIIIIIII)V
 Landroid/content/res/AssetManager;->sSystem:Landroid/content/res/AssetManager;
 Landroid/content/res/ColorStateList$ColorStateListFactory;-><init>(Landroid/content/res/ColorStateList;)V
+Landroid/content/res/ColorStateList;-><init>()V
 Landroid/content/res/ColorStateList;->canApplyTheme()Z
 Landroid/content/res/ColorStateList;->getColors()[I
 Landroid/content/res/ColorStateList;->getStates()[[I
@@ -1899,6 +1911,7 @@
 Landroid/content/res/Resources;->updateSystemConfiguration(Landroid/content/res/Configuration;Landroid/util/DisplayMetrics;Landroid/content/res/CompatibilityInfo;)V
 Landroid/content/res/ResourcesImpl;-><init>(Landroid/content/res/AssetManager;Landroid/util/DisplayMetrics;Landroid/content/res/Configuration;Landroid/view/DisplayAdjustments;)V
 Landroid/content/res/ResourcesImpl;->getAssets()Landroid/content/res/AssetManager;
+Landroid/content/res/ResourcesImpl;->getDisplayMetrics()Landroid/util/DisplayMetrics;
 Landroid/content/res/ResourcesImpl;->getValue(ILandroid/util/TypedValue;Z)V
 Landroid/content/res/ResourcesImpl;->mAccessLock:Ljava/lang/Object;
 Landroid/content/res/ResourcesImpl;->mAnimatorCache:Landroid/content/res/ConfigurationBoundResourceCache;
@@ -2158,6 +2171,7 @@
 Landroid/graphics/CanvasProperty;->createPaint(Landroid/graphics/Paint;)Landroid/graphics/CanvasProperty;
 Landroid/graphics/ColorMatrixColorFilter;->mMatrix:Landroid/graphics/ColorMatrix;
 Landroid/graphics/ColorMatrixColorFilter;->setColorMatrix(Landroid/graphics/ColorMatrix;)V
+Landroid/graphics/ColorMatrixColorFilter;->setColorMatrixArray([F)V
 Landroid/graphics/drawable/AnimatedImageDrawable;->onAnimationEnd()V
 Landroid/graphics/drawable/AnimatedRotateDrawable;->setFramesCount(I)V
 Landroid/graphics/drawable/AnimatedRotateDrawable;->setFramesDuration(I)V
@@ -4189,6 +4203,7 @@
 Landroid/os/SELinux;->restoreconRecursive(Ljava/io/File;)Z
 Landroid/os/ServiceManager;-><init>()V
 Landroid/os/ServiceManager;->addService(Ljava/lang/String;Landroid/os/IBinder;)V
+Landroid/os/ServiceManager;->addService(Ljava/lang/String;Landroid/os/IBinder;Z)V
 Landroid/os/ServiceManager;->addService(Ljava/lang/String;Landroid/os/IBinder;ZI)V
 Landroid/os/ServiceManager;->checkService(Ljava/lang/String;)Landroid/os/IBinder;
 Landroid/os/ServiceManager;->getIServiceManager()Landroid/os/IServiceManager;
@@ -4273,6 +4288,7 @@
 Landroid/os/storage/VolumeInfo;->getDiskId()Ljava/lang/String;
 Landroid/os/storage/VolumeInfo;->getEnvironmentForState(I)Ljava/lang/String;
 Landroid/os/storage/VolumeInfo;->getFsUuid()Ljava/lang/String;
+Landroid/os/storage/VolumeInfo;->getInternalPath()Ljava/io/File;
 Landroid/os/storage/VolumeInfo;->getInternalPathForUser(I)Ljava/io/File;
 Landroid/os/storage/VolumeInfo;->getMountUserId()I
 Landroid/os/storage/VolumeInfo;->getPath()Ljava/io/File;
@@ -4308,6 +4324,7 @@
 Landroid/os/StrictMode;->sLastVmViolationTime:Ljava/util/HashMap;
 Landroid/os/StrictMode;->sWindowManager:Landroid/util/Singleton;
 Landroid/os/StrictMode;->violationsBeingTimed:Ljava/lang/ThreadLocal;
+Landroid/os/SystemClock;-><init>()V
 Landroid/os/SystemClock;->currentThreadTimeMicro()J
 Landroid/os/SystemClock;->currentTimeMicro()J
 Landroid/os/SystemProperties;-><init>()V
@@ -4393,6 +4410,7 @@
 Landroid/os/UserManager;->getUserStartRealtime()J
 Landroid/os/UserManager;->getUserUnlockRealtime()J
 Landroid/os/UserManager;->hasBaseUserRestriction(Ljava/lang/String;Landroid/os/UserHandle;)Z
+Landroid/os/UserManager;->isDeviceInDemoMode(Landroid/content/Context;)Z
 Landroid/os/UserManager;->isGuestUser(I)Z
 Landroid/os/UserManager;->isLinkedUser()Z
 Landroid/os/UserManager;->isUserAdmin(I)Z
@@ -4598,6 +4616,7 @@
 Landroid/provider/Settings$Global;->ZEN_MODE_IMPORTANT_INTERRUPTIONS:I
 Landroid/provider/Settings$Global;->ZEN_MODE_NO_INTERRUPTIONS:I
 Landroid/provider/Settings$Global;->ZEN_MODE_OFF:I
+Landroid/provider/Settings$NameValueCache;->getStringForUser(Landroid/content/ContentResolver;Ljava/lang/String;I)Ljava/lang/String;
 Landroid/provider/Settings$NameValueCache;->mProviderHolder:Landroid/provider/Settings$ContentProviderHolder;
 Landroid/provider/Settings$Secure;->ACCESSIBILITY_AUTOCLICK_ENABLED:Ljava/lang/String;
 Landroid/provider/Settings$Secure;->ACCESSIBILITY_CAPTIONING_TYPEFACE:Ljava/lang/String;
@@ -4636,10 +4655,12 @@
 Landroid/provider/Settings$Secure;->SETTINGS_TO_BACKUP:[Ljava/lang/String;
 Landroid/provider/Settings$Secure;->SMS_DEFAULT_APPLICATION:Ljava/lang/String;
 Landroid/provider/Settings$Secure;->sNameValueCache:Landroid/provider/Settings$NameValueCache;
+Landroid/provider/Settings$Secure;->sProviderHolder:Landroid/provider/Settings$ContentProviderHolder;
 Landroid/provider/Settings$Secure;->VOICE_RECOGNITION_SERVICE:Ljava/lang/String;
 Landroid/provider/Settings$System;->AIRPLANE_MODE_TOGGLEABLE_RADIOS:Ljava/lang/String;
 Landroid/provider/Settings$System;->CAR_DOCK_SOUND:Ljava/lang/String;
 Landroid/provider/Settings$System;->CAR_UNDOCK_SOUND:Ljava/lang/String;
+Landroid/provider/Settings$System;->CLONE_TO_MANAGED_PROFILE:Ljava/util/Set;
 Landroid/provider/Settings$System;->DESK_DOCK_SOUND:Ljava/lang/String;
 Landroid/provider/Settings$System;->DESK_UNDOCK_SOUND:Ljava/lang/String;
 Landroid/provider/Settings$System;->DOCK_SOUNDS_ENABLED:Ljava/lang/String;
@@ -4651,6 +4672,9 @@
 Landroid/provider/Settings$System;->LOCKSCREEN_SOUNDS_ENABLED:Ljava/lang/String;
 Landroid/provider/Settings$System;->LOCK_SOUND:Ljava/lang/String;
 Landroid/provider/Settings$System;->MASTER_MONO:Ljava/lang/String;
+Landroid/provider/Settings$System;->MOVED_TO_GLOBAL:Ljava/util/HashSet;
+Landroid/provider/Settings$System;->MOVED_TO_SECURE:Ljava/util/HashSet;
+Landroid/provider/Settings$System;->MOVED_TO_SECURE_THEN_GLOBAL:Ljava/util/HashSet;
 Landroid/provider/Settings$System;->NOTIFICATION_LIGHT_PULSE:Ljava/lang/String;
 Landroid/provider/Settings$System;->POINTER_LOCATION:Ljava/lang/String;
 Landroid/provider/Settings$System;->POINTER_SPEED:Ljava/lang/String;
@@ -4665,6 +4689,7 @@
 Landroid/provider/Settings$System;->sProviderHolder:Landroid/provider/Settings$ContentProviderHolder;
 Landroid/provider/Settings$System;->TTY_MODE:Ljava/lang/String;
 Landroid/provider/Settings$System;->UNLOCK_SOUND:Ljava/lang/String;
+Landroid/provider/Settings$System;->VALIDATORS:Ljava/util/Map;
 Landroid/provider/Settings$System;->VIBRATE_IN_SILENT:Ljava/lang/String;
 Landroid/provider/Settings;->ACTION_TRUSTED_CREDENTIALS_USER:Ljava/lang/String;
 Landroid/provider/Settings;->ACTION_USER_DICTIONARY_INSERT:Ljava/lang/String;
@@ -5408,6 +5433,7 @@
 Landroid/telephony/ServiceState;->mCdmaRoamingIndicator:I
 Landroid/telephony/ServiceState;->mCssIndicator:Z
 Landroid/telephony/ServiceState;->mIsManualNetworkSelection:Z
+Landroid/telephony/ServiceState;->mIsUsingCarrierAggregation:Z
 Landroid/telephony/ServiceState;->mNetworkId:I
 Landroid/telephony/ServiceState;->mSystemId:I
 Landroid/telephony/ServiceState;->newFromBundle(Landroid/os/Bundle;)Landroid/telephony/ServiceState;
@@ -5773,6 +5799,7 @@
 Landroid/transition/Scene;->setCurrentScene(Landroid/view/View;Landroid/transition/Scene;)V
 Landroid/transition/Transition;->cancel()V
 Landroid/transition/Transition;->end()V
+Landroid/transition/Transition;->getRunningAnimators()Landroid/util/ArrayMap;
 Landroid/transition/TransitionManager;->getRunningTransitions()Landroid/util/ArrayMap;
 Landroid/transition/TransitionManager;->sPendingTransitions:Ljava/util/ArrayList;
 Landroid/transition/TransitionManager;->sRunningTransitions:Ljava/lang/ThreadLocal;
@@ -6220,6 +6247,7 @@
 Landroid/view/SurfaceControl;->HIDDEN:I
 Landroid/view/SurfaceControl;->hide()V
 Landroid/view/SurfaceControl;->openTransaction()V
+Landroid/view/SurfaceControl;->screenshot(Landroid/graphics/Rect;III)Landroid/graphics/Bitmap;
 Landroid/view/SurfaceControl;->screenshot(Landroid/graphics/Rect;IIIIZI)Landroid/graphics/Bitmap;
 Landroid/view/SurfaceControl;->screenshot(Landroid/os/IBinder;Landroid/view/Surface;Landroid/graphics/Rect;IIIIZZ)V
 Landroid/view/SurfaceControl;->setDisplayLayerStack(Landroid/os/IBinder;I)V
@@ -7013,6 +7041,7 @@
 Landroid/widget/ListView;->fillSpecific(II)Landroid/view/View;
 Landroid/widget/ListView;->fillUp(II)Landroid/view/View;
 Landroid/widget/ListView;->getHeightForPosition(I)I
+Landroid/widget/ListView;->isDirectChildHeaderOrFooter(Landroid/view/View;)Z
 Landroid/widget/ListView;->makeAndAddView(IIZIZ)Landroid/view/View;
 Landroid/widget/ListView;->mAreAllItemsSelectable:Z
 Landroid/widget/ListView;->mDivider:Landroid/graphics/drawable/Drawable;
@@ -7561,6 +7590,7 @@
 Lcom/android/internal/appwidget/IAppWidgetService;->bindAppWidgetId(Ljava/lang/String;IILandroid/content/ComponentName;Landroid/os/Bundle;)Z
 Lcom/android/internal/appwidget/IAppWidgetService;->bindRemoteViewsService(Ljava/lang/String;ILandroid/content/Intent;Landroid/app/IApplicationThread;Landroid/os/IBinder;Landroid/app/IServiceConnection;I)Z
 Lcom/android/internal/appwidget/IAppWidgetService;->getAppWidgetIds(Landroid/content/ComponentName;)[I
+Lcom/android/internal/appwidget/IAppWidgetService;->getAppWidgetViews(Ljava/lang/String;I)Landroid/widget/RemoteViews;
 Lcom/android/internal/backup/IBackupTransport$Stub;-><init>()V
 Lcom/android/internal/backup/IBackupTransport$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/backup/IBackupTransport;
 Lcom/android/internal/backup/IBackupTransport;->clearBackupData(Landroid/content/pm/PackageInfo;)I
@@ -7777,6 +7807,9 @@
 Lcom/android/internal/R$attr;->text:I
 Lcom/android/internal/R$attr;->title:I
 Lcom/android/internal/R$attr;->webViewStyle:I
+Lcom/android/internal/R$bool;-><init>()V
+Lcom/android/internal/R$bool;->config_automatic_brightness_available:I
+Lcom/android/internal/R$bool;->config_intrusiveNotificationLed:I
 Lcom/android/internal/R$bool;->config_mms_content_disposition_support:I
 Lcom/android/internal/R$bool;->config_showNavigationBar:I
 Lcom/android/internal/R$dimen;-><init>()V
@@ -8200,6 +8233,8 @@
 Lcom/android/internal/R$styleable;->Window:[I
 Lcom/android/internal/R$styleable;->WindowAnimation:[I
 Lcom/android/internal/R$styleable;->Window_windowActionBarFullscreenDecorLayout:I
+Lcom/android/internal/R$styleable;->Window_windowBackground:I
+Lcom/android/internal/R$styleable;->Window_windowFullscreen:I
 Lcom/android/internal/R$styleable;->Window_windowIsFloating:I
 Lcom/android/internal/R$styleable;->Window_windowIsTranslucent:I
 Lcom/android/internal/R$styleable;->Window_windowShowWallpaper:I
@@ -8269,6 +8304,7 @@
 Lcom/android/internal/telephony/IPhoneStateListener;->onSignalStrengthChanged(I)V
 Lcom/android/internal/telephony/IPhoneStateListener;->onSignalStrengthsChanged(Landroid/telephony/SignalStrength;)V
 Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;->getDeviceId(Ljava/lang/String;)Ljava/lang/String;
 Lcom/android/internal/telephony/IPhoneSubInfo$Stub;-><init>()V
 Lcom/android/internal/telephony/IPhoneSubInfo$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IPhoneSubInfo;
 Lcom/android/internal/telephony/IPhoneSubInfo$Stub;->TRANSACTION_getDeviceId:I
@@ -8454,6 +8490,8 @@
 Lcom/android/internal/view/menu/MenuBuilder;->addMenuPresenter(Lcom/android/internal/view/menu/MenuPresenter;Landroid/content/Context;)V
 Lcom/android/internal/view/menu/MenuBuilder;->collapseItemActionView(Lcom/android/internal/view/menu/MenuItemImpl;)Z
 Lcom/android/internal/view/menu/MenuBuilder;->getContext()Landroid/content/Context;
+Lcom/android/internal/view/menu/MenuBuilder;->getHeaderIcon()Landroid/graphics/drawable/Drawable;
+Lcom/android/internal/view/menu/MenuBuilder;->getHeaderTitle()Ljava/lang/CharSequence;
 Lcom/android/internal/view/menu/MenuBuilder;->getNonActionItems()Ljava/util/ArrayList;
 Lcom/android/internal/view/menu/MenuBuilder;->getRootMenu()Lcom/android/internal/view/menu/MenuBuilder;
 Lcom/android/internal/view/menu/MenuBuilder;->getVisibleItems()Ljava/util/ArrayList;
@@ -8471,11 +8509,14 @@
 Lcom/android/internal/view/menu/MenuItemImpl;->requestsActionButton()Z
 Lcom/android/internal/view/menu/MenuItemImpl;->requiresActionButton()Z
 Lcom/android/internal/view/menu/MenuItemImpl;->setActionViewExpanded(Z)V
+Lcom/android/internal/view/menu/MenuItemImpl;->setExclusiveCheckable(Z)V
 Lcom/android/internal/view/menu/MenuItemImpl;->setMenuInfo(Landroid/view/ContextMenu$ContextMenuInfo;)V
 Lcom/android/internal/view/menu/MenuPopupHelper;-><init>(Landroid/content/Context;Lcom/android/internal/view/menu/MenuBuilder;)V
 Lcom/android/internal/view/menu/MenuPopupHelper;-><init>(Landroid/content/Context;Lcom/android/internal/view/menu/MenuBuilder;Landroid/view/View;)V
 Lcom/android/internal/view/menu/MenuPopupHelper;->dismiss()V
+Lcom/android/internal/view/menu/MenuPopupHelper;->getPopup()Lcom/android/internal/view/menu/MenuPopup;
 Lcom/android/internal/view/menu/MenuPopupHelper;->mForceShowIcon:Z
+Lcom/android/internal/view/menu/MenuPopupHelper;->setAnchorView(Landroid/view/View;)V
 Lcom/android/internal/view/menu/MenuPopupHelper;->setForceShowIcon(Z)V
 Lcom/android/internal/view/menu/MenuPopupHelper;->setGravity(I)V
 Lcom/android/internal/view/menu/MenuPopupHelper;->show()V
@@ -8802,6 +8843,7 @@
 Ljava/lang/reflect/Field;->getOffset()I
 Ljava/lang/reflect/Parameter;-><init>(Ljava/lang/String;ILjava/lang/reflect/Executable;I)V
 Ljava/lang/reflect/Proxy;->invoke(Ljava/lang/reflect/Proxy;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;
+Ljava/lang/Runtime;-><init>()V
 Ljava/lang/Runtime;->load(Ljava/lang/String;Ljava/lang/ClassLoader;)V
 Ljava/lang/Runtime;->loadLibrary(Ljava/lang/String;Ljava/lang/ClassLoader;)V
 Ljava/lang/Runtime;->loadLibrary0(Ljava/lang/ClassLoader;Ljava/lang/String;)V
@@ -9170,6 +9212,7 @@
 Lorg/xml/sax/helpers/NamespaceSupport;->contexts:[Lorg/xml/sax/helpers/NamespaceSupport$Context;
 Lorg/xml/sax/helpers/NamespaceSupport;->currentContext:Lorg/xml/sax/helpers/NamespaceSupport$Context;
 Lorg/xml/sax/helpers/NamespaceSupport;->EMPTY_ENUMERATION:Ljava/util/Enumeration;
+Lorg/xml/sax/helpers/NamespaceSupport;->namespaceDeclUris:Z
 Lorg/xml/sax/helpers/ParserAdapter;->attAdapter:Lorg/xml/sax/helpers/ParserAdapter$AttributeListAdapter;
 Lorg/xml/sax/helpers/ParserAdapter;->atts:Lorg/xml/sax/helpers/AttributesImpl;
 Lorg/xml/sax/helpers/ParserAdapter;->checkNotParsing(Ljava/lang/String;Ljava/lang/String;)V
@@ -9189,6 +9232,7 @@
 Lorg/xml/sax/helpers/ParserAdapter;->reportError(Ljava/lang/String;)V
 Lorg/xml/sax/helpers/ParserAdapter;->setup(Lorg/xml/sax/Parser;)V
 Lorg/xml/sax/helpers/ParserAdapter;->setupParser()V
+Lorg/xml/sax/helpers/ParserAdapter;->uris:Z
 Lorg/xml/sax/helpers/XMLFilterImpl;->contentHandler:Lorg/xml/sax/ContentHandler;
 Lorg/xml/sax/helpers/XMLFilterImpl;->dtdHandler:Lorg/xml/sax/DTDHandler;
 Lorg/xml/sax/helpers/XMLFilterImpl;->entityResolver:Lorg/xml/sax/EntityResolver;
diff --git a/core/java/android/animation/IntEvaluator.java b/core/java/android/animation/IntEvaluator.java
index 34fb0dc..1de2ae7 100644
--- a/core/java/android/animation/IntEvaluator.java
+++ b/core/java/android/animation/IntEvaluator.java
@@ -24,7 +24,7 @@
     /**
      * This function returns the result of linearly interpolating the start and end values, with
      * <code>fraction</code> representing the proportion between the start and end values. The
-     * calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>,
+     * calculation is a simple parametric calculation: <code>result = x0 + t * (x1 - x0)</code>,
      * where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
      * and <code>t</code> is <code>fraction</code>.
      *
@@ -39,4 +39,4 @@
         int startInt = startValue;
         return (int)(startInt + fraction * (endValue - startInt));
     }
-}
\ No newline at end of file
+}
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 1d5f49a..9b6764d 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -21,6 +21,7 @@
 import android.content.ComponentName;
 import android.content.IIntentSender;
 import android.content.Intent;
+import android.content.pm.ApplicationInfo;
 import android.content.res.Configuration;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -407,4 +408,9 @@
      * has {@code permission}.
      */
     public abstract void enforceCallerIsRecentsOrHasPermission(String permission, String func);
+
+    /**
+     * @return The intent used to launch the home activity.
+     */
+    public abstract Intent getHomeIntent();
 }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 1ea93a4..c22a43e 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2767,7 +2767,6 @@
      */
     private void fixDuplicateExtras() {
         if (extras != null) {
-            fixDuplicateExtra(mSmallIcon, EXTRA_SMALL_ICON);
             fixDuplicateExtra(mLargeIcon, EXTRA_LARGE_ICON);
         }
     }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 22367b2..ff38c1f 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -9398,9 +9398,9 @@
      * <ul>
      *   <li>{@link ApnSetting#getOperatorNumeric()}</li>
      *   <li>{@link ApnSetting#getApnName()}</li>
-     *   <li>{@link ApnSetting#getProxyAddress()}</li>
+     *   <li>{@link ApnSetting#getProxyAddressAsString()}</li>
      *   <li>{@link ApnSetting#getProxyPort()}</li>
-     *   <li>{@link ApnSetting#getMmsProxyAddress()}</li>
+     *   <li>{@link ApnSetting#getMmsProxyAddressAsString()}</li>
      *   <li>{@link ApnSetting#getMmsProxyPort()}</li>
      *   <li>{@link ApnSetting#getMmsc()}</li>
      *   <li>{@link ApnSetting#isEnabled()}</li>
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index d65e051..3120421 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -1120,6 +1120,9 @@
     /** @hide */
     public String[] splitClassLoaderNames;
 
+    /** @hide */
+    public boolean hiddenUntilInstalled;
+
     /**
      * Represents the default policy. The actual policy used will depend on other properties of
      * the application, e.g. the target SDK version.
@@ -1460,6 +1463,7 @@
         compileSdkVersion = orig.compileSdkVersion;
         compileSdkVersionCodename = orig.compileSdkVersionCodename;
         mHiddenApiPolicy = orig.mHiddenApiPolicy;
+        hiddenUntilInstalled = orig.hiddenUntilInstalled;
     }
 
     public String toString() {
@@ -1534,6 +1538,7 @@
         dest.writeString(compileSdkVersionCodename);
         dest.writeString(appComponentFactory);
         dest.writeInt(mHiddenApiPolicy);
+        dest.writeInt(hiddenUntilInstalled ? 1 : 0);
     }
 
     public static final Parcelable.Creator<ApplicationInfo> CREATOR
@@ -1605,6 +1610,7 @@
         compileSdkVersionCodename = source.readString();
         appComponentFactory = source.readString();
         mHiddenApiPolicy = source.readInt();
+        hiddenUntilInstalled = source.readInt() != 0;
     }
 
     /**
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index c988fa9..bc5b32c 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -598,6 +598,9 @@
     boolean setApplicationHiddenSettingAsUser(String packageName, boolean hidden, int userId);
     boolean getApplicationHiddenSettingAsUser(String packageName, int userId);
 
+    void setSystemAppHiddenUntilInstalled(String packageName, boolean hidden);
+    boolean setSystemAppInstallState(String packageName, boolean installed, int userId);
+
     IPackageInstaller getPackageInstaller();
 
     boolean setBlockUninstallForUser(String packageName, boolean blockUninstall, int userId);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 7253e77..68d0da9 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -147,6 +147,7 @@
             GET_DISABLED_COMPONENTS,
             GET_DISABLED_UNTIL_USED_COMPONENTS,
             GET_UNINSTALLED_PACKAGES,
+            MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface PackageInfoFlags {}
@@ -164,6 +165,7 @@
             MATCH_STATIC_SHARED_LIBRARIES,
             GET_DISABLED_UNTIL_USED_COMPONENTS,
             GET_UNINSTALLED_PACKAGES,
+            MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ApplicationInfoFlags {}
@@ -522,6 +524,12 @@
     public static final int MATCH_DEBUG_TRIAGED_MISSING = 0x10000000;
 
     /**
+     * Internal flag used to indicate that a package is a hidden system app.
+     * @hide
+     */
+    public static final int MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS =  0x20000000;
+
+    /**
      * Flag for {@link #addCrossProfileIntentFilter}: if this flag is set: when
      * resolving an intent that matches the {@code CrossProfileIntentFilter},
      * the current profile will be skipped. Only activities in the target user
@@ -4841,7 +4849,8 @@
      * on the system for other users, also install it for the specified user.
      * @hide
      */
-     @RequiresPermission(anyOf = {
+    @RequiresPermission(anyOf = {
+            Manifest.permission.INSTALL_EXISTING_PACKAGES,
             Manifest.permission.INSTALL_PACKAGES,
             Manifest.permission.INTERACT_ACROSS_USERS_FULL})
     public abstract int installExistingPackageAsUser(String packageName, @UserIdInt int userId)
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 3f8a390..79f3e53 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -639,11 +639,19 @@
      */
     private static boolean checkUseInstalledOrHidden(int flags, PackageUserState state,
             ApplicationInfo appInfo) {
+        // Returns false if the package is hidden system app until installed.
+        if ((flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) == 0
+                && !state.installed
+                && appInfo != null && appInfo.hiddenUntilInstalled) {
+            return false;
+        }
+
         // If available for the target user, or trying to match uninstalled packages and it's
         // a system app.
         return state.isAvailable(flags)
                 || (appInfo != null && appInfo.isSystemApp()
-                        && (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0);
+                        && ((flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0
+                        || (flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) != 0));
     }
 
     public static boolean isAvailable(PackageUserState state) {
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 87c64cd..32c6898 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -2365,13 +2365,25 @@
      * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, is defined relative to the active array rectangle given in
      * this field, with <code>(0, 0)</code> being the top-left of this rectangle.</p>
      * <p>The active array may be smaller than the full pixel array, since the full array may
-     * include black calibration pixels or other inactive regions, and geometric correction
-     * resulting in scaling or cropping may have been applied.</p>
+     * include black calibration pixels or other inactive regions.</p>
+     * <p>For devices that do not support {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the active
+     * array must be the same as {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.</p>
+     * <p>For devices that support {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the active array must
+     * be enclosed by {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}. The difference between
+     * pre-correction active array and active array accounts for scaling or cropping caused
+     * by lens geometric distortion correction.</p>
+     * <p>In general, application should always refer to active array size for controls like
+     * metering regions or crop region. Two exceptions are when the application is dealing with
+     * RAW image buffers (RAW_SENSOR, RAW10, RAW12 etc), or when application explicitly set
+     * {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} to OFF. In these cases, application should refer
+     * to {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.</p>
      * <p><b>Units</b>: Pixel coordinates on the image sensor</p>
      * <p>This key is available on all devices.</p>
      *
+     * @see CaptureRequest#DISTORTION_CORRECTION_MODE
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE
+     * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
      */
     @PublicKey
     public static final Key<android.graphics.Rect> SENSOR_INFO_ACTIVE_ARRAY_SIZE =
@@ -2616,9 +2628,9 @@
      * <ol>
      * <li>{@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion}.</li>
      * </ol>
-     * <p>If all of the geometric distortion fields are no-ops, this rectangle will be the same
-     * as the post-distortion-corrected rectangle given in
-     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</p>
+     * <p>If the camera device doesn't support geometric distortion correction, or all of the
+     * geometric distortion fields are no-ops, this rectangle will be the same as the
+     * post-distortion-corrected rectangle given in {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</p>
      * <p>This rectangle is defined relative to the full pixel array; (0,0) is the top-left of
      * the full pixel array, and the size of the full pixel array is given by
      * {@link CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE android.sensor.info.pixelArraySize}.</p>
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 411a97e..aca77a5 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -1269,11 +1269,26 @@
      * Otherwise will always be present.</p>
      * <p>The maximum number of regions supported by the device is determined by the value
      * of {@link CameraCharacteristics#CONTROL_MAX_REGIONS_AE android.control.maxRegionsAe}.</p>
-     * <p>The coordinate system is based on the active pixel array,
-     * with (0,0) being the top-left pixel in the active pixel array, and
+     * <p>For devices not supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+     * system always follows that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with (0,0) being
+     * the top-left pixel in the active pixel array, and
      * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
-     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the
-     * bottom-right pixel in the active pixel array.</p>
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the
+     * active pixel array.</p>
+     * <p>For devices supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+     * system depends on the mode being set.
+     * When the distortion correction mode is OFF, the coordinate system follows
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, with
+     * <code>(0, 0)</code> being the top-left pixel of the pre-correction active array, and
+     * ({@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.width - 1,
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.height - 1) being the bottom-right
+     * pixel in the pre-correction active pixel array.
+     * When the distortion correction mode is not OFF, the coordinate system follows
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
+     * <code>(0, 0)</code> being the top-left pixel of the active array, and
+     * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the
+     * active pixel array.</p>
      * <p>The weight must be within <code>[0, 1000]</code>, and represents a weight
      * for every pixel in the area. This means that a large metering area
      * with the same weight as a smaller area will have more effect in
@@ -1289,15 +1304,20 @@
      * region and output only the intersection rectangle as the metering region in the result
      * metadata.  If the region is entirely outside the crop region, it will be ignored and
      * not reported in the result metadata.</p>
-     * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p>
+     * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on
+     * distortion correction capability and mode</p>
      * <p><b>Range of valid values:</b><br>
      * Coordinates must be between <code>[(0,0), (width, height))</code> of
-     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p>
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}
+     * depending on distortion correction capability and mode</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      *
      * @see CameraCharacteristics#CONTROL_MAX_REGIONS_AE
+     * @see CaptureRequest#DISTORTION_CORRECTION_MODE
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+     * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
      */
     @PublicKey
     public static final Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AE_REGIONS =
@@ -1443,11 +1463,26 @@
      * Otherwise will always be present.</p>
      * <p>The maximum number of focus areas supported by the device is determined by the value
      * of {@link CameraCharacteristics#CONTROL_MAX_REGIONS_AF android.control.maxRegionsAf}.</p>
-     * <p>The coordinate system is based on the active pixel array,
-     * with (0,0) being the top-left pixel in the active pixel array, and
+     * <p>For devices not supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+     * system always follows that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with (0,0) being
+     * the top-left pixel in the active pixel array, and
      * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
-     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the
-     * bottom-right pixel in the active pixel array.</p>
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the
+     * active pixel array.</p>
+     * <p>For devices supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+     * system depends on the mode being set.
+     * When the distortion correction mode is OFF, the coordinate system follows
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, with
+     * <code>(0, 0)</code> being the top-left pixel of the pre-correction active array, and
+     * ({@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.width - 1,
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.height - 1) being the bottom-right
+     * pixel in the pre-correction active pixel array.
+     * When the distortion correction mode is not OFF, the coordinate system follows
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
+     * <code>(0, 0)</code> being the top-left pixel of the active array, and
+     * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the
+     * active pixel array.</p>
      * <p>The weight must be within <code>[0, 1000]</code>, and represents a weight
      * for every pixel in the area. This means that a large metering area
      * with the same weight as a smaller area will have more effect in
@@ -1464,15 +1499,20 @@
      * region and output only the intersection rectangle as the metering region in the result
      * metadata. If the region is entirely outside the crop region, it will be ignored and
      * not reported in the result metadata.</p>
-     * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p>
+     * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on
+     * distortion correction capability and mode</p>
      * <p><b>Range of valid values:</b><br>
      * Coordinates must be between <code>[(0,0), (width, height))</code> of
-     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p>
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}
+     * depending on distortion correction capability and mode</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      *
      * @see CameraCharacteristics#CONTROL_MAX_REGIONS_AF
+     * @see CaptureRequest#DISTORTION_CORRECTION_MODE
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+     * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
      */
     @PublicKey
     public static final Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AF_REGIONS =
@@ -1612,11 +1652,26 @@
      * Otherwise will always be present.</p>
      * <p>The maximum number of regions supported by the device is determined by the value
      * of {@link CameraCharacteristics#CONTROL_MAX_REGIONS_AWB android.control.maxRegionsAwb}.</p>
-     * <p>The coordinate system is based on the active pixel array,
-     * with (0,0) being the top-left pixel in the active pixel array, and
+     * <p>For devices not supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+     * system always follows that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with (0,0) being
+     * the top-left pixel in the active pixel array, and
      * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
-     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the
-     * bottom-right pixel in the active pixel array.</p>
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the
+     * active pixel array.</p>
+     * <p>For devices supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+     * system depends on the mode being set.
+     * When the distortion correction mode is OFF, the coordinate system follows
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, with
+     * <code>(0, 0)</code> being the top-left pixel of the pre-correction active array, and
+     * ({@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.width - 1,
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.height - 1) being the bottom-right
+     * pixel in the pre-correction active pixel array.
+     * When the distortion correction mode is not OFF, the coordinate system follows
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
+     * <code>(0, 0)</code> being the top-left pixel of the active array, and
+     * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the
+     * active pixel array.</p>
      * <p>The weight must range from 0 to 1000, and represents a weight
      * for every pixel in the area. This means that a large metering area
      * with the same weight as a smaller area will have more effect in
@@ -1632,15 +1687,20 @@
      * region and output only the intersection rectangle as the metering region in the result
      * metadata.  If the region is entirely outside the crop region, it will be ignored and
      * not reported in the result metadata.</p>
-     * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p>
+     * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on
+     * distortion correction capability and mode</p>
      * <p><b>Range of valid values:</b><br>
      * Coordinates must be between <code>[(0,0), (width, height))</code> of
-     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p>
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}
+     * depending on distortion correction capability and mode</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      *
      * @see CameraCharacteristics#CONTROL_MAX_REGIONS_AWB
+     * @see CaptureRequest#DISTORTION_CORRECTION_MODE
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+     * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
      */
     @PublicKey
     public static final Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AWB_REGIONS =
@@ -2433,9 +2493,17 @@
     /**
      * <p>The desired region of the sensor to read out for this capture.</p>
      * <p>This control can be used to implement digital zoom.</p>
-     * <p>The crop region coordinate system is based off
-     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with <code>(0, 0)</code> being the
-     * top-left corner of the sensor active array.</p>
+     * <p>For devices not supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+     * system always follows that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with <code>(0, 0)</code> being
+     * the top-left pixel of the active array.</p>
+     * <p>For devices supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+     * system depends on the mode being set.
+     * When the distortion correction mode is OFF, the coordinate system follows
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, with
+     * <code>(0, 0)</code> being the top-left pixel of the pre-correction active array.
+     * When the distortion correction mode is not OFF, the coordinate system follows
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
+     * <code>(0, 0)</code> being the top-left pixel of the active array.</p>
      * <p>Output streams use this rectangle to produce their output,
      * cropping to a smaller region if necessary to maintain the
      * stream's aspect ratio, then scaling the sensor input to
@@ -2454,20 +2522,30 @@
      * outputs will crop horizontally (pillarbox), and 16:9
      * streams will match exactly. These additional crops will
      * be centered within the crop region.</p>
-     * <p>The width and height of the crop region cannot
-     * be set to be smaller than
+     * <p>If the coordinate system is android.sensor.info.activeArraysSize, the width and height
+     * of the crop region cannot be set to be smaller than
      * <code>floor( activeArraySize.width / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code> and
      * <code>floor( activeArraySize.height / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code>, respectively.</p>
+     * <p>If the coordinate system is {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, the width
+     * and height of the crop region cannot be set to be smaller than
+     * <code>floor( preCorrectionActiveArraySize.width / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code>
+     * and
+     * <code>floor( preCorrectionActiveArraySize.height / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code>,
+     * respectively.</p>
      * <p>The camera device may adjust the crop region to account
      * for rounding and other hardware requirements; the final
      * crop region used will be included in the output capture
      * result.</p>
      * <p><b>Units</b>: Pixel coordinates relative to
-     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p>
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on distortion correction
+     * capability and mode</p>
      * <p>This key is available on all devices.</p>
      *
+     * @see CaptureRequest#DISTORTION_CORRECTION_MODE
      * @see CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+     * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
      */
     @PublicKey
     public static final Key<android.graphics.Rect> SCALER_CROP_REGION =
@@ -3186,15 +3264,14 @@
      * any correction at all would slow down capture rate.  Every output stream will have a
      * similar amount of enhancement applied.</p>
      * <p>The correction only applies to processed outputs such as YUV, JPEG, or DEPTH16; it is not
-     * applied to any RAW output.  Metadata coordinates such as face rectangles or metering
+     * applied to any RAW output. Metadata coordinates such as face rectangles or metering
      * regions are also not affected by correction.</p>
-     * <p>Applications enabling distortion correction need to pay extra attention when converting
-     * image coordinates between corrected output buffers and the sensor array. For example, if
-     * the app supports tap-to-focus and enables correction, it then has to apply the distortion
-     * model described in {@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion} to the image buffer tap coordinates to properly
-     * calculate the tap position on the sensor active array to be used with
-     * {@link CaptureRequest#CONTROL_AF_REGIONS android.control.afRegions}. The same applies in reverse to detected face rectangles if
-     * they need to be drawn on top of the corrected output buffers.</p>
+     * <p>This control will be on by default on devices that support this control. Applications
+     * disabling distortion correction need to pay extra attention with the coordinate system of
+     * metering regions, crop region, and face rectangles. When distortion correction is OFF,
+     * metadata coordinates follow the coordinate system of
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}. When distortion is not OFF, metadata
+     * coordinates follow the coordinate system of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</p>
      * <p><b>Possible values:</b>
      * <ul>
      *   <li>{@link #DISTORTION_CORRECTION_MODE_OFF OFF}</li>
@@ -3205,9 +3282,10 @@
      * {@link CameraCharacteristics#DISTORTION_CORRECTION_AVAILABLE_MODES android.distortionCorrection.availableModes}</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      *
-     * @see CaptureRequest#CONTROL_AF_REGIONS
      * @see CameraCharacteristics#DISTORTION_CORRECTION_AVAILABLE_MODES
      * @see CameraCharacteristics#LENS_DISTORTION
+     * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+     * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
      * @see #DISTORTION_CORRECTION_MODE_OFF
      * @see #DISTORTION_CORRECTION_MODE_FAST
      * @see #DISTORTION_CORRECTION_MODE_HIGH_QUALITY
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 6439338..75c27f5 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -730,11 +730,26 @@
      * Otherwise will always be present.</p>
      * <p>The maximum number of regions supported by the device is determined by the value
      * of {@link CameraCharacteristics#CONTROL_MAX_REGIONS_AE android.control.maxRegionsAe}.</p>
-     * <p>The coordinate system is based on the active pixel array,
-     * with (0,0) being the top-left pixel in the active pixel array, and
+     * <p>For devices not supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+     * system always follows that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with (0,0) being
+     * the top-left pixel in the active pixel array, and
      * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
-     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the
-     * bottom-right pixel in the active pixel array.</p>
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the
+     * active pixel array.</p>
+     * <p>For devices supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+     * system depends on the mode being set.
+     * When the distortion correction mode is OFF, the coordinate system follows
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, with
+     * <code>(0, 0)</code> being the top-left pixel of the pre-correction active array, and
+     * ({@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.width - 1,
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.height - 1) being the bottom-right
+     * pixel in the pre-correction active pixel array.
+     * When the distortion correction mode is not OFF, the coordinate system follows
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
+     * <code>(0, 0)</code> being the top-left pixel of the active array, and
+     * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the
+     * active pixel array.</p>
      * <p>The weight must be within <code>[0, 1000]</code>, and represents a weight
      * for every pixel in the area. This means that a large metering area
      * with the same weight as a smaller area will have more effect in
@@ -750,15 +765,20 @@
      * region and output only the intersection rectangle as the metering region in the result
      * metadata.  If the region is entirely outside the crop region, it will be ignored and
      * not reported in the result metadata.</p>
-     * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p>
+     * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on
+     * distortion correction capability and mode</p>
      * <p><b>Range of valid values:</b><br>
      * Coordinates must be between <code>[(0,0), (width, height))</code> of
-     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p>
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}
+     * depending on distortion correction capability and mode</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      *
      * @see CameraCharacteristics#CONTROL_MAX_REGIONS_AE
+     * @see CaptureRequest#DISTORTION_CORRECTION_MODE
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+     * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
      */
     @PublicKey
     public static final Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AE_REGIONS =
@@ -1152,11 +1172,26 @@
      * Otherwise will always be present.</p>
      * <p>The maximum number of focus areas supported by the device is determined by the value
      * of {@link CameraCharacteristics#CONTROL_MAX_REGIONS_AF android.control.maxRegionsAf}.</p>
-     * <p>The coordinate system is based on the active pixel array,
-     * with (0,0) being the top-left pixel in the active pixel array, and
+     * <p>For devices not supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+     * system always follows that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with (0,0) being
+     * the top-left pixel in the active pixel array, and
      * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
-     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the
-     * bottom-right pixel in the active pixel array.</p>
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the
+     * active pixel array.</p>
+     * <p>For devices supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+     * system depends on the mode being set.
+     * When the distortion correction mode is OFF, the coordinate system follows
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, with
+     * <code>(0, 0)</code> being the top-left pixel of the pre-correction active array, and
+     * ({@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.width - 1,
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.height - 1) being the bottom-right
+     * pixel in the pre-correction active pixel array.
+     * When the distortion correction mode is not OFF, the coordinate system follows
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
+     * <code>(0, 0)</code> being the top-left pixel of the active array, and
+     * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the
+     * active pixel array.</p>
      * <p>The weight must be within <code>[0, 1000]</code>, and represents a weight
      * for every pixel in the area. This means that a large metering area
      * with the same weight as a smaller area will have more effect in
@@ -1173,15 +1208,20 @@
      * region and output only the intersection rectangle as the metering region in the result
      * metadata. If the region is entirely outside the crop region, it will be ignored and
      * not reported in the result metadata.</p>
-     * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p>
+     * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on
+     * distortion correction capability and mode</p>
      * <p><b>Range of valid values:</b><br>
      * Coordinates must be between <code>[(0,0), (width, height))</code> of
-     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p>
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}
+     * depending on distortion correction capability and mode</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      *
      * @see CameraCharacteristics#CONTROL_MAX_REGIONS_AF
+     * @see CaptureRequest#DISTORTION_CORRECTION_MODE
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+     * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
      */
     @PublicKey
     public static final Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AF_REGIONS =
@@ -1730,11 +1770,26 @@
      * Otherwise will always be present.</p>
      * <p>The maximum number of regions supported by the device is determined by the value
      * of {@link CameraCharacteristics#CONTROL_MAX_REGIONS_AWB android.control.maxRegionsAwb}.</p>
-     * <p>The coordinate system is based on the active pixel array,
-     * with (0,0) being the top-left pixel in the active pixel array, and
+     * <p>For devices not supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+     * system always follows that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with (0,0) being
+     * the top-left pixel in the active pixel array, and
      * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
-     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the
-     * bottom-right pixel in the active pixel array.</p>
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the
+     * active pixel array.</p>
+     * <p>For devices supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+     * system depends on the mode being set.
+     * When the distortion correction mode is OFF, the coordinate system follows
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, with
+     * <code>(0, 0)</code> being the top-left pixel of the pre-correction active array, and
+     * ({@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.width - 1,
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.height - 1) being the bottom-right
+     * pixel in the pre-correction active pixel array.
+     * When the distortion correction mode is not OFF, the coordinate system follows
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
+     * <code>(0, 0)</code> being the top-left pixel of the active array, and
+     * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the bottom-right pixel in the
+     * active pixel array.</p>
      * <p>The weight must range from 0 to 1000, and represents a weight
      * for every pixel in the area. This means that a large metering area
      * with the same weight as a smaller area will have more effect in
@@ -1750,15 +1805,20 @@
      * region and output only the intersection rectangle as the metering region in the result
      * metadata.  If the region is entirely outside the crop region, it will be ignored and
      * not reported in the result metadata.</p>
-     * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p>
+     * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on
+     * distortion correction capability and mode</p>
      * <p><b>Range of valid values:</b><br>
      * Coordinates must be between <code>[(0,0), (width, height))</code> of
-     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p>
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}
+     * depending on distortion correction capability and mode</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      *
      * @see CameraCharacteristics#CONTROL_MAX_REGIONS_AWB
+     * @see CaptureRequest#DISTORTION_CORRECTION_MODE
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+     * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
      */
     @PublicKey
     public static final Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AWB_REGIONS =
@@ -3099,9 +3159,17 @@
     /**
      * <p>The desired region of the sensor to read out for this capture.</p>
      * <p>This control can be used to implement digital zoom.</p>
-     * <p>The crop region coordinate system is based off
-     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with <code>(0, 0)</code> being the
-     * top-left corner of the sensor active array.</p>
+     * <p>For devices not supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+     * system always follows that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with <code>(0, 0)</code> being
+     * the top-left pixel of the active array.</p>
+     * <p>For devices supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+     * system depends on the mode being set.
+     * When the distortion correction mode is OFF, the coordinate system follows
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, with
+     * <code>(0, 0)</code> being the top-left pixel of the pre-correction active array.
+     * When the distortion correction mode is not OFF, the coordinate system follows
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
+     * <code>(0, 0)</code> being the top-left pixel of the active array.</p>
      * <p>Output streams use this rectangle to produce their output,
      * cropping to a smaller region if necessary to maintain the
      * stream's aspect ratio, then scaling the sensor input to
@@ -3120,20 +3188,30 @@
      * outputs will crop horizontally (pillarbox), and 16:9
      * streams will match exactly. These additional crops will
      * be centered within the crop region.</p>
-     * <p>The width and height of the crop region cannot
-     * be set to be smaller than
+     * <p>If the coordinate system is android.sensor.info.activeArraysSize, the width and height
+     * of the crop region cannot be set to be smaller than
      * <code>floor( activeArraySize.width / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code> and
      * <code>floor( activeArraySize.height / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code>, respectively.</p>
+     * <p>If the coordinate system is {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, the width
+     * and height of the crop region cannot be set to be smaller than
+     * <code>floor( preCorrectionActiveArraySize.width / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code>
+     * and
+     * <code>floor( preCorrectionActiveArraySize.height / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code>,
+     * respectively.</p>
      * <p>The camera device may adjust the crop region to account
      * for rounding and other hardware requirements; the final
      * crop region used will be included in the output capture
      * result.</p>
      * <p><b>Units</b>: Pixel coordinates relative to
-     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</p>
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on distortion correction
+     * capability and mode</p>
      * <p>This key is available on all devices.</p>
      *
+     * @see CaptureRequest#DISTORTION_CORRECTION_MODE
      * @see CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+     * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
      */
     @PublicKey
     public static final Key<android.graphics.Rect> SCALER_CROP_REGION =
@@ -3624,12 +3702,23 @@
     /**
      * <p>List of landmarks for detected
      * faces.</p>
-     * <p>The coordinate system is that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
+     * <p>For devices not supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+     * system always follows that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with <code>(0, 0)</code> being
+     * the top-left pixel of the active array.</p>
+     * <p>For devices supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+     * system depends on the mode being set.
+     * When the distortion correction mode is OFF, the coordinate system follows
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, with
+     * <code>(0, 0)</code> being the top-left pixel of the pre-correction active array.
+     * When the distortion correction mode is not OFF, the coordinate system follows
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
      * <code>(0, 0)</code> being the top-left pixel of the active array.</p>
      * <p>Only available if {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} == FULL
      * This key is available on all devices.</p>
      *
+     * @see CaptureRequest#DISTORTION_CORRECTION_MODE
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+     * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
      * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
      * @hide
      */
@@ -3639,12 +3728,23 @@
     /**
      * <p>List of the bounding rectangles for detected
      * faces.</p>
-     * <p>The coordinate system is that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
+     * <p>For devices not supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+     * system always follows that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with <code>(0, 0)</code> being
+     * the top-left pixel of the active array.</p>
+     * <p>For devices supporting {@link CaptureRequest#DISTORTION_CORRECTION_MODE android.distortionCorrection.mode} control, the coordinate
+     * system depends on the mode being set.
+     * When the distortion correction mode is OFF, the coordinate system follows
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, with
+     * <code>(0, 0)</code> being the top-left pixel of the pre-correction active array.
+     * When the distortion correction mode is not OFF, the coordinate system follows
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
      * <code>(0, 0)</code> being the top-left pixel of the active array.</p>
      * <p>Only available if {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} != OFF
      * This key is available on all devices.</p>
      *
+     * @see CaptureRequest#DISTORTION_CORRECTION_MODE
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+     * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
      * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
      * @hide
      */
@@ -4478,15 +4578,14 @@
      * any correction at all would slow down capture rate.  Every output stream will have a
      * similar amount of enhancement applied.</p>
      * <p>The correction only applies to processed outputs such as YUV, JPEG, or DEPTH16; it is not
-     * applied to any RAW output.  Metadata coordinates such as face rectangles or metering
+     * applied to any RAW output. Metadata coordinates such as face rectangles or metering
      * regions are also not affected by correction.</p>
-     * <p>Applications enabling distortion correction need to pay extra attention when converting
-     * image coordinates between corrected output buffers and the sensor array. For example, if
-     * the app supports tap-to-focus and enables correction, it then has to apply the distortion
-     * model described in {@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion} to the image buffer tap coordinates to properly
-     * calculate the tap position on the sensor active array to be used with
-     * {@link CaptureRequest#CONTROL_AF_REGIONS android.control.afRegions}. The same applies in reverse to detected face rectangles if
-     * they need to be drawn on top of the corrected output buffers.</p>
+     * <p>This control will be on by default on devices that support this control. Applications
+     * disabling distortion correction need to pay extra attention with the coordinate system of
+     * metering regions, crop region, and face rectangles. When distortion correction is OFF,
+     * metadata coordinates follow the coordinate system of
+     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}. When distortion is not OFF, metadata
+     * coordinates follow the coordinate system of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</p>
      * <p><b>Possible values:</b>
      * <ul>
      *   <li>{@link #DISTORTION_CORRECTION_MODE_OFF OFF}</li>
@@ -4497,9 +4596,10 @@
      * {@link CameraCharacteristics#DISTORTION_CORRECTION_AVAILABLE_MODES android.distortionCorrection.availableModes}</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      *
-     * @see CaptureRequest#CONTROL_AF_REGIONS
      * @see CameraCharacteristics#DISTORTION_CORRECTION_AVAILABLE_MODES
      * @see CameraCharacteristics#LENS_DISTORTION
+     * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+     * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
      * @see #DISTORTION_CORRECTION_MODE_OFF
      * @see #DISTORTION_CORRECTION_MODE_FAST
      * @see #DISTORTION_CORRECTION_MODE_HIGH_QUALITY
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 4baf263..86bd30c 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -747,6 +747,9 @@
         if (faceDetectMode == null) {
             Log.w(TAG, "Face detect mode metadata is null, assuming the mode is SIMPLE");
             faceDetectMode = CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE;
+        } else if (faceDetectMode > CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL) {
+            // Face detect mode is larger than FULL, assuming the mode is FULL
+            faceDetectMode = CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL;
         } else {
             if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_OFF) {
                 return new Face[0];
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index a040a09..1ee3c93 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -82,9 +82,9 @@
  *
  * </ul>
  *
- * <p> As of {@link android.os.Build.VERSION_CODES#P Android P}, all formats can be used for
- * sharing, subject to device support. On prior API levels, only {@link ImageFormat#PRIVATE}
- * format may be used.</p>
+ * <p> As of {@link android.os.Build.VERSION_CODES#P Android P}, all formats except
+ * {@link ImageFormat#JPEG} and {@link ImageFormat#RAW_PRIVATE} can be used for sharing, subject to
+ * device support. On prior API levels, only {@link ImageFormat#PRIVATE} format may be used.</p>
  *
  * @see CameraDevice#createCaptureSessionByOutputConfigurations
  *
diff --git a/core/java/android/hardware/location/NanoAppFilter.java b/core/java/android/hardware/location/NanoAppFilter.java
index 4d8e734..562065e 100644
--- a/core/java/android/hardware/location/NanoAppFilter.java
+++ b/core/java/android/hardware/location/NanoAppFilter.java
@@ -85,7 +85,7 @@
         mAppId = in.readLong();
         mAppVersion = in.readInt();
         mVersionRestrictionMask = in.readInt();
-        mAppIdVendorMask = in.readInt();
+        mAppIdVendorMask = in.readLong();
     }
 
     public int describeContents() {
@@ -93,7 +93,6 @@
     }
 
     public void writeToParcel(Parcel out, int flags) {
-
         out.writeLong(mAppId);
         out.writeInt(mAppVersion);
         out.writeInt(mVersionRestrictionMask);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4347a30..2439d23 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7537,9 +7537,6 @@
          */
         public static final String ASSIST_GESTURE_SENSITIVITY = "assist_gesture_sensitivity";
 
-        private static final Validator ASSIST_GESTURE_SENSITIVITY_VALIDATOR =
-                new SettingsValidators.InclusiveFloatRangeValidator(0.0f, 1.0f);
-
         /**
          * Whether the assist gesture should silence alerts.
          *
@@ -7569,8 +7566,6 @@
          */
         public static final String ASSIST_GESTURE_SETUP_COMPLETE = "assist_gesture_setup_complete";
 
-        private static final Validator ASSIST_GESTURE_SETUP_COMPLETE_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Control whether Night display is currently activated.
          * @hide
@@ -8026,8 +8021,6 @@
             NFC_PAYMENT_DEFAULT_COMPONENT,
             AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN,
             ASSIST_GESTURE_ENABLED,
-            ASSIST_GESTURE_SENSITIVITY,
-            ASSIST_GESTURE_SETUP_COMPLETE,
             ASSIST_GESTURE_SILENCE_ALERTS_ENABLED,
             ASSIST_GESTURE_WAKE_ENABLED,
             VR_DISPLAY_MODE,
@@ -8166,8 +8159,6 @@
             VALIDATORS.put(AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN,
                     AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN_VALIDATOR);
             VALIDATORS.put(ASSIST_GESTURE_ENABLED, ASSIST_GESTURE_ENABLED_VALIDATOR);
-            VALIDATORS.put(ASSIST_GESTURE_SENSITIVITY, ASSIST_GESTURE_SENSITIVITY_VALIDATOR);
-            VALIDATORS.put(ASSIST_GESTURE_SETUP_COMPLETE, ASSIST_GESTURE_SETUP_COMPLETE_VALIDATOR);
             VALIDATORS.put(ASSIST_GESTURE_SILENCE_ALERTS_ENABLED,
                     ASSIST_GESTURE_SILENCE_ALERTS_ENABLED_VALIDATOR);
             VALIDATORS.put(ASSIST_GESTURE_WAKE_ENABLED, ASSIST_GESTURE_WAKE_ENABLED_VALIDATOR);
diff --git a/core/java/android/service/autofill/TextValueSanitizer.java b/core/java/android/service/autofill/TextValueSanitizer.java
index e5ad77a..a8c080a 100644
--- a/core/java/android/service/autofill/TextValueSanitizer.java
+++ b/core/java/android/service/autofill/TextValueSanitizer.java
@@ -37,7 +37,7 @@
  * <p>For example, to remove spaces from groups of 4-digits in a credit card:
  *
  * <pre class="prettyprint">
- * new TextValueSanitizer(Pattern.compile("^(\\d{4})\\s?(\\d{4})\\s?(\\d{4})\\s?(\\d{4})$",
+ * new TextValueSanitizer(Pattern.compile("^(\\d{4})\\s?(\\d{4})\\s?(\\d{4})\\s?(\\d{4})$"),
  *     "$1$2$3$4")
  * </pre>
  */
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 01562b3..6f1bd78 100644
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -33,7 +33,6 @@
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
-import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -487,8 +486,9 @@
          * intent. The possible values for this extra are
          * {@link TextToSpeech#SUCCESS} and {@link TextToSpeech#ERROR}.
          *
-         * @deprecated No longer in use. If client ise interested in information about what
-         * changed, is should send ACTION_CHECK_TTS_DATA intent to discover available voices.
+         * @deprecated No longer in use. If client is interested in information about what
+         * changed, it should use the ACTION_CHECK_TTS_DATA
+         * intent to discover available voices.
          */
         @Deprecated
         public static final String EXTRA_TTS_DATA_INSTALLED = "dataInstalled";
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index 47bda53..496bc9f 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -29,6 +29,7 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Region;
+import android.graphics.Region.Op;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -325,14 +326,9 @@
      * @hide
      */
     public static DisplayCutout fromBoundingRect(int left, int top, int right, int bottom) {
-        Path path = new Path();
-        path.reset();
-        path.moveTo(left, top);
-        path.lineTo(left, bottom);
-        path.lineTo(right, bottom);
-        path.lineTo(right, top);
-        path.close();
-        return fromBounds(path);
+        Region r = Region.obtain();
+        r.set(left, top, right, bottom);
+        return fromBounds(r);
     }
 
     /**
@@ -340,26 +336,19 @@
      *
      * @hide
      */
-    public static DisplayCutout fromBounds(Path path) {
-        RectF clipRect = new RectF();
-        path.computeBounds(clipRect, false /* unused */);
-        Region clipRegion = Region.obtain();
-        clipRegion.set((int) clipRect.left, (int) clipRect.top,
-                (int) clipRect.right, (int) clipRect.bottom);
-
-        Region bounds = new Region();
-        bounds.setPath(path, clipRegion);
-        clipRegion.recycle();
-        return new DisplayCutout(ZERO_RECT, bounds, false /* copyArguments */);
+    public static DisplayCutout fromBounds(Region region) {
+        return new DisplayCutout(ZERO_RECT, region, false /* copyArguments */);
     }
 
     /**
-     * Creates the bounding path according to @android:string/config_mainBuiltInDisplayCutout.
+     * Creates the display cutout according to
+     * @android:string/config_mainBuiltInDisplayCutoutRectApproximation, which is the closest
+     * rectangle-base approximation of the cutout.
      *
      * @hide
      */
-    public static DisplayCutout fromResources(Resources res, int displayWidth, int displayHeight) {
-        return fromSpec(res.getString(R.string.config_mainBuiltInDisplayCutout),
+    public static DisplayCutout fromResourcesRectApproximation(Resources res, int displayWidth, int displayHeight) {
+        return fromSpec(res.getString(R.string.config_mainBuiltInDisplayCutoutRectApproximation),
                 displayWidth, displayHeight, DENSITY_DEVICE_STABLE / (float) DENSITY_DEFAULT);
     }
 
@@ -369,7 +358,8 @@
      * @hide
      */
     public static Path pathFromResources(Resources res, int displayWidth, int displayHeight) {
-        return pathAndDisplayCutoutFromSpec(res.getString(R.string.config_mainBuiltInDisplayCutout),
+        return pathAndDisplayCutoutFromSpec(
+                res.getString(R.string.config_mainBuiltInDisplayCutout),
                 displayWidth, displayHeight, DENSITY_DEVICE_STABLE / (float) DENSITY_DEFAULT).first;
     }
 
@@ -417,6 +407,7 @@
         }
 
         final Path p;
+        final Region r = Region.obtain();
         try {
             p = PathParser.createPathFromPathData(spec);
         } catch (Throwable e) {
@@ -431,6 +422,8 @@
         m.postTranslate(offsetX, 0);
         p.transform(m);
 
+        addToRegion(p, r);
+
         if (bottomSpec != null) {
             final Path bottomPath;
             try {
@@ -443,9 +436,10 @@
             m.postTranslate(0, displayHeight);
             bottomPath.transform(m);
             p.addPath(bottomPath);
+            addToRegion(bottomPath, r);
         }
 
-        final Pair<Path, DisplayCutout> result = new Pair<>(p, fromBounds(p));
+        final Pair<Path, DisplayCutout> result = new Pair<>(p, fromBounds(r));
         synchronized (CACHE_LOCK) {
             sCachedSpec = spec;
             sCachedDisplayWidth = displayWidth;
@@ -456,6 +450,14 @@
         return result;
     }
 
+    private static void addToRegion(Path p, Region r) {
+        final RectF rectF = new RectF();
+        final Rect rect = new Rect();
+        p.computeBounds(rectF, false /* unused */);
+        rectF.round(rect);
+        r.op(rect, Op.UNION);
+    }
+
     private static Region boundingRectsToRegion(List<Rect> rects) {
         Region result = Region.obtain();
         if (rects != null) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index b2e53ed7..98a1ec3 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1641,7 +1641,6 @@
 
     private Rect ensureInsetsNonNegative(Rect insets, String kind) {
         if (insets.left < 0  || insets.top < 0  || insets.right < 0  || insets.bottom < 0) {
-            Log.wtf(mTag, "Negative " + kind + "Insets: " + insets + ", mFirst=" + mFirst);
             return new Rect(Math.max(0, insets.left),
                     Math.max(0, insets.top),
                     Math.max(0, insets.right),
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index d7f1d6e..3452b0c 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -71,280 +71,25 @@
 import java.util.Map;
 
 /**
- * <p>A View that displays web pages. This class is the basis upon which you
- * can roll your own web browser or simply display some online content within your Activity.
- * It uses the WebKit rendering engine to display
- * web pages and includes methods to navigate forward and backward
- * through a history, zoom in and out, perform text searches and more.
- *
- * <p>Note that, in order for your Activity to access the Internet and load web pages
- * in a WebView, you must add the {@code INTERNET} permissions to your
- * Android Manifest file:
- *
- * <pre>
- * {@code <uses-permission android:name="android.permission.INTERNET" />}
- * </pre>
- *
- * <p>This must be a child of the <a
- * href="{@docRoot}guide/topics/manifest/manifest-element.html">{@code <manifest>}</a>
- * element.
- *
- * <p>For more information, read
- * <a href="{@docRoot}guide/webapps/webview.html">Building Web Apps in WebView</a>.
+ * A View that displays web pages.
  *
  * <h3>Basic usage</h3>
  *
- * <p>By default, a WebView provides no browser-like widgets, does not
- * enable JavaScript and web page errors are ignored. If your goal is only
- * to display some HTML as a part of your UI, this is probably fine;
- * the user won't need to interact with the web page beyond reading
- * it, and the web page won't need to interact with the user. If you
- * actually want a full-blown web browser, then you probably want to
- * invoke the Browser application with a URL Intent rather than show it
- * with a WebView. For example:
- * <pre>
- * Uri uri = Uri.parse("https://www.example.com");
- * Intent intent = new Intent(Intent.ACTION_VIEW, uri);
- * startActivity(intent);
- * </pre>
- * <p>See {@link android.content.Intent} for more information.
  *
- * <p>To provide a WebView in your own Activity, include a {@code <WebView>} in your layout,
- * or set the entire Activity window as a WebView during {@link
- * android.app.Activity#onCreate(Bundle) onCreate()}:
+ * <p>In most cases, we recommend using a standard web browser, like Chrome, to deliver
+ * content to the user. To learn more about web browsers, read the guide on
+ * <a href="/guide/components/intents-common#Browser">
+ * invoking a browser with an intent</a>.
  *
- * <pre class="prettyprint">
- * WebView webview = new WebView(this);
- * setContentView(webview);
- * </pre>
+ * <p>WebView objects allow you to display web content as part of your activity layout, but
+ * lack some of the features of fully-developed browsers. A WebView is useful when
+ * you need increased control over the UI and advanced configuration options that will allow
+ * you to embed web pages in a specially-designed environment for your app.
  *
- * <p>Then load the desired web page:
- *
- * <pre>
- * // Simplest usage: note that an exception will NOT be thrown
- * // if there is an error loading this page (see below).
- * webview.loadUrl("https://example.com/");
- *
- * // OR, you can also load from an HTML string:
- * String summary = "&lt;html>&lt;body>You scored &lt;b>192&lt;/b> points.&lt;/body>&lt;/html>";
- * webview.loadData(summary, "text/html", null);
- * // ... although note that there are restrictions on what this HTML can do.
- * // See {@link #loadData(String,String,String)} and {@link
- * #loadDataWithBaseURL(String,String,String,String,String)} for more info.
- * // Also see {@link #loadData(String,String,String)} for information on encoding special
- * // characters.
- * </pre>
- *
- * <p>A WebView has several customization points where you can add your
- * own behavior. These are:
- *
- * <ul>
- *   <li>Creating and setting a {@link android.webkit.WebChromeClient} subclass.
- *       This class is called when something that might impact a
- *       browser UI happens, for instance, progress updates and
- *       JavaScript alerts are sent here (see <a
- * href="{@docRoot}guide/developing/debug-tasks.html#DebuggingWebPages">Debugging Tasks</a>).
- *   </li>
- *   <li>Creating and setting a {@link android.webkit.WebViewClient} subclass.
- *       It will be called when things happen that impact the
- *       rendering of the content, eg, errors or form submissions. You
- *       can also intercept URL loading here (via {@link
- * android.webkit.WebViewClient#shouldOverrideUrlLoading(WebView,String)
- * shouldOverrideUrlLoading()}).</li>
- *   <li>Modifying the {@link android.webkit.WebSettings}, such as
- * enabling JavaScript with {@link android.webkit.WebSettings#setJavaScriptEnabled(boolean)
- * setJavaScriptEnabled()}. </li>
- *   <li>Injecting Java objects into the WebView using the
- *       {@link android.webkit.WebView#addJavascriptInterface} method. This
- *       method allows you to inject Java objects into a page's JavaScript
- *       context, so that they can be accessed by JavaScript in the page.</li>
- * </ul>
- *
- * <p>Here's a more complicated example, showing error handling,
- *    settings, and progress notification:
- *
- * <pre class="prettyprint">
- * // Let's display the progress in the activity title bar, like the
- * // browser app does.
- * getWindow().requestFeature(Window.FEATURE_PROGRESS);
- *
- * webview.getSettings().setJavaScriptEnabled(true);
- *
- * final Activity activity = this;
- * webview.setWebChromeClient(new WebChromeClient() {
- *   public void onProgressChanged(WebView view, int progress) {
- *     // Activities and WebViews measure progress with different scales.
- *     // The progress meter will automatically disappear when we reach 100%
- *     activity.setProgress(progress * 1000);
- *   }
- * });
- * webview.setWebViewClient(new WebViewClient() {
- *   public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
- *     Toast.makeText(activity, "Oh no! " + description, Toast.LENGTH_SHORT).show();
- *   }
- * });
- *
- * webview.loadUrl("https://developer.android.com/");
- * </pre>
- *
- * <h3>Zoom</h3>
- *
- * <p>To enable the built-in zoom, set
- * {@link #getSettings() WebSettings}.{@link WebSettings#setBuiltInZoomControls(boolean)}
- * (introduced in API level {@link android.os.Build.VERSION_CODES#CUPCAKE}).
- *
- * <p class="note"><b>Note:</b> Using zoom if either the height or width is set to
- * {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} may lead to undefined behavior
- * and should be avoided.
- *
- * <h3>Cookie and window management</h3>
- *
- * <p>For obvious security reasons, your application has its own
- * cache, cookie store etc.&mdash;it does not share the Browser
- * application's data.
- *
- * <p>By default, requests by the HTML to open new windows are
- * ignored. This is {@code true} whether they be opened by JavaScript or by
- * the target attribute on a link. You can customize your
- * {@link WebChromeClient} to provide your own behavior for opening multiple windows,
- * and render them in whatever manner you want.
- *
- * <p>The standard behavior for an Activity is to be destroyed and
- * recreated when the device orientation or any other configuration changes. This will cause
- * the WebView to reload the current page. If you don't want that, you
- * can set your Activity to handle the {@code orientation} and {@code keyboardHidden}
- * changes, and then just leave the WebView alone. It'll automatically
- * re-orient itself as appropriate. Read <a
- * href="{@docRoot}guide/topics/resources/runtime-changes.html">Handling Runtime Changes</a> for
- * more information about how to handle configuration changes during runtime.
- *
- *
- * <h3>Building web pages to support different screen densities</h3>
- *
- * <p>The screen density of a device is based on the screen resolution. A screen with low density
- * has fewer available pixels per inch, where a screen with high density
- * has more &mdash; sometimes significantly more &mdash; pixels per inch. The density of a
- * screen is important because, other things being equal, a UI element (such as a button) whose
- * height and width are defined in terms of screen pixels will appear larger on the lower density
- * screen and smaller on the higher density screen.
- * For simplicity, Android collapses all actual screen densities into three generalized densities:
- * high, medium, and low.
- * <p>By default, WebView scales a web page so that it is drawn at a size that matches the default
- * appearance on a medium density screen. So, it applies 1.5x scaling on a high density screen
- * (because its pixels are smaller) and 0.75x scaling on a low density screen (because its pixels
- * are bigger).
- * Starting with API level {@link android.os.Build.VERSION_CODES#ECLAIR}, WebView supports DOM, CSS,
- * and meta tag features to help you (as a web developer) target screens with different screen
- * densities.
- * <p>Here's a summary of the features you can use to handle different screen densities:
- * <ul>
- * <li>The {@code window.devicePixelRatio} DOM property. The value of this property specifies the
- * default scaling factor used for the current device. For example, if the value of {@code
- * window.devicePixelRatio} is "1.0", then the device is considered a medium density (mdpi) device
- * and default scaling is not applied to the web page; if the value is "1.5", then the device is
- * considered a high density device (hdpi) and the page content is scaled 1.5x; if the
- * value is "0.75", then the device is considered a low density device (ldpi) and the content is
- * scaled 0.75x.</li>
- * <li>The {@code -webkit-device-pixel-ratio} CSS media query. Use this to specify the screen
- * densities for which this style sheet is to be used. The corresponding value should be either
- * "0.75", "1", or "1.5", to indicate that the styles are for devices with low density, medium
- * density, or high density screens, respectively. For example:
- * <pre>
- * &lt;link rel="stylesheet" media="screen and (-webkit-device-pixel-ratio:1.5)" href="hdpi.css" /&gt;</pre>
- * <p>The {@code hdpi.css} stylesheet is only used for devices with a screen pixel ratio of 1.5,
- * which is the high density pixel ratio.
- * </li>
- * </ul>
- *
- * <h3>HTML5 Video support</h3>
- *
- * <p>In order to support inline HTML5 video in your application you need to have hardware
- * acceleration turned on.
- *
- * <h3>Full screen support</h3>
- *
- * <p>In order to support full screen &mdash; for video or other HTML content &mdash; you need to set a
- * {@link android.webkit.WebChromeClient} and implement both
- * {@link WebChromeClient#onShowCustomView(View, WebChromeClient.CustomViewCallback)}
- * and {@link WebChromeClient#onHideCustomView()}. If the implementation of either of these two methods is
- * missing then the web contents will not be allowed to enter full screen. Optionally you can implement
- * {@link WebChromeClient#getVideoLoadingProgressView()} to customize the View displayed whilst a video
- * is loading.
- *
- * <h3>HTML5 Geolocation API support</h3>
- *
- * <p>For applications targeting Android N and later releases
- * (API level > {@link android.os.Build.VERSION_CODES#M}) the geolocation api is only supported on
- * secure origins such as https. For such applications requests to geolocation api on non-secure
- * origins are automatically denied without invoking the corresponding
- * {@link WebChromeClient#onGeolocationPermissionsShowPrompt(String, GeolocationPermissions.Callback)}
- * method.
- *
- * <h3>Layout size</h3>
- * <p>
- * It is recommended to set the WebView layout height to a fixed value or to
- * {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT} instead of using
- * {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT}.
- * When using {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT}
- * for the height none of the WebView's parents should use a
- * {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} layout height since that could result in
- * incorrect sizing of the views.
- *
- * <p>Setting the WebView's height to {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT}
- * enables the following behaviors:
- * <ul>
- * <li>The HTML body layout height is set to a fixed value. This means that elements with a height
- * relative to the HTML body may not be sized correctly. </li>
- * <li>For applications targeting {@link android.os.Build.VERSION_CODES#KITKAT} and earlier SDKs the
- * HTML viewport meta tag will be ignored in order to preserve backwards compatibility. </li>
- * </ul>
- *
- * <p>
- * Using a layout width of {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} is not
- * supported. If such a width is used the WebView will attempt to use the width of the parent
- * instead.
- *
- * <h3>Metrics</h3>
- *
- * <p>
- * WebView may upload anonymous diagnostic data to Google when the user has consented. This data
- * helps Google improve WebView. Data is collected on a per-app basis for each app which has
- * instantiated a WebView. An individual app can opt out of this feature by putting the following
- * tag in its manifest's {@code <application>} element:
- * <pre>
- * &lt;manifest&gt;
- *     &lt;application&gt;
- *         ...
- *         &lt;meta-data android:name=&quot;android.webkit.WebView.MetricsOptOut&quot;
- *             android:value=&quot;true&quot; /&gt;
- *     &lt;/application&gt;
- * &lt;/manifest&gt;
- * </pre>
- * <p>
- * Data will only be uploaded for a given app if the user has consented AND the app has not opted
- * out.
- *
- * <h3>Safe Browsing</h3>
- *
- * <p>
- * With Safe Browsing, WebView will block malicious URLs and present a warning UI to the user to
- * allow them to navigate back safely or proceed to the malicious page.
- * <p>
- * Safe Browsing is enabled by default on devices which support it. If your app needs to disable
- * Safe Browsing for all WebViews, it can do so in the manifest's {@code <application>} element:
- * <p>
- * <pre>
- * &lt;manifest&gt;
- *     &lt;application&gt;
- *         ...
- *         &lt;meta-data android:name=&quot;android.webkit.WebView.EnableSafeBrowsing&quot;
- *             android:value=&quot;false&quot; /&gt;
- *     &lt;/application&gt;
- * &lt;/manifest&gt;
- * </pre>
- *
- * <p>
- * Otherwise, see {@link WebSettings#setSafeBrowsingEnabled}.
+ * <p>To learn more about WebView and alternatives for serving web content, read the
+ * documentation on
+ * <a href="/guide/webapps/">
+ * Web-based content</a>.
  *
  */
 // Implementation notes.
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index 6c19256..4e77f0b 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -293,7 +293,7 @@
 
     /**
      * @return The callback to be invoked with an item in this AdapterView has
-     *         been clicked, or null id no callback has been set.
+     *         been clicked, or null if no callback has been set.
      */
     @Nullable
     public final OnItemClickListener getOnItemClickListener() {
@@ -365,7 +365,7 @@
 
     /**
      * @return The callback to be invoked with an item in this AdapterView has
-     *         been clicked and held, or null id no callback as been set.
+     *         been clicked and held, or null if no callback has been set.
      */
     public final OnItemLongClickListener getOnItemLongClickListener() {
         return mOnItemLongClickListener;
diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java
index 6df76fa..e6f948f 100644
--- a/core/java/android/widget/AppSecurityPermissions.java
+++ b/core/java/android/widget/AppSecurityPermissions.java
@@ -21,6 +21,7 @@
 import android.content.DialogInterface;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
+import android.content.pm.PackageItemInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PermissionGroupInfo;
@@ -590,7 +591,8 @@
     private void addPermToList(List<MyPermissionInfo> permList,
             MyPermissionInfo pInfo) {
         if (pInfo.mLabel == null) {
-            pInfo.mLabel = pInfo.loadLabel(mPm);
+            pInfo.mLabel = pInfo.loadSafeLabel(mPm, 20000, PackageItemInfo.SAFE_LABEL_FLAG_TRIM
+                    | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE);
         }
         int idx = Collections.binarySearch(permList, pInfo, mPermComparator);
         if(localLOGV) Log.i(TAG, "idx="+idx+", list.size="+permList.size());
@@ -611,7 +613,9 @@
                 }
                 MyPermissionGroupInfo group = mPermGroups.get(pInfo.group);
                 if (group != null) {
-                    pInfo.mLabel = pInfo.loadLabel(mPm);
+                    pInfo.mLabel = pInfo.loadSafeLabel(mPm, 20000,
+                            PackageItemInfo.SAFE_LABEL_FLAG_TRIM
+                            | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE);
                     addPermToList(group.mAllPermissions, pInfo);
                     if (pInfo.mNew) {
                         addPermToList(group.mNewPermissions, pInfo);
@@ -622,14 +626,18 @@
 
         for (MyPermissionGroupInfo pgrp : mPermGroups.values()) {
             if (pgrp.labelRes != 0 || pgrp.nonLocalizedLabel != null) {
-                pgrp.mLabel = pgrp.loadLabel(mPm);
+                pgrp.mLabel = pgrp.loadSafeLabel(mPm, 20000, PackageItemInfo.SAFE_LABEL_FLAG_TRIM
+                        | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE);
             } else {
                 ApplicationInfo app;
                 try {
                     app = mPm.getApplicationInfo(pgrp.packageName, 0);
-                    pgrp.mLabel = app.loadLabel(mPm);
+                    pgrp.mLabel = app.loadSafeLabel(mPm, 20000, PackageItemInfo.SAFE_LABEL_FLAG_TRIM
+                            | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE);
                 } catch (NameNotFoundException e) {
-                    pgrp.mLabel = pgrp.loadLabel(mPm);
+                    pgrp.mLabel = pgrp.loadSafeLabel(mPm, 20000,
+                            PackageItemInfo.SAFE_LABEL_FLAG_TRIM
+                            | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE);
                 }
             }
             mPermGroupsList.add(pgrp);
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 1372987..67b7100a 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -80,7 +80,7 @@
  *
  * <p>
  * To learn more about Drawables, see: <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.
- * To learn more about working with Bitmaps, see: <a href="{@docRoot}topic/performance/graphics/index.htm">Handling Bitmaps</a>.
+ * To learn more about working with Bitmaps, see: <a href="{@docRoot}topic/performance/graphics/index.html">Handling Bitmaps</a>.
  * </p>
  *
  * @attr ref android.R.styleable#ImageView_adjustViewBounds
diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java
index f6a69d9..5778544 100644
--- a/core/java/com/android/internal/app/PlatLogoActivity.java
+++ b/core/java/com/android/internal/app/PlatLogoActivity.java
@@ -18,6 +18,9 @@
 
 import android.animation.TimeAnimator;
 import android.app.Activity;
+import android.content.ActivityNotFoundException;
+import android.content.ContentResolver;
+import android.content.Intent;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.ColorFilter;
@@ -25,12 +28,15 @@
 import android.graphics.Path;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
+import android.provider.Settings;
 import android.util.Log;
 import android.view.MotionEvent;
 import android.view.MotionEvent.PointerCoords;
 import android.view.View;
 import android.widget.FrameLayout;
 
+import org.json.JSONObject;
+
 public class PlatLogoActivity extends Activity {
     FrameLayout layout;
     TimeAnimator anim;
@@ -87,7 +93,7 @@
             darkest = 0;
             for (int i=0; i<slots; i++) {
                 palette[i] = Color.HSVToColor(color);
-                color[0] += 360f/slots;
+                color[0] = (color[0] + 360f/slots) % 360f;
                 if (lum(palette[i]) < lum(palette[darkest])) darkest = i;
             }
 
@@ -178,27 +184,97 @@
         bg = new PBackground();
         layout.setBackground(bg);
 
+        final ContentResolver cr = getContentResolver();
+
         layout.setOnTouchListener(new View.OnTouchListener() {
+            final String TOUCH_STATS = "touch.stats";
+
             final PointerCoords pc0 = new PointerCoords();
             final PointerCoords pc1 = new PointerCoords();
 
+            double pressure_min, pressure_max;
+            int maxPointers;
+            int tapCount;
+
             @Override
             public boolean onTouch(View v, MotionEvent event) {
+                final float pressure = event.getPressure();
                 switch (event.getActionMasked()) {
                     case MotionEvent.ACTION_DOWN:
+                        pressure_min = pressure_max = pressure;
+                        // fall through
                     case MotionEvent.ACTION_MOVE:
-                        if (event.getPointerCount() > 1) {
+                        if (pressure < pressure_min) pressure_min = pressure;
+                        if (pressure > pressure_max) pressure_max = pressure;
+                        final int pc = event.getPointerCount();
+                        if (pc > maxPointers) maxPointers = pc;
+                        if (pc > 1) {
                             event.getPointerCoords(0, pc0);
                             event.getPointerCoords(1, pc1);
                             bg.setRadius((float) Math.hypot(pc0.x - pc1.x, pc0.y - pc1.y) / 2f);
                         }
                         break;
+                    case MotionEvent.ACTION_CANCEL:
+                    case MotionEvent.ACTION_UP:
+                        try {
+                            final String touchDataJson = Settings.System.getString(cr, TOUCH_STATS);
+                            final JSONObject touchData = new JSONObject(
+                                    touchDataJson != null ? touchDataJson : "{}");
+                            if (touchData.has("min")) {
+                                pressure_min = Math.min(pressure_min, touchData.getDouble("min"));
+                            }
+                            if (touchData.has("max")) {
+                                pressure_max = Math.max(pressure_max, touchData.getDouble("max"));
+                            }
+                            touchData.put("min", pressure_min);
+                            touchData.put("max", pressure_max);
+                            Settings.System.putString(cr, TOUCH_STATS, touchData.toString());
+                        } catch (Exception e) {
+                            Log.e("PlatLogoActivity", "Can't write touch settings", e);
+                        }
+
+                        if (maxPointers == 1) {
+                            tapCount ++;
+                            if (tapCount < 7) {
+                                bg.randomizePalette();
+                            } else {
+                                launchNextStage();
+                            }
+                        } else {
+                            tapCount = 0;
+                        }
+                        maxPointers = 0;
+                        break;
                 }
                 return true;
             }
         });
     }
 
+    private void launchNextStage() {
+        final ContentResolver cr = getContentResolver();
+
+        if (Settings.System.getLong(cr, Settings.System.EGG_MODE, 0) == 0) {
+            // For posterity: the moment this user unlocked the easter egg
+            try {
+                Settings.System.putLong(cr,
+                        Settings.System.EGG_MODE,
+                        System.currentTimeMillis());
+            } catch (RuntimeException e) {
+                Log.e("PlatLogoActivity", "Can't write settings", e);
+            }
+        }
+        try {
+            startActivity(new Intent(Intent.ACTION_MAIN)
+                    .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_CLEAR_TASK)
+                    .addCategory("com.android.internal.category.PLATLOGO"));
+        } catch (ActivityNotFoundException ex) {
+            Log.e("PlatLogoActivity", "No more eggs.");
+        }
+        finish();
+    }
+
     @Override
     public void onStart() {
         super.onStart();
diff --git a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
index 26fb6b64..07bb453 100644
--- a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
+++ b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
@@ -27,9 +27,11 @@
 public class AmbientDisplayConfiguration {
 
     private final Context mContext;
+    private final boolean mAlwaysOnByDefault;
 
     public AmbientDisplayConfiguration(Context context) {
         mContext = context;
+        mAlwaysOnByDefault = mContext.getResources().getBoolean(R.bool.config_dozeAlwaysOnEnabled);
     }
 
     public boolean enabled(int user) {
@@ -101,8 +103,8 @@
     }
 
     public boolean alwaysOnEnabled(int user) {
-        return boolSettingDefaultOn(Settings.Secure.DOZE_ALWAYS_ON, user) && alwaysOnAvailable()
-                && !accessibilityInversionEnabled(user);
+        return boolSetting(Settings.Secure.DOZE_ALWAYS_ON, user, mAlwaysOnByDefault ? 1 : 0)
+                && alwaysOnAvailable() && !accessibilityInversionEnabled(user);
     }
 
     public boolean alwaysOnAvailable() {
diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java
index 0fd6109..4ba93bc 100644
--- a/core/java/com/android/internal/widget/MessagingLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLayout.java
@@ -60,6 +60,13 @@
 public class MessagingLayout extends FrameLayout {
 
     private static final float COLOR_SHIFT_AMOUNT = 60;
+    /**
+     *  Pattren for filter some ingonable characters.
+     *  p{Z} for any kind of whitespace or invisible separator.
+     *  p{C} for any kind of punctuation character.
+     */
+    private static final Pattern IGNORABLE_CHAR_PATTERN
+            = Pattern.compile("[\\p{C}\\p{Z}]");
     private static final Pattern SPECIAL_CHAR_PATTERN
             = Pattern.compile ("[!@#$%&*()_+=|<>?{}\\[\\]~-]");
     private static final Consumer<MessagingMessage> REMOVE_MESSAGE
@@ -233,7 +240,10 @@
                 continue;
             }
             if (!uniqueNames.containsKey(senderName)) {
-                char c = senderName.charAt(0);
+                // Only use visible characters to get uniqueNames
+                String pureSenderName = IGNORABLE_CHAR_PATTERN
+                        .matcher(senderName).replaceAll("" /* replacement */);
+                char c = pureSenderName.charAt(0);
                 if (uniqueCharacters.containsKey(c)) {
                     // this character was already used, lets make it more unique. We first need to
                     // resolve the existing character if it exists
@@ -245,7 +255,7 @@
                     uniqueNames.put(senderName, findNameSplit((String) senderName));
                 } else {
                     uniqueNames.put(senderName, Character.toString(c));
-                    uniqueCharacters.put(c, senderName);
+                    uniqueCharacters.put(c, pureSenderName);
                 }
             }
         }
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index caf4e4b4..e30a3e7 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -45,6 +45,7 @@
 #include <unistd.h>
 
 #include "android-base/logging.h"
+#include <android-base/properties.h>
 #include <android-base/file.h>
 #include <android-base/stringprintf.h>
 #include <cutils/fs.h>
@@ -70,6 +71,7 @@
 using android::String8;
 using android::base::StringPrintf;
 using android::base::WriteStringToFile;
+using android::base::GetBoolProperty;
 
 #define CREATE_ERROR(...) StringPrintf("%s:%d: ", __FILE__, __LINE__). \
                               append(StringPrintf(__VA_ARGS__))
@@ -931,12 +933,16 @@
           RuntimeAbort(env, __LINE__, "System server process has died. Restarting Zygote!");
       }
 
-      // Assign system_server to the correct memory cgroup.
-      // Not all devices mount /dev/memcg so check for the file first
-      // to avoid unnecessarily printing errors and denials in the logs.
-      if (!access("/dev/memcg/system/tasks", F_OK) &&
+      bool low_ram_device = GetBoolProperty("ro.config.low_ram", false);
+      bool per_app_memcg = GetBoolProperty("ro.config.per_app_memcg", low_ram_device);
+      if (per_app_memcg) {
+          // Assign system_server to the correct memory cgroup.
+          // Not all devices mount /dev/memcg so check for the file first
+          // to avoid unnecessarily printing errors and denials in the logs.
+          if (!access("/dev/memcg/system/tasks", F_OK) &&
                 !WriteStringToFile(StringPrintf("%d", pid), "/dev/memcg/system/tasks")) {
-        ALOGE("couldn't write %d to /dev/memcg/system/tasks", pid);
+              ALOGE("couldn't write %d to /dev/memcg/system/tasks", pid);
+          }
       }
   }
   return pid;
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index 7467d8f..2de53b9 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -319,6 +319,8 @@
     optional bool removed = 36;
     optional bool is_on_screen = 37;
     optional bool is_visible = 38;
+    optional bool pending_forced_seamless_rotation = 39;
+    optional int64 finished_forced_seamless_rotation_frame = 40;
 }
 
 message IdentifierProto {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ac9617c..b1be683 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2238,7 +2238,8 @@
         android:description="@string/permdesc_install_shortcut"
         android:protectionLevel="normal"/>
 
-    <!--This permission is no longer supported.
+    <!-- <p class="caution"><strong>Don't use this permission in your app.</strong><br>This
+         permission is no longer supported.
     -->
     <permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT"
         android:label="@string/permlab_uninstall_shortcut"
@@ -3025,6 +3026,15 @@
     <permission android:name="android.permission.INSTALL_PACKAGE_UPDATES"
         android:protectionLevel="signature|privileged" />
 
+    <!-- Allows an application to install existing system packages. This is a limited
+         version of {@link android.Manifest.permission#INSTALL_PACKAGES}.
+         <p>Not for use by third-party applications.
+         TODO(b/80204953): remove this permission once we have a long-term solution.
+         @hide
+    -->
+    <permission android:name="com.android.permission.INSTALL_EXISTING_PACKAGES"
+        android:protectionLevel="signature|privileged" />
+
     <!-- @SystemApi Allows an application to clear user data.
          <p>Not for use by third-party applications
          @hide
diff --git a/core/res/res/anim/lock_screen_behind_enter_fade_in.xml b/core/res/res/anim/lock_screen_behind_enter_fade_in.xml
index e9475f5..ff95aea 100644
--- a/core/res/res/anim/lock_screen_behind_enter_fade_in.xml
+++ b/core/res/res/anim/lock_screen_behind_enter_fade_in.xml
@@ -16,7 +16,6 @@
   -->
 
 <alpha xmlns:android="http://schemas.android.com/apk/res/android"
-    android:background="#ff000000"
     android:detachWallpaper="true"
     android:shareInterpolator="false"
     android:interpolator="@interpolator/linear"
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 9d36694..bf302af 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -42,13 +42,13 @@
         <item><xliff:g id="id">@string/status_bar_phone_evdo_signal</xliff:g></item>
         <item><xliff:g id="id">@string/status_bar_phone_signal</xliff:g></item>
         <item><xliff:g id="id">@string/status_bar_secure</xliff:g></item>
-        <item><xliff:g id="id">@string/status_bar_bluetooth</xliff:g></item>
         <item><xliff:g id="id">@string/status_bar_managed_profile</xliff:g></item>
         <item><xliff:g id="id">@string/status_bar_cast</xliff:g></item>
         <item><xliff:g id="id">@string/status_bar_vpn</xliff:g></item>
+        <item><xliff:g id="id">@string/status_bar_bluetooth</xliff:g></item>
+        <item><xliff:g id="id">@string/status_bar_location</xliff:g></item>
         <item><xliff:g id="id">@string/status_bar_mute</xliff:g></item>
         <item><xliff:g id="id">@string/status_bar_volume</xliff:g></item>
-        <item><xliff:g id="id">@string/status_bar_location</xliff:g></item>
         <item><xliff:g id="id">@string/status_bar_zen</xliff:g></item>
         <item><xliff:g id="id">@string/status_bar_ethernet</xliff:g></item>
         <item><xliff:g id="id">@string/status_bar_wifi</xliff:g></item>
@@ -667,9 +667,27 @@
     <!-- Boolean indicating that wifi only link configuratios that have exact same credentials (i.e PSK) -->
     <bool translatable="false" name="config_wifi_only_link_same_credential_configurations">true</bool>
 
-    <!-- Boolean indicating whether framework needs to set the tx power limit for meeting SAR requirements
-         during voice calls -->
-    <bool translatable="false" name="config_wifi_framework_enable_voice_call_sar_tx_power_limit">false</bool>
+    <!-- Boolean indicating whether framework needs to set the tx power limit for meeting SAR requirements -->
+    <bool translatable="false" name="config_wifi_framework_enable_sar_tx_power_limit">false</bool>
+
+    <!-- Boolean indicating whether framework needs to use body proximity to set the tx power limit
+         for meeting SAR requirements -->
+    <bool translatable="false" name="config_wifi_framework_enable_body_proximity_sar_tx_power_limit">false</bool>
+
+    <!-- String for the sensor type for body/head proximity for SAR -->
+    <string translatable="false" name="config_wifi_sar_sensor_type"></string>
+
+    <!-- Integer indicating event id by sar sensor for free space -->
+    <integer translatable="false" name="config_wifi_framework_sar_free_space_event_id">1</integer>
+
+    <!-- Integer indicating event id by sar sensor for near hand -->
+    <integer translatable="false" name="config_wifi_framework_sar_near_hand_event_id">2</integer>
+
+    <!-- Integer indicating event id by sar sensor for near head -->
+    <integer translatable="false" name="config_wifi_framework_sar_near_head_event_id">3</integer>
+
+    <!-- Integer indicating event id by sar sensor for near body -->
+    <integer translatable="false" name="config_wifi_framework_sar_near_body_event_id">4</integer>
 
     <!-- Wifi driver supports batched scan -->
     <bool translatable="false" name="config_wifi_batched_scan_supported">false</bool>
@@ -2093,6 +2111,10 @@
          states. -->
     <bool name="config_dozeAlwaysOnDisplayAvailable">false</bool>
 
+    <!-- Control whether the always on display mode is enabled by default. This value will be used
+         during initialization when the setting is still null. -->
+    <bool name="config_dozeAlwaysOnEnabled">true</bool>
+
     <!-- Whether the display blanks itself when transitioning from a doze to a non-doze state -->
     <bool name="config_displayBlanksAfterDoze">false</bool>
 
@@ -2939,6 +2961,14 @@
          -->
     <string translatable="false" name="config_mainBuiltInDisplayCutout"></string>
 
+    <!-- Like config_mainBuiltInDisplayCutout, but this path is used to report the
+         one single bounding rect per device edge to the app via
+         {@link DisplayCutout#getBoundingRect}. Note that this path should try to match the visual
+         appearance of the cutout as much as possible, and may be smaller than
+         config_mainBuiltInDisplayCutout
+         -->
+    <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">@string/config_mainBuiltInDisplayCutout</string>
+
     <!-- Whether the display cutout region of the main built-in display should be forced to
          black in software (to avoid aliasing or emulate a cutout that is not physically existent).
          -->
@@ -3145,6 +3175,9 @@
     <!-- True if camera app should be pinned via Pinner Service -->
     <bool name="config_pinnerCameraApp">false</bool>
 
+    <!-- True if home app should be pinned via Pinner Service -->
+    <bool name="config_pinnerHomeApp">false</bool>
+
     <!-- Number of days preloaded file cache should be preserved on a device before it can be
          deleted -->
     <integer name="config_keepPreloadsMinDays">7</integer>
@@ -3455,4 +3488,10 @@
     <!-- Whether or not swipe up gesture's opt-in setting is available on this device -->
     <bool name="config_swipe_up_gesture_setting_available">false</bool>
 
+    <!-- Applications which are disabled unless matching a particular sku -->
+    <string-array name="config_disableApksUnlessMatchedSku_apk_list" translatable="false" />
+    <string-array name="config_disableApkUnlessMatchedSku_skus_list" translatable="false" />
+
+    <!-- Whether or not we should show the option to show battery percentage -->
+    <bool name="config_battery_percentage_setting_available">true</bool>
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 3c5159c..f660046 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3169,6 +3169,21 @@
     <!-- A notification is shown when the user connects to a Wi-Fi network and the system detects that that network has no Internet access. This is the notification's message. -->
     <string name="wifi_no_internet_detailed">Tap for options</string>
 
+    <!-- A notification is shown when the user's softap config has been changed due to underlying
+         hardware restrictions. This is the notifications's title.
+         [CHAR_LIMIT=NONE] -->
+    <string name="wifi_softap_config_change">Changes to your hotspot settings</string>
+
+    <!-- A notification is shown when the user's softap config has been changed due to underlying
+         hardware restrictions. This is the notification's summary message.
+         [CHAR_LIMIT=NONE] -->
+    <string name="wifi_softap_config_change_summary">Your hotspot band has changed.</string>
+
+    <!-- A notification is shown when the user's softap config has been changed due to underlying
+         hardware restrictions. This is the notification's full message.
+         [CHAR_LIMIT=NONE] -->
+    <string name="wifi_softap_config_change_detailed">This device doesn\u2019t support your preference for 5GHz only. Instead, this device will use the 5GHz band when available.</string>
+
     <!-- A notification might be shown if the device switches to another network type (e.g., mobile data) because it detects that the network it was using (e.g., Wi-Fi) has lost Internet connectivity. This is the notification's title. %1$s is the network type that the device switched to, e.g., cellular data. It is one of the strings in the network_switch_type_name array. -->
     <string name="network_switch_metered">Switched to <xliff:g id="network_type">%1$s</xliff:g></string>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 65606e3..cc79541 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -336,7 +336,13 @@
   <java-symbol type="bool" name="config_wifi_framework_enable_associated_network_selection" />
   <java-symbol type="bool" name="config_wifi_framework_use_single_radio_chain_scan_results_network_selection" />
   <java-symbol type="bool" name="config_wifi_only_link_same_credential_configurations" />
-  <java-symbol type="bool" name="config_wifi_framework_enable_voice_call_sar_tx_power_limit" />
+  <java-symbol type="bool" name="config_wifi_framework_enable_sar_tx_power_limit" />
+  <java-symbol type="bool" name="config_wifi_framework_enable_body_proximity_sar_tx_power_limit" />
+  <java-symbol type="string" name="config_wifi_sar_sensor_type" />
+  <java-symbol type="integer" name="config_wifi_framework_sar_free_space_event_id" />
+  <java-symbol type="integer" name="config_wifi_framework_sar_near_hand_event_id" />
+  <java-symbol type="integer" name="config_wifi_framework_sar_near_head_event_id" />
+  <java-symbol type="integer" name="config_wifi_framework_sar_near_body_event_id" />
   <java-symbol type="bool" name="config_wifi_enable_disconnection_debounce" />
   <java-symbol type="bool" name="config_wifi_revert_country_code_on_cellular_loss" />
   <java-symbol type="bool" name="config_wifi_enable_wifi_firmware_debugging" />
@@ -1055,6 +1061,9 @@
   <java-symbol type="string" name="network_switch_type_name_unknown" />
   <java-symbol type="string" name="wifi_no_internet" />
   <java-symbol type="string" name="wifi_no_internet_detailed" />
+  <java-symbol type="string" name="wifi_softap_config_change" />
+  <java-symbol type="string" name="wifi_softap_config_change_summary" />
+  <java-symbol type="string" name="wifi_softap_config_change_detailed" />
   <java-symbol type="string" name="wifi_connect_alert_title" />
   <java-symbol type="string" name="wifi_connect_alert_message" />
   <java-symbol type="string" name="wifi_connect_default_application" />
@@ -2194,6 +2203,7 @@
   <java-symbol type="string" name="ext_media_move_failure_message" />
   <java-symbol type="style" name="Animation.RecentApplications" />
   <java-symbol type="integer" name="dock_enter_exit_duration" />
+  <java-symbol type="bool" name="config_battery_percentage_setting_available" />
 
   <!-- ImfTest -->
   <java-symbol type="layout" name="auto_complete_list" />
@@ -2888,6 +2898,7 @@
   <!-- Pinner Service -->
   <java-symbol type="array" name="config_defaultPinnerServiceFiles" />
   <java-symbol type="bool" name="config_pinnerCameraApp" />
+  <java-symbol type="bool" name="config_pinnerHomeApp" />
 
   <java-symbol type="string" name="config_doubleTouchGestureEnableFile" />
 
@@ -3232,6 +3243,7 @@
   <java-symbol type="dimen" name="config_inCallNotificationVolume" />
   <java-symbol type="string" name="config_inCallNotificationSound" />
   <java-symbol type="bool" name="config_dozeAlwaysOnDisplayAvailable" />
+  <java-symbol type="bool" name="config_dozeAlwaysOnEnabled" />
   <java-symbol type="bool" name="config_displayBlanksAfterDoze" />
   <java-symbol type="bool" name="config_displayBrightnessBucketsInDoze" />
   <java-symbol type="integer" name="config_storageManagerDaystoRetainDefault" />
@@ -3327,6 +3339,7 @@
 
   <java-symbol type="string" name="global_action_logout" />
   <java-symbol type="string" name="config_mainBuiltInDisplayCutout" />
+  <java-symbol type="string" name="config_mainBuiltInDisplayCutoutRectApproximation" />
   <java-symbol type="drawable" name="messaging_user" />
   <java-symbol type="bool" name="config_fillMainBuiltInDisplayCutout" />
   <java-symbol type="drawable" name="ic_logout" />
@@ -3391,4 +3404,7 @@
 
   <java-symbol type="integer" name="config_defaultHapticFeedbackIntensity" />
   <java-symbol type="integer" name="config_defaultNotificationVibrationIntensity" />
+
+  <java-symbol type="array" name="config_disableApksUnlessMatchedSku_apk_list" />
+  <java-symbol type="array" name="config_disableApkUnlessMatchedSku_skus_list" />
 </resources>
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index dea3235..e50efa9 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -508,6 +508,8 @@
                  Settings.Secure.ANR_SHOW_BACKGROUND,
                  Settings.Secure.ASSISTANT,
                  Settings.Secure.ASSIST_DISCLOSURE_ENABLED,
+                 Settings.Secure.ASSIST_GESTURE_SENSITIVITY,
+                 Settings.Secure.ASSIST_GESTURE_SETUP_COMPLETE,
                  Settings.Secure.ASSIST_SCREENSHOT_ENABLED,
                  Settings.Secure.ASSIST_STRUCTURE_ENABLED,
                  Settings.Secure.AUTOFILL_FEATURE_FIELD_CLASSIFICATION,
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index 54358e3..e397ed9 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -57,6 +57,8 @@
 import com.android.internal.R;
 import com.android.internal.util.VirtualRefBasePtr;
 
+import dalvik.annotation.optimization.FastNative;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -64,7 +66,6 @@
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 
-import dalvik.annotation.optimization.FastNative;
 
 /**
  * This class animates properties of a {@link android.graphics.drawable.VectorDrawable} with
@@ -167,7 +168,7 @@
  * </p>
  * Below is an example of a VectorDrawable defined in vectordrawable.xml. This VectorDrawable is
  * referred to by its file name (not including file suffix) in the
- * <a href="AVDExample">AnimatedVectorDrawable XML example</a>.
+ * <a href="#AVDExample">AnimatedVectorDrawable XML example</a>.
  * <pre>
  * &lt;vector xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
  *     android:height=&quot;64dp&quot;
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index 2b5a37b..4c007cb 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -811,7 +811,7 @@
         }
 
         int errorCode = mKeyStore.importWrappedKey(
-            Credentials.USER_SECRET_KEY + alias,
+            Credentials.USER_PRIVATE_KEY + alias,
             entry.getWrappedKeyBytes(),
             Credentials.USER_PRIVATE_KEY + entry.getWrappingKeyAlias(),
             maskingKey,
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index b2e0f67..553e86e 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -268,6 +268,11 @@
     private final boolean mIsStrongBoxBacked;
     private final boolean mUserConfirmationRequired;
     private final boolean mUnlockedDeviceRequired;
+    /*
+     * ***NOTE***: All new fields MUST also be added to the following:
+     * ParcelableKeyGenParameterSpec class.
+     * The KeyGenParameterSpec.Builder constructor that takes a KeyGenParameterSpec
+     */
 
     /**
      * @hide should be built with Builder
@@ -791,6 +796,9 @@
             mUniqueIdIncluded = sourceSpec.isUniqueIdIncluded();
             mUserAuthenticationValidWhileOnBody = sourceSpec.isUserAuthenticationValidWhileOnBody();
             mInvalidatedByBiometricEnrollment = sourceSpec.isInvalidatedByBiometricEnrollment();
+            mIsStrongBoxBacked = sourceSpec.isStrongBoxBacked();
+            mUserConfirmationRequired = sourceSpec.isUserConfirmationRequired();
+            mUnlockedDeviceRequired = sourceSpec.isUnlockedDeviceRequired();
         }
 
         /**
diff --git a/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
index 911bbf8..8231dc9 100644
--- a/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
@@ -97,11 +97,14 @@
         out.writeBoolean(mSpec.isRandomizedEncryptionRequired());
         out.writeBoolean(mSpec.isUserAuthenticationRequired());
         out.writeInt(mSpec.getUserAuthenticationValidityDurationSeconds());
+        out.writeBoolean(mSpec.isUserPresenceRequired());
         out.writeByteArray(mSpec.getAttestationChallenge());
         out.writeBoolean(mSpec.isUniqueIdIncluded());
         out.writeBoolean(mSpec.isUserAuthenticationValidWhileOnBody());
         out.writeBoolean(mSpec.isInvalidatedByBiometricEnrollment());
-        out.writeBoolean(mSpec.isUserPresenceRequired());
+        out.writeBoolean(mSpec.isStrongBoxBacked());
+        out.writeBoolean(mSpec.isUserConfirmationRequired());
+        out.writeBoolean(mSpec.isUnlockedDeviceRequired());
     }
 
     private static Date readDateOrNull(Parcel in) {
@@ -114,19 +117,12 @@
     }
 
     private ParcelableKeyGenParameterSpec(Parcel in) {
-        String keystoreAlias = in.readString();
-        int purposes = in.readInt();
-        KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(
-                keystoreAlias, purposes);
-        builder.setUid(in.readInt());
-        // KeySize is -1 by default, if the KeyGenParameterSpec previously parcelled had the default
-        // value, do not set it as this will cause setKeySize to throw.
-        int keySize = in.readInt();
-        if (keySize >= 0) {
-            builder.setKeySize(keySize);
-        }
+        final String keystoreAlias = in.readString();
+        final int purposes = in.readInt();
+        final int uid = in.readInt();
+        final int keySize = in.readInt();
 
-        int keySpecType = in.readInt();
+        final int keySpecType = in.readInt();
         AlgorithmParameterSpec algorithmSpec = null;
         if (keySpecType == ALGORITHM_PARAMETER_SPEC_NONE) {
             algorithmSpec = null;
@@ -141,32 +137,60 @@
             throw new IllegalArgumentException(
                     String.format("Unknown algorithm parameter spec: %d", keySpecType));
         }
-        if (algorithmSpec != null) {
-            builder.setAlgorithmParameterSpec(algorithmSpec);
-        }
-        builder.setCertificateSubject(new X500Principal(in.createByteArray()));
-        builder.setCertificateSerialNumber(new BigInteger(in.createByteArray()));
-        builder.setCertificateNotBefore(new Date(in.readLong()));
-        builder.setCertificateNotAfter(new Date(in.readLong()));
-        builder.setKeyValidityStart(readDateOrNull(in));
-        builder.setKeyValidityForOriginationEnd(readDateOrNull(in));
-        builder.setKeyValidityForConsumptionEnd(readDateOrNull(in));
-        String[] digests = in.createStringArray();
-        if (digests != null) {
-            builder.setDigests(digests);
-        }
-        builder.setEncryptionPaddings(in.createStringArray());
-        builder.setSignaturePaddings(in.createStringArray());
-        builder.setBlockModes(in.createStringArray());
-        builder.setRandomizedEncryptionRequired(in.readBoolean());
-        builder.setUserAuthenticationRequired(in.readBoolean());
-        builder.setUserAuthenticationValidityDurationSeconds(in.readInt());
-        builder.setAttestationChallenge(in.createByteArray());
-        builder.setUniqueIdIncluded(in.readBoolean());
-        builder.setUserAuthenticationValidWhileOnBody(in.readBoolean());
-        builder.setInvalidatedByBiometricEnrollment(in.readBoolean());
-        builder.setUserPresenceRequired(in.readBoolean());
-        mSpec = builder.build();
+
+        final X500Principal certificateSubject = new X500Principal(in.createByteArray());
+        final BigInteger certificateSerialNumber = new BigInteger(in.createByteArray());
+        final Date certificateNotBefore = new Date(in.readLong());
+        final Date certificateNotAfter = new Date(in.readLong());
+        final Date keyValidityStartDate = readDateOrNull(in);
+        final Date keyValidityForOriginationEnd = readDateOrNull(in);
+        final Date keyValidityForConsumptionEnd = readDateOrNull(in);
+        final String[] digests = in.createStringArray();
+        final String[] encryptionPaddings = in.createStringArray();
+        final String[] signaturePaddings = in.createStringArray();
+        final String[] blockModes = in.createStringArray();
+        final boolean randomizedEncryptionRequired = in.readBoolean();
+        final boolean userAuthenticationRequired = in.readBoolean();
+        final int userAuthenticationValidityDurationSeconds = in.readInt();
+        final boolean userPresenceRequired = in.readBoolean();
+        final byte[] attestationChallenge = in.createByteArray();
+        final boolean uniqueIdIncluded = in.readBoolean();
+        final boolean userAuthenticationValidWhileOnBody = in.readBoolean();
+        final boolean invalidatedByBiometricEnrollment = in.readBoolean();
+        final boolean isStrongBoxBacked = in.readBoolean();
+        final boolean userConfirmationRequired = in.readBoolean();
+        final boolean unlockedDeviceRequired = in.readBoolean();
+        // The KeyGenParameterSpec is intentionally not constructed using a Builder here:
+        // The intention is for this class to break if new parameters are added to the
+        // KeyGenParameterSpec constructor (whereas using a builder would silently drop them).
+        mSpec = new KeyGenParameterSpec(
+                keystoreAlias,
+                uid,
+                keySize,
+                algorithmSpec,
+                certificateSubject,
+                certificateSerialNumber,
+                certificateNotBefore,
+                certificateNotAfter,
+                keyValidityStartDate,
+                keyValidityForOriginationEnd,
+                keyValidityForConsumptionEnd,
+                purposes,
+                digests,
+                encryptionPaddings,
+                signaturePaddings,
+                blockModes,
+                randomizedEncryptionRequired,
+                userAuthenticationRequired,
+                userAuthenticationValidityDurationSeconds,
+                userPresenceRequired,
+                attestationChallenge,
+                uniqueIdIncluded,
+                userAuthenticationValidWhileOnBody,
+                invalidatedByBiometricEnrollment,
+                isStrongBoxBacked,
+                userConfirmationRequired,
+                unlockedDeviceRequired);
     }
 
     public static final Creator<ParcelableKeyGenParameterSpec> CREATOR = new Creator<ParcelableKeyGenParameterSpec>() {
diff --git a/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java b/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java
index 254b6be..32f8ec4 100644
--- a/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java
+++ b/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java
@@ -77,6 +77,9 @@
                 .setUniqueIdIncluded(true)
                 .setUserAuthenticationValidWhileOnBody(true)
                 .setInvalidatedByBiometricEnrollment(true)
+                .setIsStrongBoxBacked(true)
+                .setUserConfirmationRequired(true)
+                .setUnlockedDeviceRequired(true)
                 .build();
     }
 
@@ -105,6 +108,9 @@
         assertThat(spec.isUniqueIdIncluded(), is(true));
         assertThat(spec.isUserAuthenticationValidWhileOnBody(), is(true));
         assertThat(spec.isInvalidatedByBiometricEnrollment(), is(true));
+        assertThat(spec.isStrongBoxBacked(), is(true));
+        assertThat(spec.isUserConfirmationRequired(), is(true));
+        assertThat(spec.isUnlockedDeviceRequired(), is(true));
     }
 
     private Parcel parcelForReading(ParcelableKeyGenParameterSpec spec) {
diff --git a/libs/androidfw/ChunkIterator.cpp b/libs/androidfw/ChunkIterator.cpp
index d8adbe5..8fc3219 100644
--- a/libs/androidfw/ChunkIterator.cpp
+++ b/libs/androidfw/ChunkIterator.cpp
@@ -32,11 +32,30 @@
 
   if (len_ != 0) {
     // Prepare the next chunk.
-    VerifyNextChunk();
+    if (VerifyNextChunkNonFatal()) {
+      VerifyNextChunk();
+    }
   }
   return Chunk(this_chunk);
 }
 
+// TODO(b/111401637) remove this and have full resource file verification
+// Returns false if there was an error.
+bool ChunkIterator::VerifyNextChunkNonFatal() {
+  if (len_ < sizeof(ResChunk_header)) {
+    last_error_ = "not enough space for header";
+    last_error_was_fatal_ = false;
+    return false;
+  }
+  const size_t size = dtohl(next_chunk_->size);
+  if (size > len_) {
+    last_error_ = "chunk size is bigger than given data";
+    last_error_was_fatal_ = false;
+    return false;
+  }
+  return true;
+}
+
 // Returns false if there was an error.
 bool ChunkIterator::VerifyNextChunk() {
   const uintptr_t header_start = reinterpret_cast<uintptr_t>(next_chunk_);
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index 04d506a..c2740c9 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -560,7 +560,9 @@
 
   if (iter.HadError()) {
     LOG(ERROR) << iter.GetLastError();
-    return {};
+    if (iter.HadFatalError()) {
+      return {};
+    }
   }
 
   // Flatten and construct the TypeSpecs.
@@ -641,7 +643,9 @@
 
   if (iter.HadError()) {
     LOG(ERROR) << iter.GetLastError();
-    return false;
+    if (iter.HadFatalError()) {
+      return false;
+    }
   }
   return true;
 }
@@ -673,7 +677,9 @@
 
   if (iter.HadError()) {
     LOG(ERROR) << iter.GetLastError();
-    return {};
+    if (iter.HadFatalError()) {
+      return {};
+    }
   }
 
   // Need to force a move for mingw32.
diff --git a/libs/androidfw/include/androidfw/Chunk.h b/libs/androidfw/include/androidfw/Chunk.h
index 89b588e..99a52dc 100644
--- a/libs/androidfw/include/androidfw/Chunk.h
+++ b/libs/androidfw/include/androidfw/Chunk.h
@@ -94,18 +94,27 @@
 
   Chunk Next();
   inline bool HasNext() const { return !HadError() && len_ != 0; };
+  // Returns whether there was an error and processing should stop
   inline bool HadError() const { return last_error_ != nullptr; }
   inline std::string GetLastError() const { return last_error_; }
+  // Returns whether there was an error and processing should stop. For legacy purposes,
+  // some errors are considered "non fatal". Fatal errors stop processing new chunks and
+  // throw away any chunks already processed. Non fatal errors also stop processing new
+  // chunks, but, will retain and use any valid chunks already processed.
+  inline bool HadFatalError() const { return HadError() && last_error_was_fatal_; }
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ChunkIterator);
 
   // Returns false if there was an error.
   bool VerifyNextChunk();
+  // Returns false if there was an error. For legacy purposes.
+  bool VerifyNextChunkNonFatal();
 
   const ResChunk_header* next_chunk_;
   size_t len_;
   const char* last_error_;
+  bool last_error_was_fatal_ = true;
 };
 
 }  // namespace android
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
index 107890e..0760f16 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
@@ -26,6 +26,7 @@
 #include "DeviceInfo.h"
 #include "Matrix.h"
 #include "Properties.h"
+#include "utils/MathUtils.h"
 
 using namespace android::uirenderer::renderthread;
 
@@ -116,9 +117,9 @@
             paint.setBlendMode(SkBlendMode::kSrc);
             // Apply a filter, which is matching OpenGL pipeline readback behaviour. Filter usage
             // is codified by tests using golden images like DecodeAccuracyTest.
-            if (skiaSrcRect.width() != bitmap->width() ||
-                skiaSrcRect.height() != bitmap->height()) {
-                // TODO: apply filter always, but check if tests will be fine
+            bool disableFilter = MathUtils::areEqual(skiaSrcRect.width(), skiaDestRect.width())
+                    && MathUtils::areEqual(skiaSrcRect.height(), skiaDestRect.height());
+            if (!disableFilter) {
                 paint.setFilterQuality(kLow_SkFilterQuality);
             }
             scaledSurface->getCanvas()->concat(textureMatrix);
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 7c68b55..2a2f4fe 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -143,7 +143,7 @@
      * MIME type for HEIF still image data encoded in HEVC.
      *
      * To decode such an image, {@link MediaCodec} decoder for
-     * {@ #MIMETYPE_VIDEO_HEVC} shall be used. The client needs to form
+     * {@link #MIMETYPE_VIDEO_HEVC} shall be used. The client needs to form
      * the correct {@link #MediaFormat} based on additional information in
      * the track format, and send it to {@link MediaCodec#configure}.
      *
diff --git a/media/java/android/media/MediaHTTPConnection.java b/media/java/android/media/MediaHTTPConnection.java
index aae1f51..6bf52bd 100644
--- a/media/java/android/media/MediaHTTPConnection.java
+++ b/media/java/android/media/MediaHTTPConnection.java
@@ -323,8 +323,10 @@
         StrictMode.setThreadPolicy(policy);
 
         try {
-            if (offset != mCurrentOffset) {
-                seekTo(offset);
+            synchronized(this) {
+                if (offset != mCurrentOffset) {
+                    seekTo(offset);
+                }
             }
 
             int n = mInputStream.read(data, 0, size);
@@ -366,7 +368,7 @@
     }
 
     @Override
-    public long getSize() {
+    public synchronized long getSize() {
         if (mConnection == null) {
             try {
                 seekTo(0);
@@ -379,7 +381,7 @@
     }
 
     @Override
-    public String getMIMEType() {
+    public synchronized String getMIMEType() {
         if (mConnection == null) {
             try {
                 seekTo(0);
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index ada91be..d532e52 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -2510,10 +2510,10 @@
         @Override
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(mTrackType);
+            dest.writeString(mFormat.getString(MediaFormat.KEY_MIME));
             dest.writeString(getLanguage());
 
             if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
-                dest.writeString(mFormat.getString(MediaFormat.KEY_MIME));
                 dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_AUTOSELECT));
                 dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_DEFAULT));
                 dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE));
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 0ba45f13..3215167 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -106,6 +106,7 @@
         "libandroid_runtime",  // ???
         "libaudioclient",  // for use of AudioTrack, AudioSystem. to be removed
         "liblog",  // NDK
+        "libbinder",
         "libdrmframework",  // for FileSource, MediaHTTP
         "libgui",  // for VideoFrameScheduler
         "libhidlallocatorutils",
@@ -122,7 +123,6 @@
     static_libs: [
         "libbacktrace",
         "libbase",
-        "libbinder",
         "libc_malloc_debug_backtrace",
         "libcrypto",
         "libcutils",
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index c36858a..a45aa90 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -612,8 +612,12 @@
     Image_setBufferItem(env, image, buffer);
     env->SetLongField(image, gSurfaceImageClassInfo.mTimestamp,
             static_cast<jlong>(buffer->mTimestamp));
+    auto transform = buffer->mTransform;
+    if (buffer->mTransformToDisplayInverse) {
+        transform |= NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
+    }
     env->SetIntField(image, gSurfaceImageClassInfo.mTransform,
-            static_cast<jint>(buffer->mTransform));
+            static_cast<jint>(transform));
     env->SetIntField(image, gSurfaceImageClassInfo.mScalingMode,
             static_cast<jint>(buffer->mScalingMode));
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
index b2be464..5ab5092 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
@@ -43,6 +43,8 @@
 import android.hardware.camera2.TotalCaptureResult;
 import android.hardware.camera2.params.InputConfiguration;
 import android.hardware.camera2.params.MeteringRectangle;
+import android.hardware.camera2.params.OutputConfiguration;
+import android.hardware.camera2.params.SessionConfiguration;
 import android.hardware.camera2.params.StreamConfigurationMap;
 import android.location.Location;
 import android.location.LocationManager;
@@ -75,6 +77,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.Executor;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicLong;
@@ -694,6 +697,38 @@
     }
 
     /**
+     * Configure a new camera session with output surfaces and initial session parameters.
+     *
+     * @param camera The CameraDevice to be configured.
+     * @param outputSurfaces The surface list that used for camera output.
+     * @param listener The callback CameraDevice will notify when session is available.
+     * @param handler The handler used to notify callbacks.
+     * @param initialRequest Initial request settings to use as session parameters.
+     */
+    public static CameraCaptureSession configureCameraSessionWithParameters(CameraDevice camera,
+            List<Surface> outputSurfaces, BlockingSessionCallback listener,
+            Handler handler, CaptureRequest initialRequest) throws CameraAccessException {
+        List<OutputConfiguration> outConfigurations = new ArrayList<>(outputSurfaces.size());
+        for (Surface surface : outputSurfaces) {
+            outConfigurations.add(new OutputConfiguration(surface));
+        }
+        SessionConfiguration sessionConfig = new SessionConfiguration(
+                SessionConfiguration.SESSION_REGULAR, outConfigurations,
+                new HandlerExecutor(handler), listener);
+        sessionConfig.setSessionParameters(initialRequest);
+        camera.createCaptureSession(sessionConfig);
+
+        CameraCaptureSession session = listener.waitAndGetSession(SESSION_CONFIGURE_TIMEOUT_MS);
+        assertFalse("Camera session should not be a reprocessable session",
+                session.isReprocessable());
+        assertFalse("Capture session type must be regular",
+                CameraConstrainedHighSpeedCaptureSession.class.isAssignableFrom(
+                        session.getClass()));
+
+        return session;
+    }
+
+    /**
      * Configure a new camera session with output surfaces and type.
      *
      * @param camera The CameraDevice to be configured.
@@ -1334,6 +1369,20 @@
         }
     }
 
+    public static class HandlerExecutor implements Executor {
+        private final Handler mHandler;
+
+        public HandlerExecutor(Handler handler) {
+            assertNotNull("handler must be valid", handler);
+            mHandler = handler;
+        }
+
+        @Override
+        public void execute(Runnable runCmd) {
+            mHandler.post(runCmd);
+        }
+    }
+
     /**
      * Provide a mock for {@link CameraDevice.StateCallback}.
      *
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2RecordingTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2RecordingTest.java
index ddb05f0..8f27fef 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2RecordingTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2RecordingTest.java
@@ -58,6 +58,7 @@
 import static com.android.mediaframeworktest.helpers.CameraTestUtils.SimpleCaptureCallback;
 import static com.android.mediaframeworktest.helpers.CameraTestUtils.SimpleImageReaderListener;
 import static com.android.mediaframeworktest.helpers.CameraTestUtils.configureCameraSession;
+import static com.android.mediaframeworktest.helpers.CameraTestUtils.configureCameraSessionWithParameters;
 import static com.android.mediaframeworktest.helpers.CameraTestUtils.getSupportedVideoSizes;
 import static com.android.mediaframeworktest.helpers.CameraTestUtils.getValueNotNull;
 
@@ -872,7 +873,6 @@
             outputSurfaces.add(mReaderSurface);
         }
         mSessionListener = new BlockingSessionCallback();
-        mSession = configureCameraSession(mCamera, outputSurfaces, mSessionListener, mHandler);
 
         CaptureRequest.Builder recordingRequestBuilder =
                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
@@ -885,7 +885,10 @@
         }
         recordingRequestBuilder.addTarget(mRecordingSurface);
         recordingRequestBuilder.addTarget(mPreviewSurface);
-        mSession.setRepeatingRequest(recordingRequestBuilder.build(), listener, mHandler);
+        CaptureRequest recordingRequest = recordingRequestBuilder.build();
+        mSession = configureCameraSessionWithParameters(mCamera, outputSurfaces, mSessionListener,
+                mHandler, recordingRequest);
+        mSession.setRepeatingRequest(recordingRequest, listener, mHandler);
 
         if (useMediaRecorder) {
             mMediaRecorder.start();
diff --git a/packages/EasterEgg/Android.bp b/packages/EasterEgg/Android.bp
new file mode 100644
index 0000000..43ed810
--- /dev/null
+++ b/packages/EasterEgg/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+android_app {
+    // the build system in pi-dev can't quite handle R.java in kt
+    // so we will have a mix of java and kotlin files
+    srcs: ["src/**/*.java", "src/**/*.kt"],
+
+    resource_dirs: ["res"],
+
+    name: "EasterEgg",
+
+    certificate: "platform",
+
+	sdk_version: "current",
+
+    optimize: {
+        enabled: false,
+    }
+}
diff --git a/packages/EasterEgg/Android.mk b/packages/EasterEgg/Android.mk
deleted file mode 100644
index 605a75d..0000000
--- a/packages/EasterEgg/Android.mk
+++ /dev/null
@@ -1,29 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    jsr305
-
-LOCAL_STATIC_ANDROID_LIBRARIES := \
-    android-support-v4 \
-    android-support-v13 \
-    android-support-dynamic-animation \
-    android-support-v7-recyclerview \
-    android-support-v7-preference \
-    android-support-v7-appcompat \
-    android-support-v14-preference
-
-LOCAL_USE_AAPT2 := true
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-
-LOCAL_PACKAGE_NAME := EasterEgg
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_CERTIFICATE := platform
-
-include $(BUILD_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/EasterEgg/AndroidManifest.xml b/packages/EasterEgg/AndroidManifest.xml
index 172490d..6651d9a 100644
--- a/packages/EasterEgg/AndroidManifest.xml
+++ b/packages/EasterEgg/AndroidManifest.xml
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-Copyright (C) 2016 The Android Open Source Project
+    Copyright (C) 2018 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
+    Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
@@ -15,85 +15,28 @@
     limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.egg"
-          android:versionCode="1"
-          android:versionName="1.0">
+    package="com.android.egg"
+    android:versionCode="1"
+    android:versionName="1.0">
 
-    <uses-sdk android:minSdkVersion="26" />
+    <uses-sdk android:minSdkVersion="28" />
 
-    <uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <application
+        android:icon="@drawable/icon"
+        android:label="@string/app_name">
 
-    <application android:label="@string/app_name" android:icon="@drawable/icon">
-
-        <activity android:name=".octo.Ocquarium"
-            android:theme="@android:style/Theme.DeviceDefault.NoActionBar.Fullscreen"
-            android:label="@string/app_name">
+        <activity
+            android:name=".paint.PaintActivity"
+            android:configChanges="orientation|keyboardHidden|screenSize|uiMode"
+            android:label="@string/app_name"
+            android:theme="@style/AppTheme">
             <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
+                <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.DEFAULT" />
+                <!--<category android:name="android.intent.category.LAUNCHER" />-->
                 <category android:name="com.android.internal.category.PLATLOGO" />
             </intent-filter>
         </activity>
-
-        <!-- Android N lives on inside Android O... -->
-
-        <!-- Long press the QS tile to get here -->
-        <activity android:name=".neko.NekoLand"
-                  android:theme="@android:style/Theme.Material.NoActionBar"
-                  android:label="@string/app_name">
-            <intent-filter>
-                <action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES" />
-                <action android:name="android.intent.action.MAIN" />
-            </intent-filter>
-        </activity>
-
-        <!-- This is where the magic happens -->
-        <service
-            android:name=".neko.NekoService"
-            android:enabled="true"
-            android:permission="android.permission.BIND_JOB_SERVICE"
-            android:exported="true" >
-        </service>
-
-        <!-- Used to show over lock screen -->
-        <activity android:name=".neko.NekoLockedActivity"
-                  android:excludeFromRecents="true"
-                  android:theme="@android:style/Theme.Material.Light.Dialog.NoActionBar"
-                  android:showOnLockScreen="true" />
-
-        <!-- Used to enable easter egg -->
-        <activity android:name=".neko.NekoActivationActivity"
-            android:excludeFromRecents="true"
-            android:theme="@android:style/Theme.NoDisplay"
-            >
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.DEFAULT" />
-            </intent-filter>
-        </activity>
-
-        <!-- The quick settings tile, disabled by default -->
-        <service
-            android:name=".neko.NekoTile"
-            android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
-            android:icon="@drawable/stat_icon"
-            android:enabled="false"
-            android:label="@string/default_tile_name">
-            <intent-filter>
-                <action android:name="android.service.quicksettings.action.QS_TILE" />
-            </intent-filter>
-        </service>
-
-        <!-- FileProvider for sending pictures -->
-        <provider
-                android:name="android.support.v4.content.FileProvider"
-                android:authorities="com.android.egg.fileprovider"
-                android:grantUriPermissions="true"
-                android:exported="false">
-            <meta-data
-                    android:name="android.support.FILE_PROVIDER_PATHS"
-                    android:resource="@xml/filepaths" />
-        </provider>
     </application>
-</manifest>
+
+</manifest>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/values/dimens.xml b/packages/EasterEgg/res/color-night/toolbar_icon_color.xml
similarity index 63%
copy from packages/EasterEgg/res/values/dimens.xml
copy to packages/EasterEgg/res/color-night/toolbar_icon_color.xml
index e9dcebd..c0a8152 100644
--- a/packages/EasterEgg/res/values/dimens.xml
+++ b/packages/EasterEgg/res/color-night/toolbar_icon_color.xml
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-Copyright (C) 2016 The Android Open Source Project
+    Copyright (C) 2018 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
+    Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
@@ -14,6 +14,7 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
-    <dimen name="neko_display_size">64dp</dimen>
-</resources>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="#FFFF3333" android:state_selected="true" />
+    <item android:color="#FFFFFFFF" />
+</selector>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/values/dimens.xml b/packages/EasterEgg/res/color/toolbar_icon_color.xml
similarity index 71%
rename from packages/EasterEgg/res/values/dimens.xml
rename to packages/EasterEgg/res/color/toolbar_icon_color.xml
index e9dcebd..d3247e4 100644
--- a/packages/EasterEgg/res/values/dimens.xml
+++ b/packages/EasterEgg/res/color/toolbar_icon_color.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-Copyright (C) 2016 The Android Open Source Project
+Copyright (C) 2018 The Android Open Source Project
 
    Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
@@ -14,6 +14,7 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
-    <dimen name="neko_display_size">64dp</dimen>
-</resources>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="#FFCC0000" android:state_selected="true" />
+    <item android:color="#FF000000" />
+</selector>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/drawable/back.xml b/packages/EasterEgg/res/drawable/back.xml
deleted file mode 100644
index b55d65c..0000000
--- a/packages/EasterEgg/res/drawable/back.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path android:name="back" android:fillColor="#FF000000" android:pathData="M37.1,22c-1.1,0 -1.9,0.8 -1.9,1.9v5.6c0,1.1 0.8,1.9 1.9,1.9H39v-1.9v-5.6V22H37.1z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/belly.xml b/packages/EasterEgg/res/drawable/belly.xml
deleted file mode 100644
index 8b0e9af..0000000
--- a/packages/EasterEgg/res/drawable/belly.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path android:name="belly" android:fillColor="#FF000000" android:pathData="M20.5,25c-3.6,0 -6.5,2.9 -6.5,6.5V38h13v-6.5C27,27.9 24.1,25 20.5,25z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/body.xml b/packages/EasterEgg/res/drawable/body.xml
deleted file mode 100644
index 8608720..0000000
--- a/packages/EasterEgg/res/drawable/body.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path android:name="body" android:fillColor="#FF000000" android:pathData="M9,20h30v18h-30z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/bowtie.xml b/packages/EasterEgg/res/drawable/bowtie.xml
deleted file mode 100644
index 33fa921..0000000
--- a/packages/EasterEgg/res/drawable/bowtie.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path android:name="bowtie" android:fillColor="#FF000000" android:pathData="M29,16.8l-10,5l0,-5l10,5z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/cap.xml b/packages/EasterEgg/res/drawable/cap.xml
deleted file mode 100644
index d8b4cc5..0000000
--- a/packages/EasterEgg/res/drawable/cap.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path android:name="cap" android:fillColor="#FF000000" android:pathData="M27.2,3.8c-1,-0.2 -2.1,-0.3 -3.2,-0.3s-2.1,0.1 -3.2,0.3c0.2,1.3 1.5,2.2 3.2,2.2C25.6,6.1 26.9,5.1 27.2,3.8z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/collar.xml b/packages/EasterEgg/res/drawable/collar.xml
deleted file mode 100644
index 5e4d0fd..0000000
--- a/packages/EasterEgg/res/drawable/collar.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path android:name="collar" android:fillColor="#FF000000" android:pathData="M9,18.4h30v1.7h-30z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/face_spot.xml b/packages/EasterEgg/res/drawable/face_spot.xml
deleted file mode 100644
index a89fb4f..0000000
--- a/packages/EasterEgg/res/drawable/face_spot.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path android:name="face_spot" android:fillColor="#FF000000" android:pathData="M19.5,15.2a4.5,3.2 0,1 0,9 0a4.5,3.2 0,1 0,-9 0z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/food_bits.xml b/packages/EasterEgg/res/drawable/food_bits.xml
deleted file mode 100644
index 1b2bb6f..0000000
--- a/packages/EasterEgg/res/drawable/food_bits.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M19.1,34l-3.5,1.3c-1,0.4,-2.2,-0.1,-2.6,-1.1l-1.2,-3c-0.4,-1,0.1,-2.2,1.1,-2.6l3.5,-1.3c1,-0.4,2.2,0.1,2.6,1.1l1.2,3   C20.6,32.4,20.1,33.6,19.1,34z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M25.2,28.1L22.9,28c-0.8,0,-1.5,-0.7,-1.4,-1.6l0.1,-2c0,-0.8,0.7,-1.5,1.6,-1.4l2.4,0.1c0.8,0,1.5,0.7,1.4,1.6l-0.1,2   C26.8,27.5,26.1,28.1,25.2,28.1z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M18.7,23.1L16.5,23c-0.5,0,-0.9,-0.4,-0.8,-0.9l0.1,-2.2c0,-0.5,0.4,-0.9,0.9,-0.8l2.2,0.1c0.5,0,0.9,0.4,0.8,0.9   l-0.1,2.2C19.6,22.8,19.2,23.1,18.7,23.1z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M32.2,35.3l-3.6,-1.8c-1,-0.5,-1.4,-1.7,-0.9,-2.7l1.6,-3.1c0.5,-1,1.7,-1.4,2.7,-0.9l3.6,1.8c1,0.5,1.4,1.7,0.9,2.7   l-1.6,3.1C34.4,35.4,33.2,35.7,32.2,35.3z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/food_chicken.xml b/packages/EasterEgg/res/drawable/food_chicken.xml
deleted file mode 100644
index 95b2fb5..0000000
--- a/packages/EasterEgg/res/drawable/food_chicken.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M9,12v14h10V11H9z M11.7,16.3c-0.7,0,-1.3,-0.6,-1.3,-1.3s0.6,-1.3,1.3,-1.3S13,14.3,13,15S12.4,16.3,11.7,16.3z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M5.7,20.1l1.6,-3.0l-1.6,-3.0l4.4,3.0z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M19.0,6.0l-2.3,2.3l-2.7,-2.6l-2.7,2.6l-2.3,-2.3l0.0,4.0l10.0,0.0z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M9,25c0,8.3,6.7,15,15,15s15,-6.7,15,-15H9z M29.9,31.5h-11v-1h12L29.9,31.5z M31.9,29.5h-13v-1h14L31.9,29.5z M33.9,27.5   h-15v-1h16L33.9,27.5z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M27.0,38.6h2.0v6.0h-2.0z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M17.4,44.6l-2.1999998,0.0l4.4000006,-6.0l2.1999989,0.0z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/food_cookie.xml b/packages/EasterEgg/res/drawable/food_cookie.xml
deleted file mode 100644
index 74dd134..0000000
--- a/packages/EasterEgg/res/drawable/food_cookie.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-    <group>
-        <path
-            android:fillColor="#55FFFFFF"
-            android:fillType="evenOdd"
-            android:pathData="M5.71 18.29A8.99 8.99 0 0 0 22 13c0-3-1.46-5.65-3.71-7.29A8.99 8.99 0 0 0 2 11c0 3 1.46 5.65 3.71 7.29z"/>
-        <path
-            android:fillColor="#FFFFFFFF"
-            android:fillType="evenOdd"
-            android:pathData="M7.25 19.18A8.5 8.5 0 0 0 19.19 7.24 9 9 0 0 1 7.24 19.19z"/>
-        <path
-            android:fillColor="#55FFFFFF"
-            android:pathData="M10.5 3a0.5 0.5 0 1 1 1 0v2.05a0.5 0.5 0 1 1-1 0V3zm3.1 0.42a0.5 0.5 0 0 1 0.93 0.39l-0.8 1.88A0.5 0.5 0 1 1 12.8 5.3l0.8-1.88zm2.7 1.57a0.5 0.5 0 1 1 0.71 0.7l-1.45 1.46a0.5 0.5 0 0 1-0.7-0.71l1.44-1.45zm1.9 2.5a0.5 0.5 0 0 1 0.38 0.92l-1.9 0.77a0.5 0.5 0 0 1-0.37-0.93l1.9-0.77zM19 10.5a0.5 0.5 0 1 1 0 1h-2.05a0.5 0.5 0 0 1 0-1H19zm-0.42 3.1a0.5 0.5 0 0 1-0.39 0.93l-1.88-0.8a0.5 0.5 0 1 1 0.39-0.92l1.88 0.8zm-1.57 2.7a0.5 0.5 0 1 1-0.7 0.71l-1.46-1.45a0.5 0.5 0 0 1 0.71-0.7l1.45 1.44zm-2.5 1.9a0.5 0.5 0 1 1-0.92 0.38l-0.77-1.9a0.5 0.5 0 0 1 0.93-0.37l0.77 1.9zM11.5 19a0.5 0.5 0 1 1-1 0v-2.05a0.5 0.5 0 0 1 1 0V19zm-3.1-0.42a0.5 0.5 0 0 1-0.93-0.39l0.8-1.88A0.5 0.5 0 0 1 9.2 16.7l-0.8 1.88zm-2.7-1.57a0.5 0.5 0 1 1-0.71-0.7l1.45-1.46a0.5 0.5 0 0 1 0.7 0.71L5.7 17.01zm-1.9-2.48a0.5 0.5 0 0 1-0.38-0.92l1.88-0.8a0.5 0.5 0 0 1 0.4 0.92l-1.9 0.8zM3 11.5a0.5 0.5 0 1 1 0-1h2.05a0.5 0.5 0 1 1 0 1H3zm0.42-3.1A0.5 0.5 0 0 1 3.8 7.46l1.88 0.8A0.5 0.5 0 1 1 5.3 9.2L3.42 8.4zm1.57-2.7a0.5 0.5 0 1 1 0.7-0.71l1.46 1.45a0.5 0.5 0 0 1-0.71 0.7L4.99 5.7zm2.5-1.9A0.5 0.5 0 0 1 8.4 3.41l0.77 1.9a0.5 0.5 0 0 1-0.93 0.37L7.48 3.8z"/>
-    </group>
-</vector>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/drawable/food_dish.xml b/packages/EasterEgg/res/drawable/food_dish.xml
deleted file mode 100644
index 3fff6a9..0000000
--- a/packages/EasterEgg/res/drawable/food_dish.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M24,13.8C11.3,13.8,1,18.3,1,24c0,5.7,10.3,10.2,23,10.2S47,29.7,47,24C47,18.3,36.7,13.8,24,13.8z M33.7,26.6   c1.1,-0.6,1.8,-1.3,1.8,-2c0,-2.1,-5.2,-3.8,-11.7,-3.8s-11.7,1.7,-11.7,3.8c0,0.6,0.4,1.2,1.2,1.7c-1.7,-0.8,-2.8,-1.7,-2.8,-2.8   c0,-2.5,6,-4.5,13.4,-4.5s13.4,2,13.4,4.5C37.4,24.7,36,25.8,33.7,26.6z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/food_donut.xml b/packages/EasterEgg/res/drawable/food_donut.xml
deleted file mode 100644
index eaf831e..0000000
--- a/packages/EasterEgg/res/drawable/food_donut.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M24,4.5c-10.5,0,-19,8.5,-19,19s8.5,19,19,19s19,-8.5,19,-19S34.5,4.5,24,4.5z M35.2,15.5l1.6,-1.1   c0.3,-0.2,0.6,-0.1,0.8,0.1l0.1,0.1c0.2,0.3,0.1,0.6,-0.1,0.8l-1.6,1.1c-0.3,0.2,-0.6,0.1,-0.8,-0.1l-0.1,-0.1   C34.9,16.1,35,15.7,35.2,15.5z M32.7,10.7c0,-0.3,0.3,-0.5,0.6,-0.5l0.1,0c0.3,0,0.5,0.3,0.5,0.6l-0.2,2c0,0.3,-0.3,0.5,-0.6,0.5l-0.1,0   c-0.3,0,-0.5,-0.3,-0.5,-0.6L32.7,10.7z M31.7,15.1l1.5,-0.2c0.2,0,0.5,0.1,0.5,0.4l0,0.1c0,0.2,-0.1,0.5,-0.4,0.5l-1.5,0.2   c-0.2,0,-0.5,-0.1,-0.5,-0.4l0,-0.1C31.3,15.4,31.5,15.2,31.7,15.1z M28.8,10.6l1.6,-1.1c0.3,-0.2,0.6,-0.1,0.8,0.1l0.1,0.1   c0.2,0.3,0.1,0.6,-0.1,0.8l-1.6,1.1c-0.3,0.2,-0.6,0.1,-0.8,-0.1l-0.1,-0.1C28.4,11.1,28.5,10.8,28.8,10.6z M25.8,6   c0,-0.3,0.3,-0.5,0.6,-0.5l0.1,0c0.3,0,0.5,0.3,0.5,0.6l-0.2,2c0,0.3,-0.3,0.5,-0.6,0.5l-0.1,0c-0.3,0,-0.5,-0.3,-0.5,-0.6L25.8,6z    M20.7,6.5l1.9,-0.7c0.3,-0.1,0.6,0,0.7,0.3l0,0.1c0.1,0.3,0,0.6,-0.3,0.7l-1.9,0.7c-0.3,0.1,-0.6,0,-0.7,-0.3l0,-0.1   C20.3,6.9,20.4,6.6,20.7,6.5z M19.9,10.9l1.5,-0.2c0.2,0,0.5,0.1,0.5,0.4l0,0.1c0,0.2,-0.1,0.5,-0.4,0.5l-1.5,0.2   c-0.2,0,-0.5,-0.1,-0.5,-0.4l0,-0.1C19.5,11.1,19.7,10.9,19.9,10.9z M16,10.9L16,10.9c0.2,-0.3,0.4,-0.4,0.6,-0.3l1.3,0.7   c0.2,0.1,0.3,0.4,0.2,0.6L18,12c-0.1,0.2,-0.4,0.3,-0.6,0.2l-1.3,-0.7C15.9,11.4,15.8,11.1,16,10.9z M15.8,18.5c0.2,0,0.4,0.1,0.5,0.4   l0,0.1c0,0.2,-0.1,0.4,-0.4,0.5l-1.5,0.2c-0.2,0,-0.4,-0.1,-0.5,-0.4l0,-0.1c0,-0.2,0.1,-0.4,0.4,-0.5L15.8,18.5z M14,21.8l-1.6,1.1   c-0.3,0.2,-0.6,0.1,-0.8,-0.1l-0.1,-0.1c-0.2,-0.3,-0.1,-0.6,0.1,-0.8l1.6,-1.1c0.3,-0.2,0.6,-0.1,0.8,0.1l0.1,0.1   C14.3,21.3,14.3,21.6,14,21.8z M12.4,12L12.4,12c0.3,-0.2,0.5,-0.2,0.7,-0.1l1,1.1c0.2,0.2,0.2,0.4,0,0.6L14,13.7   c-0.2,0.2,-0.4,0.2,-0.6,0l-1,-1.1C12.2,12.4,12.2,12.1,12.4,12z M8.3,24.5c0,0.3,-0.3,0.5,-0.6,0.5l-0.1,0c-0.3,0,-0.5,-0.3,-0.5,-0.6   l0.2,-2c0,-0.3,0.3,-0.5,0.6,-0.5l0.1,0c0.3,0,0.5,0.3,0.5,0.6L8.3,24.5z M8.5,16.2v-0.1c0,-0.3,0.2,-0.6,0.6,-0.6h2   c0.3,0,0.6,0.2,0.6,0.6v0.1c0,0.3,-0.2,0.6,-0.6,0.6H9C8.7,16.7,8.5,16.5,8.5,16.2z M10.3,20.7c-0.3,0.2,-0.6,0.1,-0.8,-0.1l-0.1,-0.1   c-0.2,-0.3,-0.1,-0.6,0.1,-0.8l1.6,-1.1c0.3,-0.2,0.6,-0.1,0.8,0.1l0.1,0.1c0.2,0.3,0.1,0.6,-0.1,0.8L10.3,20.7z M11.3,28.3l0,-0.1   c-0.1,-0.3,0,-0.6,0.3,-0.7l1.9,-0.7c0.3,-0.1,0.6,0,0.7,0.3l0,0.1c0.1,0.3,0,0.6,-0.3,0.7L12,28.6C11.7,28.7,11.4,28.6,11.3,28.3z    M14.4,33c0,0.2,-0.2,0.4,-0.4,0.4h-1.5c-0.2,0,-0.4,-0.2,-0.4,-0.4v-0.1c0,-0.2,0.2,-0.4,0.4,-0.4H14c0.2,0,0.4,0.2,0.4,0.4V33z M17.9,35.2   l-1.6,1.1c-0.3,0.2,-0.6,0.1,-0.8,-0.1l-0.1,-0.1c-0.2,-0.3,-0.1,-0.6,0.1,-0.8l1.6,-1.1c0.3,-0.2,0.6,-0.1,0.8,0.1l0.1,0.1   C18.2,34.7,18.2,35.1,17.9,35.2z M20.7,33.8l-0.1,0.1c-0.1,0.3,-0.5,0.4,-0.8,0.2l-1.7,-1c-0.3,-0.1,-0.4,-0.5,-0.2,-0.8l0.1,-0.1   c0.1,-0.3,0.5,-0.4,0.8,-0.2l1.7,1C20.7,33.2,20.8,33.5,20.7,33.8z M17.5,23.5c0,-3.6,2.9,-6.5,6.5,-6.5s6.5,2.9,6.5,6.5   c0,3.6,-2.9,6.5,-6.5,6.5S17.5,27.1,17.5,23.5z M27.4,35.7l-1.9,0.7c-0.3,0.1,-0.6,0,-0.7,-0.3l0,-0.1c-0.1,-0.3,0,-0.6,0.3,-0.7l1.9,-0.7   c0.3,-0.1,0.6,0,0.7,0.3l0,0.1C27.9,35.3,27.7,35.6,27.4,35.7z M29.7,32.7l-1.4,0.5c-0.2,0.1,-0.5,0,-0.5,-0.3l0,-0.1   c-0.1,-0.2,0,-0.5,0.3,-0.5l1.4,-0.5c0.2,-0.1,0.5,0,0.5,0.3l0,0.1C30,32.3,29.9,32.6,29.7,32.7z M32.8,35.5l-0.1,0.1   c-0.1,0.3,-0.5,0.4,-0.8,0.2l-1.7,-1c-0.3,-0.1,-0.4,-0.5,-0.2,-0.8l0.1,-0.1c0.1,-0.3,0.5,-0.4,0.8,-0.2l1.7,1C32.8,34.9,32.9,35.2,32.8,35.5z    M33.7,30.9c0,0.2,-0.2,0.4,-0.5,0.4l-0.1,0c-0.2,0,-0.4,-0.2,-0.4,-0.5l0.1,-1.5c0,-0.2,0.2,-0.4,0.5,-0.4l0.1,0c0.2,0,0.4,0.2,0.4,0.5   L33.7,30.9z M34.5,26.5l-1.3,0.9c-0.2,0.1,-0.5,0.1,-0.6,-0.1l-0.1,-0.1c-0.1,-0.2,-0.1,-0.5,0.1,-0.6l1.3,-0.9c0.2,-0.1,0.5,-0.1,0.6,0.1   l0.1,0.1C34.8,26.1,34.7,26.3,34.5,26.5z M35.6,20.6l-1.7,-1c-0.3,-0.1,-0.4,-0.5,-0.2,-0.8l0.1,-0.1c0.1,-0.3,0.5,-0.4,0.8,-0.2l1.7,1   c0.3,0.1,0.4,0.5,0.2,0.8l-0.1,0.1C36.2,20.6,35.8,20.7,35.6,20.6z M38.6,27.1l-1.6,1.1c-0.3,0.2,-0.6,0.1,-0.8,-0.1L36.1,28   c-0.2,-0.3,-0.1,-0.6,0.1,-0.8l1.6,-1.1c0.3,-0.2,0.6,-0.1,0.8,0.1l0.1,0.1C38.9,26.6,38.8,27,38.6,27.1z M39,19.4l-1.5,0.2   c-0.2,0,-0.5,-0.1,-0.5,-0.4l0,-0.1c0,-0.2,0.1,-0.5,0.4,-0.5l1.5,-0.2c0.2,0,0.5,0.1,0.5,0.4l0,0.1C39.4,19.1,39.2,19.3,39,19.4z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/food_sysuituna.xml b/packages/EasterEgg/res/drawable/food_sysuituna.xml
deleted file mode 100644
index 28cf4a2..0000000
--- a/packages/EasterEgg/res/drawable/food_sysuituna.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M46,18.4l-5.8,4.6c-3.9,-3.2,-8.9,-5.6,-14.6,-6.3l1.2,-6l-7.3,5.9C12.5,17.2,6.4,20,2,24.3l7.2,1.4L2,27   c4.3,4.2,10.4,7.1,17.3,7.6l3.1,2.5L22,34.8c7.1,0,13.5,-2.5,18.2,-6.5l5.8,4.6l-1.4,-7.2L46,18.4z M14.3,24.8l-0.6,0.6l-1.1,-1.1   l-1.1,1.1l-0.6,-0.6l1.1,-1.1l-1.1,-1.1l0.6,-0.6l1.1,1.1l1.1,-1.1l0.6,0.6l-1.1,1.1L14.3,24.8z M18.8,29.1c0.7,-0.8,1.1,-2.2,1.1,-3.8   c0,-1.6,-0.4,-3,-1.1,-3.8c1.1,0.5,1.9,2,1.9,3.8S19.9,28.5,18.8,29.1z M20.7,29.1c0.7,-0.8,1.1,-2.2,1.1,-3.8c0,-1.6,-0.4,-3,-1.1,-3.8   c1.1,0.5,1.9,2,1.9,3.8S21.8,28.5,20.7,29.1z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/foot1.xml b/packages/EasterEgg/res/drawable/foot1.xml
deleted file mode 100644
index 0d90859..0000000
--- a/packages/EasterEgg/res/drawable/foot1.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path android:name="foot1" android:fillColor="#FF000000" android:pathData="M11.5,43m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/foot2.xml b/packages/EasterEgg/res/drawable/foot2.xml
deleted file mode 100644
index 364ba0c..0000000
--- a/packages/EasterEgg/res/drawable/foot2.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path android:name="foot2" android:fillColor="#FF000000" android:pathData="M18.5,43m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/foot3.xml b/packages/EasterEgg/res/drawable/foot3.xml
deleted file mode 100644
index e3a512a..0000000
--- a/packages/EasterEgg/res/drawable/foot3.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path android:name="foot3" android:fillColor="#FF000000" android:pathData="M29.5,43m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/foot4.xml b/packages/EasterEgg/res/drawable/foot4.xml
deleted file mode 100644
index 66b78fa..0000000
--- a/packages/EasterEgg/res/drawable/foot4.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path android:name="foot4" android:fillColor="#FF000000" android:pathData="M36.5,43m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/head.xml b/packages/EasterEgg/res/drawable/head.xml
deleted file mode 100644
index df600a8..0000000
--- a/packages/EasterEgg/res/drawable/head.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path android:name="head" android:fillColor="#FF000000" android:pathData="M9,18.5c0,-8.3 6.8,-15 15,-15s15,6.7 15,15H9z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/ic_clear.xml b/packages/EasterEgg/res/drawable/ic_clear.xml
new file mode 100644
index 0000000..489dcd2
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/ic_clear.xml
@@ -0,0 +1,27 @@
+<!--
+Copyright (C) 2018 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M19,6.41l-1.41,-1.41l-5.59,5.59l-5.59,-5.59l-1.41,1.41l5.59,5.59l-5.59,5.59l1.41,1.41l5.59,-5.59l5.59,5.59l1.41,-1.41l-5.59,-5.59z"
+      android:strokeWidth="1"
+      android:fillColor="#000000"
+      android:fillType="nonZero"
+      android:strokeColor="#00000000"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/ic_close.xml b/packages/EasterEgg/res/drawable/ic_close.xml
deleted file mode 100644
index 60ea36b..0000000
--- a/packages/EasterEgg/res/drawable/ic_close.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-    Copyright (C) 2016 The Android Open Source Project
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24.0dp"
-        android:height="24.0dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M19.0,6.41L17.59,5.0 12.0,10.59 6.41,5.0 5.0,6.41 10.59,12.0 5.0,17.59 6.41,19.0 12.0,13.41 17.59,19.0 19.0,17.59 13.41,12.0z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/ic_dropper.xml b/packages/EasterEgg/res/drawable/ic_dropper.xml
new file mode 100644
index 0000000..2307309
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/ic_dropper.xml
@@ -0,0 +1,39 @@
+<!--
+Copyright (C) 2018 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M13.6789,5.6997L3,16.3784L3,20L4,21L7.6216,21L18.3004,10.3212L13.6789,5.6997ZM7,19L5,19L5,17L13.788,8.344L15.6561,10.212L7,19Z"
+      android:strokeWidth="1"
+      android:fillColor="#000000"
+      android:fillType="nonZero"
+      android:strokeColor="#00000000"/>
+  <path
+      android:pathData="M20.9983,2.4982L21.5018,3.0017C22.0876,3.5875 22.0876,4.5373 21.5018,5.1231L18.1231,8.5018C17.5373,9.0876 16.5875,9.0876 16.0017,8.5018L15.4982,7.9983C14.9124,7.4125 14.9124,6.4627 15.4982,5.8769L18.8769,2.4982C19.4627,1.9124 20.4125,1.9124 20.9983,2.4982Z"
+      android:strokeWidth="1"
+      android:fillColor="#000000"
+      android:fillType="evenOdd"
+      android:strokeColor="#00000000"/>
+  <path
+      android:pathData="M13.8284,3l7.0711,7.0711l-2.8284,2.8284l-7.0711,-7.0711z"
+      android:strokeWidth="1"
+      android:fillColor="#000000"
+      android:fillType="evenOdd"
+      android:strokeColor="#00000000"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/ic_hourglass.xml b/packages/EasterEgg/res/drawable/ic_hourglass.xml
new file mode 100644
index 0000000..fe4b9c4
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/ic_hourglass.xml
@@ -0,0 +1,27 @@
+<!--
+    Copyright (C) 2018 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.5,11L16,7.5L16,4L8,4L8,7.5L11.5,11L11.5,13L8,16.5L8,20L16,20L16,16.5L12.5,13L12.5,11ZM6,2L18,2L18,8L17.99,8L18,8.01L14,12L18,16L17.99,16.01L18,16.01L18,22L6,22L6,16.01L6.01,16.01L6,16L10,12L6,8.01L6.01,8L6,8L6,2Z"
+      android:strokeWidth="1"
+      android:fillColor="#000000"
+      android:fillType="nonZero"
+      android:strokeColor="#00000000"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/ic_share.xml b/packages/EasterEgg/res/drawable/ic_share.xml
deleted file mode 100644
index 8cebc7e..0000000
--- a/packages/EasterEgg/res/drawable/ic_share.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-    Copyright (C) 2016 The Android Open Source Project
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24.0dp"
-        android:height="24.0dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M18.0,16.08c-0.76,0.0 -1.4,0.3 -1.9,0.77L8.91,12.7c0.05,-0.2 0.09,-0.4 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.5,0.5 1.2,0.81 2.0,0.81 1.66,0.0 3.0,-1.34 3.0,-3.0s-1.34,-3.0 -3.0,-3.0 -3.0,1.34 -3.0,3.0c0.0,0.2 0.0,0.4 0.0,0.7L8.04,9.81C7.5,9.31 6.79,9.0 6.0,9.0c-1.66,0.0 -3.0,1.34 -3.0,3.0s1.34,3.0 3.0,3.0c0.79,0.0 1.5,-0.31 2.04,-0.81l7.12,4.16c0.0,0.21 0.0,0.43 0.0,0.65 0.0,1.61 1.31,2.92 2.92,2.92 1.61,0.0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/icon.xml b/packages/EasterEgg/res/drawable/icon.xml
index 5ce9e51..2306b7b 100644
--- a/packages/EasterEgg/res/drawable/icon.xml
+++ b/packages/EasterEgg/res/drawable/icon.xml
@@ -1,7 +1,7 @@
 <!--
-Copyright (C) 2017 The Android Open Source Project
+    Copyright (C) 2018 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
+    Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
@@ -13,28 +13,7 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path
-        android:pathData="M25.0,25.0m-20.5,0.0a20.5,20.5,0,1,1,41.0,0.0a20.5,20.5,0,1,1,-41.0,0.0"
-        android:fillAlpha="0.066"
-        android:fillColor="#000000"/>
-    <path
-        android:pathData="M24.0,24.0m-20.0,0.0a20.0,20.0,0,1,1,40.0,0.0a20.0,20.0,0,1,1,-40.0,0.0"
-        android:fillColor="#283593"/>
-    <path
-        android:pathData="M44,24.2010101 L33.9004889,14.101499 L14.101499,33.9004889 L24.2010101,44 C29.2525804,43.9497929 34.2887564,41.9975027 38.1431296,38.1431296 C41.9975027,34.2887564 43.9497929,29.2525804 44,24.2010101 Z"
-        android:fillColor="#1a237e"/>
-    <path
-        android:pathData="M24.0,24.0m-14.0,0.0a14.0,14.0,0,1,1,28.0,0.0a14.0,14.0,0,1,1,-28.0,0.0"
-        android:fillColor="#5c6bc0"/>
-    <path
-        android:pathData="M37.7829445,26.469236 L29.6578482,18.3441397 L18.3441397,29.6578482 L26.469236,37.7829445 C29.1911841,37.2979273 31.7972024,36.0037754 33.9004889,33.9004889 C36.0037754,31.7972024 37.2979273,29.1911841 37.7829445,26.469236 Z"
-        android:fillColor="#3f51b5"/>
-    <path
-        android:pathData="M24.0,24.0m-8.0,0.0a8.0,8.0,0,1,1,16.0,0.0a8.0,8.0,0,1,1,-16.0,0.0"
-        android:fillColor="#FFFFFF"/>
-</vector>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/icon_bg"/>
+    <foreground android:drawable="@drawable/p"/>
+</adaptive-icon>
diff --git a/packages/EasterEgg/res/xml/filepaths.xml b/packages/EasterEgg/res/drawable/icon_bg.xml
similarity index 70%
rename from packages/EasterEgg/res/xml/filepaths.xml
rename to packages/EasterEgg/res/drawable/icon_bg.xml
index 2130025..c1553ce 100644
--- a/packages/EasterEgg/res/xml/filepaths.xml
+++ b/packages/EasterEgg/res/drawable/icon_bg.xml
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-Copyright (C) 2017 The Android Open Source Project
+    Copyright (C) 2018 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
+    Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
@@ -14,6 +14,5 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<paths>
-    <external-path name="cats" path="Pictures/Cats" />
-</paths>
\ No newline at end of file
+<color xmlns:android="http://schemas.android.com/apk/res/android"
+    android:color="#C5E1A5" />
\ No newline at end of file
diff --git a/packages/EasterEgg/res/drawable/left_ear.xml b/packages/EasterEgg/res/drawable/left_ear.xml
deleted file mode 100644
index 2b98736..0000000
--- a/packages/EasterEgg/res/drawable/left_ear.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path android:name="left_ear" android:fillColor="#FF000000" android:pathData="M15.4,1l5.1000004,5.3l-6.3,2.8000002z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/left_ear_inside.xml b/packages/EasterEgg/res/drawable/left_ear_inside.xml
deleted file mode 100644
index 1d947ed..0000000
--- a/packages/EasterEgg/res/drawable/left_ear_inside.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path android:name="left_ear_inside" android:fillColor="#FF000000" android:pathData="M15.4,1l3.5,6.2l-4.7,1.9z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/left_eye.xml b/packages/EasterEgg/res/drawable/left_eye.xml
deleted file mode 100644
index 4dde1b6..0000000
--- a/packages/EasterEgg/res/drawable/left_eye.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path android:name="left_eye" android:fillColor="#FF000000" android:pathData="M20.5,11c0,1.7 -3,1.7 -3,0C17.5,9.3 20.5,9.3 20.5,11z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/leg1.xml b/packages/EasterEgg/res/drawable/leg1.xml
deleted file mode 100644
index d72c746..0000000
--- a/packages/EasterEgg/res/drawable/leg1.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path android:name="leg1" android:fillColor="#FF000000" android:pathData="M9,37h5v6h-5z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/leg2.xml b/packages/EasterEgg/res/drawable/leg2.xml
deleted file mode 100644
index a772a87..0000000
--- a/packages/EasterEgg/res/drawable/leg2.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path android:name="leg2" android:fillColor="#FF000000" android:pathData="M16,37h5v6h-5z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/leg2_shadow.xml b/packages/EasterEgg/res/drawable/leg2_shadow.xml
deleted file mode 100644
index b01bd69..0000000
--- a/packages/EasterEgg/res/drawable/leg2_shadow.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path android:name="leg2_shadow" android:fillColor="#FF000000" android:pathData="M16,37h5v3h-5z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/leg3.xml b/packages/EasterEgg/res/drawable/leg3.xml
deleted file mode 100644
index d471236..0000000
--- a/packages/EasterEgg/res/drawable/leg3.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path android:name="leg3" android:fillColor="#FF000000" android:pathData="M27,37h5v6h-5z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/leg4.xml b/packages/EasterEgg/res/drawable/leg4.xml
deleted file mode 100644
index e5868eb..0000000
--- a/packages/EasterEgg/res/drawable/leg4.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path android:name="leg4" android:fillColor="#FF000000" android:pathData="M34,37h5v6h-5z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/mouth.xml b/packages/EasterEgg/res/drawable/mouth.xml
deleted file mode 100644
index ddcf2e8..0000000
--- a/packages/EasterEgg/res/drawable/mouth.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path android:name="mouth"
-        android:strokeColor="#FF000000"
-        android:strokeWidth="1.2"
-        android:strokeLineCap="round"
-        android:pathData="M29,14.3c-0.4,0.8 -1.3,1.4 -2.3,1.4c-1.4,0 -2.7,-1.3 -2.7,-2.7
-                          M24,13c0,1.5 -1.2,2.7 -2.7,2.7c-1,0 -1.9,-0.5 -2.3,-1.4"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/nose.xml b/packages/EasterEgg/res/drawable/nose.xml
deleted file mode 100644
index d403cd1..0000000
--- a/packages/EasterEgg/res/drawable/nose.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path android:name="nose" android:fillColor="#FF000000" android:pathData="M25.2,13c0,1.3 -2.3,1.3 -2.3,0S25.2,11.7 25.2,13z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/octo_bg.xml b/packages/EasterEgg/res/drawable/octo_bg.xml
deleted file mode 100644
index 1e46cf4..0000000
--- a/packages/EasterEgg/res/drawable/octo_bg.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <gradient android:angle="-90"
-        android:startColor="#FF205090"
-        android:endColor="#FF001040"
-        android:type="linear"
-        />
-</shape>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/drawable/p.xml b/packages/EasterEgg/res/drawable/p.xml
new file mode 100644
index 0000000..596b782
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/p.xml
@@ -0,0 +1,33 @@
+<!--
+Copyright (C) 2018 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportWidth="108"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M49,65L54,65C60.075,65 65,60.075 65,54C65,47.925 60.075,43 54,43C47.925,43 43,47.925 43,54L43,108"
+      android:strokeWidth="16"
+      android:fillColor="#00000000"
+      android:strokeColor="#7CB342"
+      android:fillType="evenOdd"/>
+  <path
+      android:pathData="M51,65L54,65C60.075,65 65,60.075 65,54C65,47.925 60.075,43 54,43C47.925,43 43,47.925 43,54L43,108"
+      android:strokeWidth="8"
+      android:fillColor="#00000000"
+      android:strokeColor="#FFFFFF"
+      android:fillType="evenOdd"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/right_ear.xml b/packages/EasterEgg/res/drawable/right_ear.xml
deleted file mode 100644
index b9fb4d1..0000000
--- a/packages/EasterEgg/res/drawable/right_ear.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path android:name="right_ear" android:fillColor="#FF000000" android:pathData="M32.6,1l-5.0999985,5.3l6.299999,2.8000002z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/right_ear_inside.xml b/packages/EasterEgg/res/drawable/right_ear_inside.xml
deleted file mode 100644
index 86b6e34..0000000
--- a/packages/EasterEgg/res/drawable/right_ear_inside.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-
-    <path android:name="right_ear_inside" android:fillColor="#FF000000" android:pathData="M33.8,9.1l-4.7,-1.9l3.5,-6.2z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/right_eye.xml b/packages/EasterEgg/res/drawable/right_eye.xml
deleted file mode 100644
index a1871a6..0000000
--- a/packages/EasterEgg/res/drawable/right_eye.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path android:name="right_eye" android:fillColor="#FF000000" android:pathData="M30.5,11c0,1.7 -3,1.7 -3,0C27.5,9.3 30.5,9.3 30.5,11z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/stat_icon.xml b/packages/EasterEgg/res/drawable/stat_icon.xml
deleted file mode 100644
index 608cb20..0000000
--- a/packages/EasterEgg/res/drawable/stat_icon.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M12,2C6.5,2 2,6.5 2,12c0,5.5 4.5,10 10,10s10,-4.5 10,-10C22,6.5 17.5,2 12,2zM5.5,11c0,-1.6 3,-1.6 3,0C8.5,12.7 5.5,12.7 5.5,11zM17.5,14.6c-0.6,1 -1.7,1.7 -2.9,1.7c-1.1,0 -2,-0.6 -2.6,-1.4c-0.6,0.9 -1.6,1.4 -2.7,1.4c-1.3,0 -2.3,-0.7 -2.9,-1.8c-0.2,-0.3 0,-0.7 0.3,-0.8c0.3,-0.2 0.7,0 0.8,0.3c0.3,0.7 1,1.1 1.8,1.1c0.9,0 1.6,-0.5 1.9,-1.3c-0.2,-0.2 -0.4,-0.4 -0.4,-0.7c0,-1.3 2.3,-1.3 2.3,0c0,0.3 -0.2,0.6 -0.4,0.7c0.3,0.8 1.1,1.3 1.9,1.3c0.8,0 1.5,-0.6 1.8,-1.1c0.2,-0.3 0.6,-0.4 0.9,-0.2C17.6,13.9 17.7,14.3 17.5,14.6zM15.5,11c0,-1.6 3,-1.6 3,0C18.5,12.7 15.5,12.7 15.5,11z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M5.2,1.0l4.1000004,4.2l-5.0,2.1000004z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M18.8,1.0l-4.0999994,4.2l5.000001,2.1000004z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/tail.xml b/packages/EasterEgg/res/drawable/tail.xml
deleted file mode 100644
index 0cca23c..0000000
--- a/packages/EasterEgg/res/drawable/tail.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path android:name="tail"
-        android:strokeColor="#FF000000"
-        android:strokeWidth="5"
-        android:strokeLineCap="round"
-        android:pathData="M35,35.5h5.9c2.1,0 3.8,-1.7 3.8,-3.8v-6.2"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/tail_cap.xml b/packages/EasterEgg/res/drawable/tail_cap.xml
deleted file mode 100644
index b82f6f9..0000000
--- a/packages/EasterEgg/res/drawable/tail_cap.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path android:name="tail_cap" android:fillColor="#FF000000" android:pathData="M42.2,25.5c0,-1.4 1.1,-2.5 2.5,-2.5s2.5,1.1 2.5,2.5H42.2z"/>
-</vector>
diff --git a/packages/EasterEgg/res/drawable/tail_shadow.xml b/packages/EasterEgg/res/drawable/tail_shadow.xml
deleted file mode 100644
index bb1ff12..0000000
--- a/packages/EasterEgg/res/drawable/tail_shadow.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path android:name="tail_shadow" android:fillColor="#FF000000" android:pathData="M40,38l0,-5l-1,0l0,5z"/>
-</vector>
diff --git a/packages/EasterEgg/res/values/dimens.xml b/packages/EasterEgg/res/drawable/toolbar_bg.xml
similarity index 65%
copy from packages/EasterEgg/res/values/dimens.xml
copy to packages/EasterEgg/res/drawable/toolbar_bg.xml
index e9dcebd..0f0e702 100644
--- a/packages/EasterEgg/res/values/dimens.xml
+++ b/packages/EasterEgg/res/drawable/toolbar_bg.xml
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-Copyright (C) 2016 The Android Open Source Project
+    Copyright (C) 2018 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
+    Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
@@ -14,6 +14,6 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
-    <dimen name="neko_display_size">64dp</dimen>
-</resources>
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
+    <solid android:color="@color/toolbar_bg_color" />
+</shape>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/drawable/toolbar_button_bg.xml b/packages/EasterEgg/res/drawable/toolbar_button_bg.xml
new file mode 100644
index 0000000..1b6a53e
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/toolbar_button_bg.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2018 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+    android:color="?android:attr/colorControlHighlight">
+    <item android:id="@android:id/mask">
+        <shape android:shape="rectangle">
+            <solid android:color="@android:color/black" />
+            <corners android:radius="4dp" />
+        </shape>
+    </item>
+</ripple>
diff --git a/packages/EasterEgg/res/layout/activity_paint.xml b/packages/EasterEgg/res/layout/activity_paint.xml
new file mode 100644
index 0000000..a4c17af
--- /dev/null
+++ b/packages/EasterEgg/res/layout/activity_paint.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2018 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    xmlns:app="http://schemas.android.com/apk/res/com.android.egg"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="#666"
+    tools:context=".paint.PaintActivity"
+    android:id="@+id/contentView" >
+
+    <include layout="@layout/toolbar"
+        android:id="@+id/toolbar"
+        android:layout_width="match_parent"
+        android:layout_height="50dp"
+        android:layout_gravity="top"
+        />
+    <include layout="@layout/colors"
+        android:id="@+id/colors"
+        android:layout_width="match_parent"
+        android:layout_height="48dp"
+        android:layout_gravity="top"
+        android:visibility="gone"
+        />
+    <include layout="@layout/brushes"
+        android:id="@+id/brushes"
+        android:layout_width="match_parent"
+        android:layout_height="48dp"
+        android:layout_gravity="top"
+        android:visibility="gone"
+        />
+
+
+</FrameLayout>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/layout/brushes.xml b/packages/EasterEgg/res/layout/brushes.xml
new file mode 100644
index 0000000..0c4b849
--- /dev/null
+++ b/packages/EasterEgg/res/layout/brushes.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2018 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="horizontal"
+    android:gravity="left"
+    android:background="@drawable/toolbar_bg"
+    android:elevation="10dp"
+    >
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/layout/cat_view.xml b/packages/EasterEgg/res/layout/cat_view.xml
deleted file mode 100644
index 85b494d..0000000
--- a/packages/EasterEgg/res/layout/cat_view.xml
+++ /dev/null
@@ -1,82 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2016 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
-  except in compliance with the License. You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software distributed under the
-  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-  KIND, either express or implied. See the License for the specific language governing
-  permissions and limitations under the License.
-  -->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:minHeight="?android:attr/listPreferredItemHeightSmall"
-    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-    android:paddingTop="8dp"
-    android:paddingBottom="8dp"
-    android:background="?android:attr/selectableItemBackgroundBorderless"
-    android:gravity="center_horizontal"
-    android:clipToPadding="false">
-
-    <FrameLayout
-        android:layout_width="96dp"
-        android:layout_height="wrap_content">
-
-        <ImageView
-            android:id="@android:id/icon"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:padding="10dp"
-            android:layout_gravity="center"
-            android:scaleType="fitCenter" />
-
-        <LinearLayout
-            android:id="@+id/contextGroup"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:visibility="invisible"
-            android:layout_gravity="bottom">
-
-            <ImageView
-                android:id="@android:id/shareText"
-                android:layout_width="40dp"
-                android:layout_height="40dp"
-                android:padding="8dp"
-                android:src="@drawable/ic_share"
-                android:scaleType="fitCenter"
-                android:background="#40000000"/>
-
-            <Space
-                android:layout_width="0dp"
-                android:layout_height="0dp"
-                android:layout_weight="1" />
-
-            <ImageView
-                android:id="@android:id/closeButton"
-                android:layout_width="40dp"
-                android:layout_height="40dp"
-                android:padding="4dp"
-                android:src="@drawable/ic_close"
-                android:scaleType="fitCenter"
-                android:background="#40000000"/>
-
-        </LinearLayout>
-
-    </FrameLayout>
-
-    <TextView
-        android:id="@android:id/title"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:textAppearance="?android:attr/textAppearanceListItem"
-        android:gravity="center"/>
-</LinearLayout>
-
diff --git a/packages/EasterEgg/res/layout/colors.xml b/packages/EasterEgg/res/layout/colors.xml
new file mode 100644
index 0000000..b90f4d7
--- /dev/null
+++ b/packages/EasterEgg/res/layout/colors.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2018 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="horizontal"
+    android:gravity="left"
+    android:background="@drawable/toolbar_bg"
+    android:elevation="10dp"
+    >
+
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/layout/edit_text.xml b/packages/EasterEgg/res/layout/edit_text.xml
deleted file mode 100644
index 9f7ac802..0000000
--- a/packages/EasterEgg/res/layout/edit_text.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2016 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
-  except in compliance with the License. You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software distributed under the
-  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-  KIND, either express or implied. See the License for the specific language governing
-  permissions and limitations under the License.
-  -->
-
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:paddingStart="20dp"
-    android:paddingEnd="20dp">
-
-    <EditText
-        android:id="@android:id/edit"
-        android:maxLines="1"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"/>
-
-</FrameLayout>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/layout/food_layout.xml b/packages/EasterEgg/res/layout/food_layout.xml
deleted file mode 100644
index d0ca0c8..0000000
--- a/packages/EasterEgg/res/layout/food_layout.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2016 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
-  except in compliance with the License. You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software distributed under the
-  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-  KIND, either express or implied. See the License for the specific language governing
-  permissions and limitations under the License.
-  -->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:orientation="vertical"
-              android:layout_width="wrap_content"
-              android:layout_height="wrap_content"
-              android:background="?android:attr/selectableItemBackgroundBorderless"
-              android:paddingLeft="4dp" android:paddingRight="4dp"
-              android:paddingBottom="6dp" android:paddingTop="6dp">
-    <ImageView
-        android:layout_width="64dp"
-        android:layout_height="64dp"
-        android:id="@+id/icon"
-        android:tint="?android:attr/colorControlNormal"/>
-    <TextView android:layout_width="64dp" android:layout_height="wrap_content"
-        android:gravity="top|center_horizontal"
-        android:id="@+id/text" />
-</LinearLayout>
diff --git a/packages/EasterEgg/res/layout/neko_activity.xml b/packages/EasterEgg/res/layout/neko_activity.xml
deleted file mode 100644
index 21a4600..0000000
--- a/packages/EasterEgg/res/layout/neko_activity.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-             android:layout_width="match_parent"
-             android:layout_height="match_parent">
-    <android.support.v7.widget.RecyclerView
-        android:id="@+id/holder"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center_horizontal"/>
-</FrameLayout>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/layout/toolbar.xml b/packages/EasterEgg/res/layout/toolbar.xml
new file mode 100644
index 0000000..9a5a9c5
--- /dev/null
+++ b/packages/EasterEgg/res/layout/toolbar.xml
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2018 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<com.android.egg.paint.CutoutAvoidingToolbar
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="50dp"
+    android:orientation="horizontal"
+    android:gravity="left"
+    android:background="@drawable/toolbar_bg"
+    android:elevation="20dp"
+    >
+
+    <Space
+        android:tag="cutoutLeft"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        />
+
+    <LinearLayout
+        android:layout_width="0dp"
+        android:tag="beforeCutout"
+        android:layout_height="match_parent"
+        android:orientation="horizontal"
+        android:layout_weight="1"
+        tools:ignore="UselessParent">
+
+        <ImageButton
+            android:id="@+id/btnBrush"
+            android:layout_width="48dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:tint="@color/toolbar_icon_color"
+            android:background="@drawable/toolbar_button_bg"
+            />
+
+        <ImageButton
+            android:id="@+id/btnColor"
+            android:layout_width="48dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:tint="@color/toolbar_icon_color"
+            android:background="@drawable/toolbar_button_bg"
+            />
+
+        <ImageButton
+            android:id="@+id/btnSample"
+            android:layout_width="48dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:background="@drawable/toolbar_button_bg"
+            android:tint="@color/toolbar_icon_color"
+            android:src="@drawable/ic_dropper" />
+
+    </LinearLayout>
+
+    <Space
+        android:tag="cutoutCenter"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        />
+
+    <LinearLayout
+        android:layout_width="0dp"
+        android:tag="afterCutout"
+        android:layout_height="match_parent"
+        android:orientation="horizontal"
+        android:layout_weight="1"
+        tools:ignore="UselessParent">
+
+        <ImageButton
+            android:id="@+id/btnZen"
+            android:layout_width="48dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:background="@drawable/toolbar_button_bg"
+            android:tint="@color/toolbar_icon_color"
+            android:src="@drawable/ic_hourglass" />
+
+        <ImageButton
+            android:id="@+id/btnClear"
+            android:layout_width="48dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:background="@drawable/toolbar_button_bg"
+            android:tint="@color/toolbar_icon_color"
+            android:src="@drawable/ic_clear" />
+
+    </LinearLayout>
+
+    <Space
+        android:tag="cutoutRight"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        />
+
+</com.android.egg.paint.CutoutAvoidingToolbar>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/values/dimens.xml b/packages/EasterEgg/res/values-night/colors.xml
similarity index 65%
copy from packages/EasterEgg/res/values/dimens.xml
copy to packages/EasterEgg/res/values-night/colors.xml
index e9dcebd..7c188f7 100644
--- a/packages/EasterEgg/res/values/dimens.xml
+++ b/packages/EasterEgg/res/values-night/colors.xml
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-Copyright (C) 2016 The Android Open Source Project
+    Copyright (C) 2018 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
+    Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
@@ -14,6 +14,8 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
-    <dimen name="neko_display_size">64dp</dimen>
-</resources>
+<resources>
+    <color name="toolbar_bg_color">#FF333333</color>
+    <color name="paper_color">#FF000000</color>
+    <color name="paint_color">#FFFFFFFF</color>
+</resources>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/values-night/styles.xml b/packages/EasterEgg/res/values-night/styles.xml
new file mode 100644
index 0000000..4edf692
--- /dev/null
+++ b/packages/EasterEgg/res/values-night/styles.xml
@@ -0,0 +1,21 @@
+<!--
+    Copyright (C) 2018 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<resources>
+    <style name="AppTheme" parent="@android:style/Theme.DeviceDefault.NoActionBar.Fullscreen">
+        <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
+        <item name="android:windowLightNavigationBar">false</item>
+    </style>
+</resources>
diff --git a/packages/EasterEgg/res/xml/filepaths.xml b/packages/EasterEgg/res/values/attrs_toolbar_view.xml
similarity index 68%
copy from packages/EasterEgg/res/xml/filepaths.xml
copy to packages/EasterEgg/res/values/attrs_toolbar_view.xml
index 2130025..ed1360f 100644
--- a/packages/EasterEgg/res/xml/filepaths.xml
+++ b/packages/EasterEgg/res/values/attrs_toolbar_view.xml
@@ -1,8 +1,7 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
-Copyright (C) 2017 The Android Open Source Project
+    Copyright (C) 2018 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
+    Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
@@ -14,6 +13,7 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<paths>
-    <external-path name="cats" path="Pictures/Cats" />
-</paths>
\ No newline at end of file
+<resources>
+    <declare-styleable name="ToolbarView">
+    </declare-styleable>
+</resources>
diff --git a/packages/EasterEgg/res/values/dimens.xml b/packages/EasterEgg/res/values/colors.xml
similarity index 66%
copy from packages/EasterEgg/res/values/dimens.xml
copy to packages/EasterEgg/res/values/colors.xml
index e9dcebd..1a5388b 100644
--- a/packages/EasterEgg/res/values/dimens.xml
+++ b/packages/EasterEgg/res/values/colors.xml
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-Copyright (C) 2016 The Android Open Source Project
+    Copyright (C) 2018 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
+    Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
@@ -14,6 +14,8 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
-    <dimen name="neko_display_size">64dp</dimen>
-</resources>
+<resources>
+    <color name="toolbar_bg_color">#FFDDDDDD</color>
+    <color name="paper_color">#FFFFFFFF</color>
+    <color name="paint_color">#FF000000</color>
+</resources>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/values/strings.xml b/packages/EasterEgg/res/values/strings.xml
index 61e3834..32dbc97 100644
--- a/packages/EasterEgg/res/values/strings.xml
+++ b/packages/EasterEgg/res/values/strings.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-Copyright (C) 2016 The Android Open Source Project
+Copyright (C) 2018 The Android Open Source Project
 
    Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
@@ -15,40 +15,5 @@
     limitations under the License.
 -->
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
-    <string name="app_name" translatable="false">Android Easter Egg</string>
-    <string name="notification_name" translatable="false">Android Neko</string>
-    <string name="notification_channel_name" translatable="false">New cats</string>
-    <string name="default_tile_name" translatable="false">\????</string>
-    <string name="notification_title" translatable="false">A cat is here.</string>
-    <string name="default_cat_name" translatable="false">Cat #%s</string>
-    <string name="directory_name" translatable="false">Cats</string>
-    <string name="confirm_delete" translatable="false">Forget %s?</string>
-    <string-array name="food_names" translatable="false">
-        <item>Empty dish</item>
-        <item>Bits</item>
-        <item>Fish</item>
-        <item>Chicken</item>
-        <item>Treat</item>
-    </string-array>
-    <array name="food_icons">
-        <item>@drawable/food_dish</item>
-        <item>@drawable/food_bits</item>
-        <item>@drawable/food_sysuituna</item>
-        <item>@drawable/food_chicken</item>
-        <item>@drawable/food_cookie</item>
-    </array>
-    <integer-array name="food_intervals">
-        <item>0</item>
-        <item>15</item>
-        <item>30</item>
-        <item>60</item>
-        <item>120</item>
-    </integer-array>
-    <integer-array name="food_new_cat_prob">
-        <item>0</item>
-        <item>5</item>
-        <item>35</item>
-        <item>65</item>
-        <item>90</item>
-    </integer-array>
+    <string name="app_name" translatable="false">PAINT.APK</string>
 </resources>
diff --git a/packages/EasterEgg/res/values/styles.xml b/packages/EasterEgg/res/values/styles.xml
new file mode 100644
index 0000000..44e2ce5
--- /dev/null
+++ b/packages/EasterEgg/res/values/styles.xml
@@ -0,0 +1,23 @@
+<!--
+    Copyright (C) 2018 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<resources>
+
+    <style name="AppTheme" parent="@android:style/Theme.DeviceDefault.Light.NoActionBar.Fullscreen">
+        <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
+        <item name="android:windowLightNavigationBar">true</item>
+    </style>
+
+</resources>
diff --git a/packages/EasterEgg/src/com/android/egg/neko/Cat.java b/packages/EasterEgg/src/com/android/egg/neko/Cat.java
deleted file mode 100644
index dd1bd07..0000000
--- a/packages/EasterEgg/src/com/android/egg/neko/Cat.java
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.egg.neko;
-
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.graphics.*;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
-import android.os.Bundle;
-
-import java.io.ByteArrayOutputStream;
-import java.util.Random;
-import java.util.concurrent.ThreadLocalRandom;
-
-import com.android.egg.R;
-import com.android.internal.logging.MetricsLogger;
-
-import static com.android.egg.neko.NekoLand.CHAN_ID;
-
-public class Cat extends Drawable {
-    public static final long[] PURR = {0, 40, 20, 40, 20, 40, 20, 40, 20, 40, 20, 40};
-
-    private Random mNotSoRandom;
-    private Bitmap mBitmap;
-    private long mSeed;
-    private String mName;
-    private int mBodyColor;
-    private int mFootType;
-    private boolean mBowTie;
-
-    private synchronized Random notSoRandom(long seed) {
-        if (mNotSoRandom == null) {
-            mNotSoRandom = new Random();
-            mNotSoRandom.setSeed(seed);
-        }
-        return mNotSoRandom;
-    }
-
-    public static final float frandrange(Random r, float a, float b) {
-        return (b-a)*r.nextFloat() + a;
-    }
-
-    public static final Object choose(Random r, Object...l) {
-        return l[r.nextInt(l.length)];
-    }
-
-    public static final int chooseP(Random r, int[] a) {
-        int pct = r.nextInt(1000);
-        final int stop = a.length-2;
-        int i=0;
-        while (i<stop) {
-            pct -= a[i];
-            if (pct < 0) break;
-            i+=2;
-        }
-        return a[i+1];
-    }
-
-    public static final int getColorIndex(int q, int[] a) {
-        for(int i = 1; i < a.length; i+=2) {
-            if (a[i] == q) {
-                return i/2;
-            }
-        }
-        return -1;
-    }
-
-    public static final int[] P_BODY_COLORS = {
-            180, 0xFF212121, // black
-            180, 0xFFFFFFFF, // white
-            140, 0xFF616161, // gray
-            140, 0xFF795548, // brown
-            100, 0xFF90A4AE, // steel
-            100, 0xFFFFF9C4, // buff
-            100, 0xFFFF8F00, // orange
-              5, 0xFF29B6F6, // blue..?
-              5, 0xFFFFCDD2, // pink!?
-              5, 0xFFCE93D8, // purple?!?!?
-              4, 0xFF43A047, // yeah, why not green
-              1, 0,          // ?!?!?!
-    };
-
-    public static final int[] P_COLLAR_COLORS = {
-            250, 0xFFFFFFFF,
-            250, 0xFF000000,
-            250, 0xFFF44336,
-             50, 0xFF1976D2,
-             50, 0xFFFDD835,
-             50, 0xFFFB8C00,
-             50, 0xFFF48FB1,
-             50, 0xFF4CAF50,
-    };
-
-    public static final int[] P_BELLY_COLORS = {
-            750, 0,
-            250, 0xFFFFFFFF,
-    };
-
-    public static final int[] P_DARK_SPOT_COLORS = {
-            700, 0,
-            250, 0xFF212121,
-             50, 0xFF6D4C41,
-    };
-
-    public static final int[] P_LIGHT_SPOT_COLORS = {
-            700, 0,
-            300, 0xFFFFFFFF,
-    };
-
-    private CatParts D;
-
-    public static void tint(int color, Drawable ... ds) {
-        for (Drawable d : ds) {
-            if (d != null) {
-                d.mutate().setTint(color);
-            }
-        }
-    }
-
-    public static boolean isDark(int color) {
-        final int r = (color & 0xFF0000) >> 16;
-        final int g = (color & 0x00FF00) >> 8;
-        final int b = color & 0x0000FF;
-        return (r + g + b) < 0x80;
-    }
-
-    public Cat(Context context, long seed) {
-        D = new CatParts(context);
-        mSeed = seed;
-
-        setName(context.getString(R.string.default_cat_name,
-                String.valueOf(mSeed % 1000)));
-
-        final Random nsr = notSoRandom(seed);
-
-        // body color
-        mBodyColor = chooseP(nsr, P_BODY_COLORS);
-        if (mBodyColor == 0) mBodyColor = Color.HSVToColor(new float[] {
-                nsr.nextFloat()*360f, frandrange(nsr,0.5f,1f), frandrange(nsr,0.5f, 1f)});
-
-        tint(mBodyColor, D.body, D.head, D.leg1, D.leg2, D.leg3, D.leg4, D.tail,
-                D.leftEar, D.rightEar, D.foot1, D.foot2, D.foot3, D.foot4, D.tailCap);
-        tint(0x20000000, D.leg2Shadow, D.tailShadow);
-        if (isDark(mBodyColor)) {
-            tint(0xFFFFFFFF, D.leftEye, D.rightEye, D.mouth, D.nose);
-        }
-        tint(isDark(mBodyColor) ? 0xFFEF9A9A : 0x20D50000, D.leftEarInside, D.rightEarInside);
-
-        tint(chooseP(nsr, P_BELLY_COLORS), D.belly);
-        tint(chooseP(nsr, P_BELLY_COLORS), D.back);
-        final int faceColor = chooseP(nsr, P_BELLY_COLORS);
-        tint(faceColor, D.faceSpot);
-        if (!isDark(faceColor)) {
-            tint(0xFF000000, D.mouth, D.nose);
-        }
-
-        mFootType = 0;
-        if (nsr.nextFloat() < 0.25f) {
-            mFootType = 4;
-            tint(0xFFFFFFFF, D.foot1, D.foot2, D.foot3, D.foot4);
-        } else {
-            if (nsr.nextFloat() < 0.25f) {
-                mFootType = 2;
-                tint(0xFFFFFFFF, D.foot1, D.foot3);
-            } else if (nsr.nextFloat() < 0.25f) {
-                mFootType = 3; // maybe -2 would be better? meh.
-                tint(0xFFFFFFFF, D.foot2, D.foot4);
-            } else if (nsr.nextFloat() < 0.1f) {
-                mFootType = 1;
-                tint(0xFFFFFFFF, (Drawable) choose(nsr, D.foot1, D.foot2, D.foot3, D.foot4));
-            }
-        }
-
-        tint(nsr.nextFloat() < 0.333f ? 0xFFFFFFFF : mBodyColor, D.tailCap);
-
-        final int capColor = chooseP(nsr, isDark(mBodyColor) ? P_LIGHT_SPOT_COLORS : P_DARK_SPOT_COLORS);
-        tint(capColor, D.cap);
-        //tint(chooseP(nsr, isDark(bodyColor) ? P_LIGHT_SPOT_COLORS : P_DARK_SPOT_COLORS), D.nose);
-
-        final int collarColor = chooseP(nsr, P_COLLAR_COLORS);
-        tint(collarColor, D.collar);
-        mBowTie = nsr.nextFloat() < 0.1f;
-        tint(mBowTie ? collarColor : 0, D.bowtie);
-    }
-
-    public static Cat create(Context context) {
-        return new Cat(context, Math.abs(ThreadLocalRandom.current().nextInt()));
-    }
-
-    public Notification.Builder buildNotification(Context context) {
-        final Bundle extras = new Bundle();
-        extras.putString("android.substName", context.getString(R.string.notification_name));
-        final Intent intent = new Intent(Intent.ACTION_MAIN)
-                .setClass(context, NekoLand.class)
-                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        return new Notification.Builder(context)
-                .setSmallIcon(Icon.createWithResource(context, R.drawable.stat_icon))
-                .setLargeIcon(createNotificationLargeIcon(context))
-                .setColor(getBodyColor())
-                .setPriority(Notification.PRIORITY_LOW)
-                .setContentTitle(context.getString(R.string.notification_title))
-                .setShowWhen(true)
-                .setCategory(Notification.CATEGORY_STATUS)
-                .setContentText(getName())
-                .setContentIntent(PendingIntent.getActivity(context, 0, intent, 0))
-                .setAutoCancel(true)
-                .setChannel(CHAN_ID)
-                .setVibrate(PURR)
-                .addExtras(extras);
-    }
-
-    public long getSeed() {
-        return mSeed;
-    }
-
-    @Override
-    public void draw(Canvas canvas) {
-        final int w = Math.min(canvas.getWidth(), canvas.getHeight());
-        final int h = w;
-
-        if (mBitmap == null || mBitmap.getWidth() != w || mBitmap.getHeight() != h) {
-            mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
-            final Canvas bitCanvas = new Canvas(mBitmap);
-            slowDraw(bitCanvas, 0, 0, w, h);
-        }
-        canvas.drawBitmap(mBitmap, 0, 0, null);
-    }
-
-    private void slowDraw(Canvas canvas, int x, int y, int w, int h) {
-        for (int i = 0; i < D.drawingOrder.length; i++) {
-            final Drawable d = D.drawingOrder[i];
-            if (d != null) {
-                d.setBounds(x, y, x+w, y+h);
-                d.draw(canvas);
-            }
-        }
-
-    }
-
-    public Bitmap createBitmap(int w, int h) {
-        if (mBitmap != null && mBitmap.getWidth() == w && mBitmap.getHeight() == h) {
-            return mBitmap.copy(mBitmap.getConfig(), true);
-        }
-        Bitmap result = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
-        slowDraw(new Canvas(result), 0, 0, w, h);
-        return result;
-    }
-
-    public static Icon recompressIcon(Icon bitmapIcon) {
-        if (bitmapIcon.getType() != Icon.TYPE_BITMAP) return bitmapIcon;
-        final Bitmap bits = bitmapIcon.getBitmap();
-        final ByteArrayOutputStream ostream = new ByteArrayOutputStream(
-                bits.getWidth() * bits.getHeight() * 2); // guess 50% compression
-        final boolean ok = bits.compress(Bitmap.CompressFormat.PNG, 100, ostream);
-        if (!ok) return null;
-        return Icon.createWithData(ostream.toByteArray(), 0, ostream.size());
-    }
-
-    public Icon createNotificationLargeIcon(Context context) {
-        final Resources res = context.getResources();
-        final int w = 2*res.getDimensionPixelSize(android.R.dimen.notification_large_icon_width);
-        final int h = 2*res.getDimensionPixelSize(android.R.dimen.notification_large_icon_height);
-        return recompressIcon(createIcon(context, w, h));
-    }
-
-    public Icon createIcon(Context context, int w, int h) {
-        Bitmap result = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
-        final Canvas canvas = new Canvas(result);
-        final Paint pt = new Paint();
-        float[] hsv = new float[3];
-        Color.colorToHSV(mBodyColor, hsv);
-        hsv[2] = (hsv[2]>0.5f)
-                ? (hsv[2] - 0.25f)
-                : (hsv[2] + 0.25f);
-        pt.setColor(Color.HSVToColor(hsv));
-        float r = w/2;
-        canvas.drawCircle(r, r, r, pt);
-        int m = w/10;
-
-        slowDraw(canvas, m, m, w-m-m, h-m-m);
-
-        return Icon.createWithBitmap(result);
-    }
-
-    @Override
-    public void setAlpha(int i) {
-
-    }
-
-    @Override
-    public void setColorFilter(ColorFilter colorFilter) {
-
-    }
-
-    @Override
-    public int getOpacity() {
-        return PixelFormat.TRANSLUCENT;
-    }
-
-    public String getName() {
-        return mName;
-    }
-
-    public void setName(String name) {
-        this.mName = name;
-    }
-
-    public int getBodyColor() {
-        return mBodyColor;
-    }
-
-    public void logAdd(Context context) {
-        logCatAction(context, "egg_neko_add");
-    }
-
-    public void logRename(Context context) {
-        logCatAction(context, "egg_neko_rename");
-    }
-
-    public void logRemove(Context context) {
-        logCatAction(context, "egg_neko_remove");
-    }
-
-    public void logShare(Context context) {
-        logCatAction(context, "egg_neko_share");
-    }
-
-    private void logCatAction(Context context, String prefix) {
-        MetricsLogger.count(context, prefix, 1);
-        MetricsLogger.histogram(context, prefix +"_color",
-                getColorIndex(mBodyColor, P_BODY_COLORS));
-        MetricsLogger.histogram(context, prefix + "_bowtie", mBowTie ? 1 : 0);
-        MetricsLogger.histogram(context, prefix + "_feet", mFootType);
-    }
-
-    public static class CatParts {
-        public Drawable leftEar;
-        public Drawable rightEar;
-        public Drawable rightEarInside;
-        public Drawable leftEarInside;
-        public Drawable head;
-        public Drawable faceSpot;
-        public Drawable cap;
-        public Drawable mouth;
-        public Drawable body;
-        public Drawable foot1;
-        public Drawable leg1;
-        public Drawable foot2;
-        public Drawable leg2;
-        public Drawable foot3;
-        public Drawable leg3;
-        public Drawable foot4;
-        public Drawable leg4;
-        public Drawable tail;
-        public Drawable leg2Shadow;
-        public Drawable tailShadow;
-        public Drawable tailCap;
-        public Drawable belly;
-        public Drawable back;
-        public Drawable rightEye;
-        public Drawable leftEye;
-        public Drawable nose;
-        public Drawable bowtie;
-        public Drawable collar;
-        public Drawable[] drawingOrder;
-
-        public CatParts(Context context) {
-            body = context.getDrawable(R.drawable.body);
-            head = context.getDrawable(R.drawable.head);
-            leg1 = context.getDrawable(R.drawable.leg1);
-            leg2 = context.getDrawable(R.drawable.leg2);
-            leg3 = context.getDrawable(R.drawable.leg3);
-            leg4 = context.getDrawable(R.drawable.leg4);
-            tail = context.getDrawable(R.drawable.tail);
-            leftEar = context.getDrawable(R.drawable.left_ear);
-            rightEar = context.getDrawable(R.drawable.right_ear);
-            rightEarInside = context.getDrawable(R.drawable.right_ear_inside);
-            leftEarInside = context.getDrawable(R.drawable.left_ear_inside);
-            faceSpot = context.getDrawable(R.drawable.face_spot);
-            cap = context.getDrawable(R.drawable.cap);
-            mouth = context.getDrawable(R.drawable.mouth);
-            foot4 = context.getDrawable(R.drawable.foot4);
-            foot3 = context.getDrawable(R.drawable.foot3);
-            foot1 = context.getDrawable(R.drawable.foot1);
-            foot2 = context.getDrawable(R.drawable.foot2);
-            leg2Shadow = context.getDrawable(R.drawable.leg2_shadow);
-            tailShadow = context.getDrawable(R.drawable.tail_shadow);
-            tailCap = context.getDrawable(R.drawable.tail_cap);
-            belly = context.getDrawable(R.drawable.belly);
-            back = context.getDrawable(R.drawable.back);
-            rightEye = context.getDrawable(R.drawable.right_eye);
-            leftEye = context.getDrawable(R.drawable.left_eye);
-            nose = context.getDrawable(R.drawable.nose);
-            collar = context.getDrawable(R.drawable.collar);
-            bowtie = context.getDrawable(R.drawable.bowtie);
-            drawingOrder = getDrawingOrder();
-        }
-        private Drawable[] getDrawingOrder() {
-            return new Drawable[] {
-                    collar,
-                    leftEar, leftEarInside, rightEar, rightEarInside,
-                    head,
-                    faceSpot,
-                    cap,
-                    leftEye, rightEye,
-                    nose, mouth,
-                    tail, tailCap, tailShadow,
-                    foot1, leg1,
-                    foot2, leg2,
-                    foot3, leg3,
-                    foot4, leg4,
-                    leg2Shadow,
-                    body, belly,
-                    bowtie
-            };
-        }
-    }
-}
diff --git a/packages/EasterEgg/src/com/android/egg/neko/Food.java b/packages/EasterEgg/src/com/android/egg/neko/Food.java
deleted file mode 100644
index 5c0f12e..0000000
--- a/packages/EasterEgg/src/com/android/egg/neko/Food.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.egg.neko;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
-
-import com.android.egg.R;
-
-public class Food {
-    private final int mType;
-
-    private static int[] sIcons;
-    private static String[] sNames;
-
-    public Food(int type) {
-        mType = type;
-    }
-
-    public Icon getIcon(Context context) {
-        if (sIcons == null) {
-            TypedArray icons = context.getResources().obtainTypedArray(R.array.food_icons);
-            sIcons = new int[icons.length()];
-            for (int i = 0; i < sIcons.length; i++) {
-                sIcons[i] = icons.getResourceId(i, 0);
-            }
-            icons.recycle();
-        }
-        return Icon.createWithResource(context, sIcons[mType]);
-    }
-
-    public String getName(Context context) {
-        if (sNames == null) {
-            sNames = context.getResources().getStringArray(R.array.food_names);
-        }
-        return sNames[mType];
-    }
-
-    public long getInterval(Context context) {
-        return context.getResources().getIntArray(R.array.food_intervals)[mType];
-    }
-
-    public int getType() {
-        return mType;
-    }
-}
diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoActivationActivity.java b/packages/EasterEgg/src/com/android/egg/neko/NekoActivationActivity.java
deleted file mode 100644
index c0b725c..0000000
--- a/packages/EasterEgg/src/com/android/egg/neko/NekoActivationActivity.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.egg.neko;
-
-import android.app.Activity;
-import android.content.ComponentName;
-import android.content.pm.PackageManager;
-import android.util.Log;
-import android.widget.Toast;
-
-import com.android.internal.logging.MetricsLogger;
-
-public class NekoActivationActivity extends Activity {
-    private void toastUp(String s) {
-        Toast toast = Toast.makeText(this, s, Toast.LENGTH_SHORT);
-        toast.getView().setBackgroundDrawable(null);
-        toast.show();
-    }
-
-    @Override
-    public void onStart() {
-        super.onStart();
-
-        final PackageManager pm = getPackageManager();
-        final ComponentName cn = new ComponentName(this, NekoTile.class);
-        if (pm.getComponentEnabledSetting(cn) == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
-            if (NekoLand.DEBUG) {
-                Log.v("Neko", "Disabling tile.");
-            }
-            pm.setComponentEnabledSetting(cn, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
-                    PackageManager.DONT_KILL_APP);
-            MetricsLogger.histogram(this, "egg_neko_enable", 0);
-            toastUp("\uD83D\uDEAB");
-        } else {
-            if (NekoLand.DEBUG) {
-                Log.v("Neko", "Enabling tile.");
-            }
-            pm.setComponentEnabledSetting(cn, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
-                    PackageManager.DONT_KILL_APP);
-            MetricsLogger.histogram(this, "egg_neko_enable", 1);
-            toastUp("\uD83D\uDC31");
-        }
-        finish();
-    }
-}
diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoDialog.java b/packages/EasterEgg/src/com/android/egg/neko/NekoDialog.java
deleted file mode 100644
index 2d2fbe8..0000000
--- a/packages/EasterEgg/src/com/android/egg/neko/NekoDialog.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.egg.neko;
-
-import android.support.annotation.NonNull;
-import android.app.Dialog;
-import android.content.Context;
-import android.support.v7.widget.GridLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.egg.R;
-import com.android.internal.logging.MetricsLogger;
-
-import java.util.ArrayList;
-
-public class NekoDialog extends Dialog {
-
-    private final Adapter mAdapter;
-
-    public NekoDialog(@NonNull Context context) {
-        super(context, android.R.style.Theme_Material_Dialog_NoActionBar);
-        RecyclerView view = new RecyclerView(getContext());
-        mAdapter = new Adapter(getContext());
-        view.setLayoutManager(new GridLayoutManager(getContext(), 2));
-        view.setAdapter(mAdapter);
-        final float dp = context.getResources().getDisplayMetrics().density;
-        final int pad = (int)(16*dp);
-        view.setPadding(pad, pad, pad, pad);
-        setContentView(view);
-    }
-
-    private void onFoodSelected(Food food) {
-        PrefState prefs = new PrefState(getContext());
-        int currentState = prefs.getFoodState();
-        if (currentState == 0 && food.getType() != 0) {
-            NekoService.registerJob(getContext(), food.getInterval(getContext()));
-        }
-        MetricsLogger.histogram(getContext(), "egg_neko_offered_food", food.getType());
-        prefs.setFoodState(food.getType());
-        dismiss();
-    }
-
-    private class Adapter extends RecyclerView.Adapter<Holder> {
-
-        private final Context mContext;
-        private final ArrayList<Food> mFoods = new ArrayList<>();
-
-        public Adapter(Context context) {
-            mContext = context;
-            int[] foods = context.getResources().getIntArray(R.array.food_names);
-            // skip food 0, you can't choose it
-            for (int i=1; i<foods.length; i++) {
-                mFoods.add(new Food(i));
-            }
-        }
-
-        @Override
-        public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
-            return new Holder(LayoutInflater.from(parent.getContext())
-                    .inflate(R.layout.food_layout, parent, false));
-        }
-
-        @Override
-        public void onBindViewHolder(final Holder holder, int position) {
-            final Food food = mFoods.get(position);
-            ((ImageView) holder.itemView.findViewById(R.id.icon))
-                    .setImageIcon(food.getIcon(mContext));
-            ((TextView) holder.itemView.findViewById(R.id.text))
-                    .setText(food.getName(mContext));
-            holder.itemView.setOnClickListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    onFoodSelected(mFoods.get(holder.getAdapterPosition()));
-                }
-            });
-        }
-
-        @Override
-        public int getItemCount() {
-            return mFoods.size();
-        }
-    }
-
-    public static class Holder extends RecyclerView.ViewHolder {
-
-        public Holder(View itemView) {
-            super(itemView);
-        }
-    }
-}
diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoLand.java b/packages/EasterEgg/src/com/android/egg/neko/NekoLand.java
deleted file mode 100644
index d2e37d8..0000000
--- a/packages/EasterEgg/src/com/android/egg/neko/NekoLand.java
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.egg.neko;
-
-import android.Manifest;
-import android.app.ActionBar;
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.graphics.drawable.Drawable;
-import android.media.MediaScannerConnection;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Environment;
-import android.provider.MediaStore.Images;
-import android.support.v4.content.FileProvider;
-import android.support.v7.widget.GridLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.util.Log;
-import android.view.ContextThemeWrapper;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnLongClickListener;
-import android.view.ViewGroup;
-import android.widget.EditText;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.egg.R;
-import com.android.egg.neko.PrefState.PrefsListener;
-import com.android.internal.logging.MetricsLogger;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
-public class NekoLand extends Activity implements PrefsListener {
-    public static String CHAN_ID = "EGG";
-
-    public static boolean DEBUG = false;
-    public static boolean DEBUG_NOTIFICATIONS = false;
-
-    private static final int EXPORT_BITMAP_SIZE = 600;
-
-    private static final int STORAGE_PERM_REQUEST = 123;
-
-    private static boolean CAT_GEN = false;
-    private PrefState mPrefs;
-    private CatAdapter mAdapter;
-    private Cat mPendingShareCat;
-
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.neko_activity);
-        final ActionBar actionBar = getActionBar();
-        if (actionBar != null) {
-            actionBar.setLogo(Cat.create(this));
-            actionBar.setDisplayUseLogoEnabled(false);
-            actionBar.setDisplayShowHomeEnabled(true);
-        }
-
-        mPrefs = new PrefState(this);
-        mPrefs.setListener(this);
-        final RecyclerView recyclerView = findViewById(R.id.holder);
-        mAdapter = new CatAdapter();
-        recyclerView.setAdapter(mAdapter);
-        recyclerView.setLayoutManager(new GridLayoutManager(this, 3));
-        int numCats = updateCats();
-        MetricsLogger.histogram(this, "egg_neko_visit_gallery", numCats);
-    }
-
-    @Override
-    protected void onDestroy() {
-        super.onDestroy();
-        mPrefs.setListener(null);
-    }
-
-    private int updateCats() {
-        Cat[] cats;
-        if (CAT_GEN) {
-            cats = new Cat[50];
-            for (int i = 0; i < cats.length; i++) {
-                cats[i] = Cat.create(this);
-            }
-        } else {
-            final float[] hsv = new float[3];
-            List<Cat> list = mPrefs.getCats();
-            Collections.sort(list, new Comparator<Cat>() {
-                @Override
-                public int compare(Cat cat, Cat cat2) {
-                    Color.colorToHSV(cat.getBodyColor(), hsv);
-                    float bodyH1 = hsv[0];
-                    Color.colorToHSV(cat2.getBodyColor(), hsv);
-                    float bodyH2 = hsv[0];
-                    return Float.compare(bodyH1, bodyH2);
-                }
-            });
-            cats = list.toArray(new Cat[0]);
-        }
-        mAdapter.setCats(cats);
-        return cats.length;
-    }
-
-    private void onCatClick(Cat cat) {
-        if (CAT_GEN) {
-            mPrefs.addCat(cat);
-            new AlertDialog.Builder(NekoLand.this)
-                    .setTitle("Cat added")
-                    .setPositiveButton(android.R.string.ok, null)
-                    .show();
-        } else {
-            showNameDialog(cat);
-        }
-//      noman.notify(1, cat.buildNotification(NekoLand.this).build());
-    }
-
-    private void onCatRemove(Cat cat) {
-        cat.logRemove(this);
-        mPrefs.removeCat(cat);
-    }
-
-    private void showNameDialog(final Cat cat) {
-        final Context context = new ContextThemeWrapper(this,
-                android.R.style.Theme_Material_Light_Dialog_NoActionBar);
-        // TODO: Move to XML, add correct margins.
-        View view = LayoutInflater.from(context).inflate(R.layout.edit_text, null);
-        final EditText text = (EditText) view.findViewById(android.R.id.edit);
-        text.setText(cat.getName());
-        text.setSelection(cat.getName().length());
-        final int size = context.getResources()
-                .getDimensionPixelSize(android.R.dimen.app_icon_size);
-        Drawable catIcon = cat.createIcon(this, size, size).loadDrawable(this);
-        new AlertDialog.Builder(context)
-                .setTitle(" ")
-                .setIcon(catIcon)
-                .setView(view)
-                .setPositiveButton(android.R.string.ok, new OnClickListener() {
-                    @Override
-                    public void onClick(DialogInterface dialog, int which) {
-                        cat.logRename(context);
-                        cat.setName(text.getText().toString().trim());
-                        mPrefs.addCat(cat);
-                    }
-                }).show();
-    }
-
-    @Override
-    public void onPrefsChanged() {
-        updateCats();
-    }
-
-    private class CatAdapter extends RecyclerView.Adapter<CatHolder> {
-
-        private Cat[] mCats;
-
-        public void setCats(Cat[] cats) {
-            mCats = cats;
-            notifyDataSetChanged();
-        }
-
-        @Override
-        public CatHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-            return new CatHolder(LayoutInflater.from(parent.getContext())
-                    .inflate(R.layout.cat_view, parent, false));
-        }
-
-        private void setContextGroupVisible(final CatHolder holder, boolean vis) {
-            final View group = holder.contextGroup;
-            if (vis && group.getVisibility() != View.VISIBLE) {
-                group.setAlpha(0);
-                group.setVisibility(View.VISIBLE);
-                group.animate().alpha(1.0f).setDuration(333);
-                Runnable hideAction = new Runnable() {
-                    @Override
-                    public void run() {
-                        setContextGroupVisible(holder, false);
-                    }
-                };
-                group.setTag(hideAction);
-                group.postDelayed(hideAction, 5000);
-            } else if (!vis && group.getVisibility() == View.VISIBLE) {
-                group.removeCallbacks((Runnable) group.getTag());
-                group.animate().alpha(0f).setDuration(250).withEndAction(new Runnable() {
-                    @Override
-                    public void run() {
-                        group.setVisibility(View.INVISIBLE);
-                    }
-                });
-            }
-        }
-
-        @Override
-        public void onBindViewHolder(final CatHolder holder, int position) {
-            Context context = holder.itemView.getContext();
-            final int size = context.getResources().getDimensionPixelSize(R.dimen.neko_display_size);
-            holder.imageView.setImageIcon(mCats[position].createIcon(context, size, size));
-            holder.textView.setText(mCats[position].getName());
-            holder.itemView.setOnClickListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    onCatClick(mCats[holder.getAdapterPosition()]);
-                }
-            });
-            holder.itemView.setOnLongClickListener(new OnLongClickListener() {
-                @Override
-                public boolean onLongClick(View v) {
-                    setContextGroupVisible(holder, true);
-                    return true;
-                }
-            });
-            holder.delete.setOnClickListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    setContextGroupVisible(holder, false);
-                    new AlertDialog.Builder(NekoLand.this)
-                        .setTitle(getString(R.string.confirm_delete, mCats[position].getName()))
-                        .setNegativeButton(android.R.string.cancel, null)
-                        .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
-                            @Override
-                            public void onClick(DialogInterface dialog, int which) {
-                                onCatRemove(mCats[holder.getAdapterPosition()]);
-                            }
-                        })
-                        .show();
-                }
-            });
-            holder.share.setOnClickListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    setContextGroupVisible(holder, false);
-                    Cat cat = mCats[holder.getAdapterPosition()];
-                    if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
-                            != PackageManager.PERMISSION_GRANTED) {
-                        mPendingShareCat = cat; 
-                        requestPermissions(
-                                new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
-                                STORAGE_PERM_REQUEST);
-                        return;
-                    }
-                    shareCat(cat);
-                }
-            });
-        }
-
-        @Override
-        public int getItemCount() {
-            return mCats.length;
-        }
-    }
-
-    private void shareCat(Cat cat) {
-        final File dir = new File(
-                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
-                getString(R.string.directory_name));
-        if (!dir.exists() && !dir.mkdirs()) {
-            Log.e("NekoLand", "save: error: can't create Pictures directory");
-            return;
-        }
-        final File png = new File(dir, cat.getName().replaceAll("[/ #:]+", "_") + ".png");
-        Bitmap bitmap = cat.createBitmap(EXPORT_BITMAP_SIZE, EXPORT_BITMAP_SIZE);
-        if (bitmap != null) {
-            try {
-                OutputStream os = new FileOutputStream(png);
-                bitmap.compress(Bitmap.CompressFormat.PNG, 0, os);
-                os.close();
-                MediaScannerConnection.scanFile(
-                        this,
-                        new String[] {png.toString()},
-                        new String[] {"image/png"},
-                        null);
-                Log.v("Neko", "cat file: " + png);
-                Uri uri = FileProvider.getUriForFile(this, "com.android.egg.fileprovider", png);
-                Log.v("Neko", "cat uri: " + uri);
-                Intent intent = new Intent(Intent.ACTION_SEND);
-                intent.putExtra(Intent.EXTRA_STREAM, uri);
-                intent.putExtra(Intent.EXTRA_SUBJECT, cat.getName());
-                intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
-                intent.setType("image/png");
-                startActivity(Intent.createChooser(intent, null));
-                cat.logShare(this);
-            } catch (IOException e) {
-                Log.e("NekoLand", "save: error: " + e);
-            }
-        }
-    }
-
-    @Override
-    public void onRequestPermissionsResult(int requestCode,
-                                           String permissions[], int[] grantResults) {
-        if (requestCode == STORAGE_PERM_REQUEST) {
-            if (mPendingShareCat != null) {
-                shareCat(mPendingShareCat);
-                mPendingShareCat = null;
-            }
-        }
-    }
-
-    private static class CatHolder extends RecyclerView.ViewHolder {
-        private final ImageView imageView;
-        private final TextView textView;
-        private final View contextGroup;
-        private final View delete;
-        private final View share;
-
-        public CatHolder(View itemView) {
-            super(itemView);
-            imageView = (ImageView) itemView.findViewById(android.R.id.icon);
-            textView = (TextView) itemView.findViewById(android.R.id.title);
-            contextGroup = itemView.findViewById(R.id.contextGroup);
-            delete = itemView.findViewById(android.R.id.closeButton);
-            share = itemView.findViewById(android.R.id.shareText);
-        }
-    }
-}
diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoLockedActivity.java b/packages/EasterEgg/src/com/android/egg/neko/NekoLockedActivity.java
deleted file mode 100644
index 5f01da8..0000000
--- a/packages/EasterEgg/src/com/android/egg/neko/NekoLockedActivity.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.egg.neko;
-
-import android.support.annotation.Nullable;
-import android.app.Activity;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnDismissListener;
-import android.os.Bundle;
-import android.view.WindowManager;
-
-public class NekoLockedActivity extends Activity implements OnDismissListener {
-
-    private NekoDialog mDialog;
-
-    @Override
-    public void onCreate(@Nullable Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
-        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
-        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
-        getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
-
-        mDialog = new NekoDialog(this);
-        mDialog.setOnDismissListener(this);
-        mDialog.show();
-    }
-
-    @Override
-    public void onDismiss(DialogInterface dialog) {
-        finish();
-    }
-}
diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoService.java b/packages/EasterEgg/src/com/android/egg/neko/NekoService.java
deleted file mode 100644
index 42506e6..0000000
--- a/packages/EasterEgg/src/com/android/egg/neko/NekoService.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.egg.neko;
-
-import android.app.Notification;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.app.job.JobInfo;
-import android.app.job.JobParameters;
-import android.app.job.JobScheduler;
-import android.app.job.JobService;
-import android.content.ComponentName;
-import android.content.Context;
-import android.net.Uri;
-import android.os.Bundle;
-
-import java.util.List;
-import android.util.Log;
-
-import com.android.egg.R;
-
-import java.util.Random;
-
-import static com.android.egg.neko.Cat.PURR;
-import static com.android.egg.neko.NekoLand.CHAN_ID;
-
-public class NekoService extends JobService {
-
-    private static final String TAG = "NekoService";
-
-    public static int JOB_ID = 42;
-
-    public static int CAT_NOTIFICATION = 1;
-    public static int DEBUG_NOTIFICATION = 1234;
-
-    public static float CAT_CAPTURE_PROB = 1.0f; // generous
-
-    public static long SECONDS = 1000;
-    public static long MINUTES = 60 * SECONDS;
-
-    public static long INTERVAL_FLEX = 5 * MINUTES;
-
-    public static float INTERVAL_JITTER_FRAC = 0.25f;
-
-    private static void setupNotificationChannels(Context context) {
-        NotificationManager noman = context.getSystemService(NotificationManager.class);
-        NotificationChannel eggChan = new NotificationChannel(CHAN_ID,
-                context.getString(R.string.notification_channel_name),
-                NotificationManager.IMPORTANCE_DEFAULT);
-        eggChan.setSound(Uri.EMPTY, Notification.AUDIO_ATTRIBUTES_DEFAULT); // cats are quiet
-        eggChan.setVibrationPattern(PURR); // not totally quiet though
-        eggChan.setBlockableSystem(true); // unlike a real cat, you can push this one off your lap
-        eggChan.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC); // cats sit in the window
-        noman.createNotificationChannel(eggChan);
-    }
-
-    @Override
-    public boolean onStartJob(JobParameters params) {
-        Log.v(TAG, "Starting job: " + String.valueOf(params));
-
-        NotificationManager noman = getSystemService(NotificationManager.class);
-        if (NekoLand.DEBUG_NOTIFICATIONS) {
-            final Bundle extras = new Bundle();
-            extras.putString("android.substName", getString(R.string.notification_name));
-            final int size = getResources()
-                    .getDimensionPixelSize(android.R.dimen.notification_large_icon_width);
-            final Cat cat = Cat.create(this);
-            final Notification.Builder builder
-                    = cat.buildNotification(this)
-                        .setContentTitle("DEBUG")
-                        .setChannel(NekoLand.CHAN_ID)
-                        .setContentText("Ran job: " + params);
-            noman.notify(DEBUG_NOTIFICATION, builder.build());
-        }
-
-        final PrefState prefs = new PrefState(this);
-        int food = prefs.getFoodState();
-        if (food != 0) {
-            prefs.setFoodState(0); // nom
-            final Random rng = new Random();
-            if (rng.nextFloat() <= CAT_CAPTURE_PROB) {
-                Cat cat;
-                List<Cat> cats = prefs.getCats();
-                final int[] probs = getResources().getIntArray(R.array.food_new_cat_prob);
-                final float new_cat_prob = (float)((food < probs.length) ? probs[food] : 50) / 100f;
-
-                if (cats.size() == 0 || rng.nextFloat() <= new_cat_prob) {
-                    cat = Cat.create(this);
-                    prefs.addCat(cat);
-                    cat.logAdd(this);
-                    Log.v(TAG, "A new cat is here: " + cat.getName());
-                } else {
-                    cat = cats.get(rng.nextInt(cats.size()));
-                    Log.v(TAG, "A cat has returned: " + cat.getName());
-                }
-
-                final Notification.Builder builder = cat.buildNotification(this);
-                noman.notify(CAT_NOTIFICATION, builder.build());
-            }
-        }
-        cancelJob(this);
-        return false;
-    }
-
-    @Override
-    public boolean onStopJob(JobParameters jobParameters) {
-        return false;
-    }
-
-    public static void registerJobIfNeeded(Context context, long intervalMinutes) {
-        JobScheduler jss = context.getSystemService(JobScheduler.class);
-        JobInfo info = jss.getPendingJob(JOB_ID);
-        if (info == null) {
-            registerJob(context, intervalMinutes);
-        }
-    }
-
-    public static void registerJob(Context context, long intervalMinutes) {
-        setupNotificationChannels(context);
-
-        JobScheduler jss = context.getSystemService(JobScheduler.class);
-        jss.cancel(JOB_ID);
-        long interval = intervalMinutes * MINUTES;
-        long jitter = (long)(INTERVAL_JITTER_FRAC * interval);
-        interval += (long)(Math.random() * (2 * jitter)) - jitter;
-        final JobInfo jobInfo = new JobInfo.Builder(JOB_ID,
-                new ComponentName(context, NekoService.class))
-                .setPeriodic(interval, INTERVAL_FLEX)
-                .build();
-
-        Log.v(TAG, "A cat will visit in " + interval + "ms: " + String.valueOf(jobInfo));
-        jss.schedule(jobInfo);
-
-        if (NekoLand.DEBUG_NOTIFICATIONS) {
-            NotificationManager noman = context.getSystemService(NotificationManager.class);
-            noman.notify(DEBUG_NOTIFICATION, new Notification.Builder(context)
-                    .setSmallIcon(R.drawable.stat_icon)
-                    .setContentTitle(String.format("Job scheduled in %d min", (interval / MINUTES)))
-                    .setContentText(String.valueOf(jobInfo))
-                    .setPriority(Notification.PRIORITY_MIN)
-                    .setCategory(Notification.CATEGORY_SERVICE)
-                    .setChannel(NekoLand.CHAN_ID)
-                    .setShowWhen(true)
-                    .build());
-        }
-    }
-
-    public static void cancelJob(Context context) {
-        JobScheduler jss = context.getSystemService(JobScheduler.class);
-        Log.v(TAG, "Canceling job");
-        jss.cancel(JOB_ID);
-    }
-}
diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoTile.java b/packages/EasterEgg/src/com/android/egg/neko/NekoTile.java
deleted file mode 100644
index 159b40a..0000000
--- a/packages/EasterEgg/src/com/android/egg/neko/NekoTile.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.egg.neko;
-
-import android.content.Intent;
-import android.service.quicksettings.Tile;
-import android.service.quicksettings.TileService;
-import android.util.Log;
-
-import com.android.egg.neko.PrefState.PrefsListener;
-import com.android.internal.logging.MetricsLogger;
-
-public class NekoTile extends TileService implements PrefsListener {
-
-    private static final String TAG = "NekoTile";
-
-    private PrefState mPrefs;
-
-    @Override
-    public void onCreate() {
-        super.onCreate();
-        mPrefs = new PrefState(this);
-    }
-
-    @Override
-    public void onStartListening() {
-        super.onStartListening();
-        mPrefs.setListener(this);
-        updateState();
-    }
-
-    @Override
-    public void onStopListening() {
-        super.onStopListening();
-        mPrefs.setListener(null);
-    }
-
-    @Override
-    public void onTileAdded() {
-        super.onTileAdded();
-        MetricsLogger.count(this, "egg_neko_tile_added", 1);
-    }
-
-    @Override
-    public void onTileRemoved() {
-        super.onTileRemoved();
-        MetricsLogger.count(this, "egg_neko_tile_removed", 1);
-    }
-
-    @Override
-    public void onPrefsChanged() {
-        updateState();
-    }
-
-    private void updateState() {
-        Tile tile = getQsTile();
-        int foodState = mPrefs.getFoodState();
-        Food food = new Food(foodState);
-        if (foodState != 0) {
-            NekoService.registerJobIfNeeded(this, food.getInterval(this));
-        }
-        tile.setIcon(food.getIcon(this));
-        tile.setLabel(food.getName(this));
-        tile.setState(foodState != 0 ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
-        tile.updateTile();
-    }
-
-    @Override
-    public void onClick() {
-        if (mPrefs.getFoodState() != 0) {
-            // there's already food loaded, let's empty it
-            MetricsLogger.count(this, "egg_neko_empty_food", 1);
-            mPrefs.setFoodState(0);
-            NekoService.cancelJob(this);
-        } else {
-            // time to feed the cats
-            if (isLocked()) {
-                if (isSecure()) {
-                    Log.d(TAG, "startActivityAndCollapse");
-                    Intent intent = new Intent(this, NekoLockedActivity.class);
-                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                    startActivityAndCollapse(intent);
-                } else {
-                    unlockAndRun(new Runnable() {
-                        @Override
-                        public void run() {
-                            showNekoDialog();
-                        }
-                    });
-                }
-            } else {
-                showNekoDialog();
-            }
-        }
-    }
-
-    private void showNekoDialog() {
-        Log.d(TAG, "showNekoDialog");
-        MetricsLogger.count(this, "egg_neko_select_food", 1);
-        showDialog(new NekoDialog(this));
-    }
-}
diff --git a/packages/EasterEgg/src/com/android/egg/neko/PrefState.java b/packages/EasterEgg/src/com/android/egg/neko/PrefState.java
deleted file mode 100644
index bf71b19..0000000
--- a/packages/EasterEgg/src/com/android/egg/neko/PrefState.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.egg.neko;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-public class PrefState implements OnSharedPreferenceChangeListener {
-
-    private static final String FILE_NAME = "mPrefs";
-
-    private static final String FOOD_STATE = "food";
-
-    private static final String CAT_KEY_PREFIX = "cat:";
-
-    private final Context mContext;
-    private final SharedPreferences mPrefs;
-    private PrefsListener mListener;
-
-    public PrefState(Context context) {
-        mContext = context;
-        mPrefs = mContext.getSharedPreferences(FILE_NAME, 0);
-    }
-
-    // Can also be used for renaming.
-    public void addCat(Cat cat) {
-        mPrefs.edit()
-              .putString(CAT_KEY_PREFIX + String.valueOf(cat.getSeed()), cat.getName())
-              .apply();
-    }
-
-    public void removeCat(Cat cat) {
-        mPrefs.edit().remove(CAT_KEY_PREFIX + String.valueOf(cat.getSeed())).apply();
-    }
-
-    public List<Cat> getCats() {
-        ArrayList<Cat> cats = new ArrayList<>();
-        Map<String, ?> map = mPrefs.getAll();
-        for (String key : map.keySet()) {
-            if (key.startsWith(CAT_KEY_PREFIX)) {
-                long seed = Long.parseLong(key.substring(CAT_KEY_PREFIX.length()));
-                Cat cat = new Cat(mContext, seed);
-                cat.setName(String.valueOf(map.get(key)));
-                cats.add(cat);
-            }
-        }
-        return cats;
-    }
-
-    public int getFoodState() {
-        return mPrefs.getInt(FOOD_STATE, 0);
-    }
-
-    public void setFoodState(int foodState) {
-        mPrefs.edit().putInt(FOOD_STATE, foodState).apply();
-    }
-
-    public void setListener(PrefsListener listener) {
-        mListener = listener;
-        if (mListener != null) {
-            mPrefs.registerOnSharedPreferenceChangeListener(this);
-        } else {
-            mPrefs.unregisterOnSharedPreferenceChangeListener(this);
-        }
-    }
-
-    @Override
-    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
-        mListener.onPrefsChanged();
-    }
-
-    public interface PrefsListener {
-        void onPrefsChanged();
-    }
-}
diff --git a/packages/EasterEgg/src/com/android/egg/octo/Ocquarium.java b/packages/EasterEgg/src/com/android/egg/octo/Ocquarium.java
deleted file mode 100644
index 8a06cc6..0000000
--- a/packages/EasterEgg/src/com/android/egg/octo/Ocquarium.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.egg.octo;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-
-import com.android.egg.R;
-
-public class Ocquarium extends Activity {
-    ImageView mImageView;
-    private OctopusDrawable mOcto;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        final float dp = getResources().getDisplayMetrics().density;
-
-        getWindow().setBackgroundDrawableResource(R.drawable.octo_bg);
-
-        FrameLayout bg = new FrameLayout(this);
-        setContentView(bg);
-        bg.setAlpha(0f);
-        bg.animate().setStartDelay(500).setDuration(5000).alpha(1f).start();
-
-        mImageView = new ImageView(this);
-        bg.addView(mImageView, new FrameLayout.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
-
-        mOcto = new OctopusDrawable(getApplicationContext());
-        mOcto.setSizePx((int) (OctopusDrawable.randfrange(40f,180f) * dp));
-        mImageView.setImageDrawable(mOcto);
-
-        mImageView.setOnTouchListener(new View.OnTouchListener() {
-            boolean touching;
-            @Override
-            public boolean onTouch(View view, MotionEvent motionEvent) {
-                switch (motionEvent.getActionMasked()) {
-                    case MotionEvent.ACTION_DOWN:
-                        if (mOcto.hitTest(motionEvent.getX(), motionEvent.getY())) {
-                            touching = true;
-                            mOcto.stopDrift();
-                        }
-                        break;
-                    case MotionEvent.ACTION_MOVE:
-                        if (touching) {
-                            mOcto.moveTo(motionEvent.getX(), motionEvent.getY());
-                        }
-                        break;
-                    case MotionEvent.ACTION_UP:
-                    case MotionEvent.ACTION_CANCEL:
-                        touching = false;
-                        mOcto.startDrift();
-                        break;
-                }
-                return true;
-            }
-        });
-    }
-
-    @Override
-    protected void onPause() {
-        mOcto.stopDrift();
-        super.onPause();
-    }
-
-    @Override
-    protected void onResume() {
-        super.onResume();
-        mOcto.startDrift();
-    }
-}
diff --git a/packages/EasterEgg/src/com/android/egg/octo/OctopusDrawable.java b/packages/EasterEgg/src/com/android/egg/octo/OctopusDrawable.java
deleted file mode 100644
index 5dde6e1..0000000
--- a/packages/EasterEgg/src/com/android/egg/octo/OctopusDrawable.java
+++ /dev/null
@@ -1,436 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.egg.octo;
-
-import android.animation.TimeAnimator;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.DashPathEffect;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.PixelFormat;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.support.animation.DynamicAnimation;
-import android.support.animation.SpringForce;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.animation.SpringAnimation;
-import android.support.animation.FloatValueHolder;
-
-public class OctopusDrawable extends Drawable {
-    private static float BASE_SCALE = 100f;
-    public static boolean PATH_DEBUG = false;
-
-    private static int BODY_COLOR   = 0xFF101010;
-    private static int ARM_COLOR    = 0xFF101010;
-    private static int ARM_COLOR_BACK = 0xFF000000;
-    private static int EYE_COLOR    = 0xFF808080;
-
-    private static int[] BACK_ARMS = {1, 3, 4, 6};
-    private static int[] FRONT_ARMS = {0, 2, 5, 7};
-
-    private Paint mPaint = new Paint();
-    private Arm[] mArms = new Arm[8];
-    final PointF point = new PointF();
-    private int mSizePx = 100;
-    final Matrix M = new Matrix();
-    final Matrix M_inv = new Matrix();
-    private TimeAnimator mDriftAnimation;
-    private boolean mBlinking;
-    private float[] ptmp = new float[2];
-    private float[] scaledBounds = new float[2];
-
-    public static float randfrange(float a, float b) {
-        return (float) (Math.random()*(b-a) + a);
-    }
-    public static float clamp(float v, float a, float b) {
-        return v<a?a:v>b?b:v;
-    }
-
-    public OctopusDrawable(Context context) {
-        float dp = context.getResources().getDisplayMetrics().density;
-        setSizePx((int) (100*dp));
-        mPaint.setAntiAlias(true);
-        for (int i=0; i<mArms.length; i++) {
-            final float bias = (float)i/(mArms.length-1) - 0.5f;
-            mArms[i] = new Arm(
-                    0,0, // arm will be repositioned on moveTo
-                    10f*bias + randfrange(0,20f), randfrange(20f,50f),
-                    40f*bias+randfrange(-60f,60f), randfrange(30f, 80f),
-                    randfrange(-40f,40f), randfrange(-80f,40f),
-                    14f, 2f);
-        }
-    }
-
-    public void setSizePx(int size) {
-        mSizePx = size;
-        M.setScale(mSizePx/BASE_SCALE, mSizePx/BASE_SCALE);
-        // TaperedPathStroke.setMinStep(20f*BASE_SCALE/mSizePx); // nice little floaty circles
-        TaperedPathStroke.setMinStep(8f*BASE_SCALE/mSizePx); // classic tentacles
-        M.invert(M_inv);
-    }
-
-    public void startDrift() {
-        if (mDriftAnimation == null) {
-            mDriftAnimation = new TimeAnimator();
-            mDriftAnimation.setTimeListener(new TimeAnimator.TimeListener() {
-                float MAX_VY = 35f;
-                float JUMP_VY = -100f;
-                float MAX_VX = 15f;
-                private float ax = 0f, ay = 30f;
-                private float vx, vy;
-                long nextjump = 0;
-                long unblink = 0;
-                @Override
-                public void onTimeUpdate(TimeAnimator timeAnimator, long t, long dt) {
-                    float t_sec = 0.001f * t;
-                    float dt_sec = 0.001f * dt;
-                    if (t > nextjump) {
-                        vy = JUMP_VY;
-                        nextjump = t + (long) randfrange(5000, 10000);
-                    }
-                    if (unblink > 0 && t > unblink) {
-                        setBlinking(false);
-                        unblink = 0;
-                    } else if (Math.random() < 0.001f) {
-                        setBlinking(true);
-                        unblink = t + 200;
-                    }
-
-                    ax = (float) (MAX_VX * Math.sin(t_sec*.25f));
-
-                    vx = clamp(vx + dt_sec * ax, -MAX_VX, MAX_VX);
-                    vy = clamp(vy + dt_sec * ay, -100*MAX_VY, MAX_VY);
-
-                    // oob check
-                    if (point.y - BASE_SCALE/2 > scaledBounds[1]) {
-                        vy = JUMP_VY;
-                    } else if (point.y + BASE_SCALE < 0) {
-                        vy = MAX_VY;
-                    }
-
-                    point.x = clamp(point.x + dt_sec * vx, 0, scaledBounds[0]);
-                    point.y = point.y + dt_sec * vy;
-
-                    repositionArms();
-               }
-            });
-        }
-        mDriftAnimation.start();
-    }
-
-    public void stopDrift() {
-        mDriftAnimation.cancel();
-    }
-
-    @Override
-    public void onBoundsChange(Rect bounds) {
-        final float w = bounds.width();
-        final float h = bounds.height();
-
-        lockArms(true);
-        moveTo(w/2, h/2);
-        lockArms(false);
-
-        scaledBounds[0] = w;
-        scaledBounds[1] = h;
-        M_inv.mapPoints(scaledBounds);
-    }
-
-    // real pixel coordinates
-    public void moveTo(float x, float y) {
-        point.x = x;
-        point.y = y;
-        mapPointF(M_inv, point);
-        repositionArms();
-    }
-
-    public boolean hitTest(float x, float y) {
-        ptmp[0] = x;
-        ptmp[1] = y;
-        M_inv.mapPoints(ptmp);
-        return Math.hypot(ptmp[0] - point.x, ptmp[1] - point.y) < BASE_SCALE/2;
-    }
-
-    private void lockArms(boolean l) {
-        for (Arm arm : mArms) {
-            arm.setLocked(l);
-        }
-    }
-    private void repositionArms() {
-        for (int i=0; i<mArms.length; i++) {
-            final float bias = (float)i/(mArms.length-1) - 0.5f;
-            mArms[i].setAnchor(
-                    point.x+bias*30f,point.y+26f);
-        }
-        invalidateSelf();
-    }
-
-    private void drawPupil(Canvas canvas, float x, float y, float size, boolean open,
-            Paint pt) {
-        final float r = open ? size*.33f : size * .1f;
-        canvas.drawRoundRect(x - size, y - r, x + size, y + r, r, r, pt);
-    }
-
-    @Override
-    public void draw(@NonNull Canvas canvas) {
-        canvas.save();
-        {
-            canvas.concat(M);
-
-            // arms behind
-            mPaint.setColor(ARM_COLOR_BACK);
-            for (int i : BACK_ARMS) {
-                mArms[i].draw(canvas, mPaint);
-            }
-
-            // head/body/thing
-            mPaint.setColor(EYE_COLOR);
-            canvas.drawCircle(point.x, point.y, 36f, mPaint);
-            mPaint.setColor(BODY_COLOR);
-            canvas.save();
-            {
-                canvas.clipOutRect(point.x - 61f, point.y + 8f,
-                        point.x + 61f, point.y + 12f);
-                canvas.drawOval(point.x-40f,point.y-60f,point.x+40f,point.y+40f, mPaint);
-            }
-            canvas.restore();
-
-            // eyes
-            mPaint.setColor(EYE_COLOR);
-            if (mBlinking) {
-                drawPupil(canvas, point.x - 16f, point.y - 12f, 6f, false, mPaint);
-                drawPupil(canvas, point.x + 16f, point.y - 12f, 6f, false, mPaint);
-            } else {
-                canvas.drawCircle(point.x - 16f, point.y - 12f, 6f, mPaint);
-                canvas.drawCircle(point.x + 16f, point.y - 12f, 6f, mPaint);
-            }
-
-            // too much?
-            if (false) {
-                mPaint.setColor(0xFF000000);
-                drawPupil(canvas, point.x - 16f, point.y - 12f, 5f, true, mPaint);
-                drawPupil(canvas, point.x + 16f, point.y - 12f, 5f, true, mPaint);
-            }
-
-            // arms in front
-            mPaint.setColor(ARM_COLOR);
-            for (int i : FRONT_ARMS) {
-                mArms[i].draw(canvas, mPaint);
-            }
-
-            if (PATH_DEBUG) for (Arm arm : mArms) {
-                arm.drawDebug(canvas);
-            }
-        }
-        canvas.restore();
-    }
-
-    public void setBlinking(boolean b) {
-        mBlinking = b;
-        invalidateSelf();
-    }
-
-    @Override
-    public void setAlpha(int i) {
-    }
-
-    @Override
-    public void setColorFilter(@Nullable ColorFilter colorFilter) {
-
-    }
-
-    @Override
-    public int getOpacity() {
-        return PixelFormat.TRANSLUCENT;
-    }
-
-    static Path pathMoveTo(Path p, PointF pt) {
-        p.moveTo(pt.x, pt.y);
-        return p;
-    }
-    static Path pathQuadTo(Path p, PointF p1, PointF p2) {
-        p.quadTo(p1.x, p1.y, p2.x, p2.y);
-        return p;
-    }
-
-    static void mapPointF(Matrix m, PointF point) {
-        float[] p = new float[2];
-        p[0] = point.x;
-        p[1] = point.y;
-        m.mapPoints(p);
-        point.x = p[0];
-        point.y = p[1];
-    }
-
-    private class Link  // he come to town
-            implements DynamicAnimation.OnAnimationUpdateListener {
-        final FloatValueHolder[] coords = new FloatValueHolder[2];
-        final SpringAnimation[] anims = new SpringAnimation[coords.length];
-        private float dx, dy;
-        private boolean locked = false;
-        Link next;
-
-        Link(int index, float x1, float y1, float dx, float dy) {
-            coords[0] = new FloatValueHolder(x1);
-            coords[1] = new FloatValueHolder(y1);
-            this.dx = dx;
-            this.dy = dy;
-            for (int i=0; i<coords.length; i++) {
-                anims[i] = new SpringAnimation(coords[i]);
-                anims[i].setSpring(new SpringForce()
-                        .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
-                        .setStiffness(
-                                index == 0 ? SpringForce.STIFFNESS_LOW
-                                        : index == 1 ? SpringForce.STIFFNESS_VERY_LOW
-                                                : SpringForce.STIFFNESS_VERY_LOW/2)
-                        .setFinalPosition(0f));
-                anims[i].addUpdateListener(this);
-            }
-        }
-        public void setLocked(boolean locked) {
-            this.locked = locked;
-        }
-        public PointF start() {
-            return new PointF(coords[0].getValue(), coords[1].getValue());
-        }
-        public PointF end() {
-            return new PointF(coords[0].getValue()+dx,coords[1].getValue()+dy);
-        }
-        public PointF mid() {
-            return new PointF(
-                    0.5f*dx+(coords[0].getValue()),
-                    0.5f*dy+(coords[1].getValue()));
-        }
-        public void animateTo(PointF target) {
-            if (locked) {
-                setStart(target.x, target.y);
-            } else {
-                anims[0].animateToFinalPosition(target.x);
-                anims[1].animateToFinalPosition(target.y);
-            }
-        }
-        @Override
-        public void onAnimationUpdate(DynamicAnimation dynamicAnimation, float v, float v1) {
-            if (next != null) {
-                next.animateTo(end());
-            }
-            OctopusDrawable.this.invalidateSelf();
-        }
-
-        public void setStart(float x, float y) {
-            coords[0].setValue(x);
-            coords[1].setValue(y);
-            onAnimationUpdate(null, 0, 0);
-        }
-    }
-
-    private class Arm {
-        final Link link1, link2, link3;
-        float max, min;
-
-        public Arm(float x, float y, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3,
-                float max, float min) {
-            link1 = new Link(0, x, y, dx1, dy1);
-            link2 = new Link(1, x+dx1, y+dy1, dx2, dy2);
-            link3 = new Link(2, x+dx1+dx2, y+dy1+dy2, dx3, dy3);
-            link1.next = link2;
-            link2.next = link3;
-
-            link1.setLocked(true);
-            link2.setLocked(false);
-            link3.setLocked(false);
-
-            this.max = max;
-            this.min = min;
-        }
-
-        // when the arm is locked, it moves rigidly, without physics
-        public void setLocked(boolean locked) {
-            link2.setLocked(locked);
-            link3.setLocked(locked);
-        }
-
-        private void setAnchor(float x, float y) {
-            link1.setStart(x,y);
-        }
-
-        public Path getPath() {
-            Path p = new Path();
-            pathMoveTo(p, link1.start());
-            pathQuadTo(p, link2.start(), link2.mid());
-            pathQuadTo(p, link2.end(), link3.end());
-            return p;
-        }
-
-        public void draw(@NonNull Canvas canvas, Paint pt) {
-            final Path p = getPath();
-            TaperedPathStroke.drawPath(canvas, p, max, min, pt);
-        }
-
-        private final Paint dpt = new Paint();
-        public void drawDebug(Canvas canvas) {
-            dpt.setStyle(Paint.Style.STROKE);
-            dpt.setStrokeWidth(0.75f);
-            dpt.setStrokeCap(Paint.Cap.ROUND);
-
-            dpt.setAntiAlias(true);
-            dpt.setColor(0xFF336699);
-
-            final Path path = getPath();
-            canvas.drawPath(path, dpt);
-
-            dpt.setColor(0xFFFFFF00);
-
-            dpt.setPathEffect(new DashPathEffect(new float[] {2f, 2f}, 0f));
-
-            canvas.drawLines(new float[] {
-                    link1.end().x,   link1.end().y,
-                    link2.start().x, link2.start().y,
-
-                    link2.end().x,   link2.end().y,
-                    link3.start().x, link3.start().y,
-            }, dpt);
-            dpt.setPathEffect(null);
-
-            dpt.setColor(0xFF00CCFF);
-
-            canvas.drawLines(new float[] {
-                    link1.start().x, link1.start().y,
-                    link1.end().x,   link1.end().y,
-
-                    link2.start().x, link2.start().y,
-                    link2.end().x,   link2.end().y,
-
-                    link3.start().x, link3.start().y,
-                    link3.end().x,   link3.end().y,
-            }, dpt);
-
-            dpt.setColor(0xFFCCEEFF);
-            canvas.drawCircle(link2.start().x, link2.start().y, 2f, dpt);
-            canvas.drawCircle(link3.start().x, link3.start().y, 2f, dpt);
-
-            dpt.setStyle(Paint.Style.FILL_AND_STROKE);
-            canvas.drawCircle(link1.start().x, link1.start().y, 2f, dpt);
-            canvas.drawCircle(link2.mid().x,   link2.mid().y,   2f, dpt);
-            canvas.drawCircle(link3.end().x,   link3.end().y,   2f, dpt);
-        }
-
-    }
-}
diff --git a/packages/EasterEgg/src/com/android/egg/octo/TaperedPathStroke.java b/packages/EasterEgg/src/com/android/egg/octo/TaperedPathStroke.java
deleted file mode 100644
index e014fbc..0000000
--- a/packages/EasterEgg/src/com/android/egg/octo/TaperedPathStroke.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.egg.octo;
-
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.PathMeasure;
-import android.os.Debug;
-
-import java.util.Arrays;
-
-public class TaperedPathStroke {
-    static float sMinStepPx = 4f;
-    static PathMeasure pm = new PathMeasure();
-    static float[] pos = {0,0};
-    static float[] tan = {0,0};
-    static float lerp(float t, float a, float b) {
-        return a + t*(b-a);
-    }
-    public static void setMinStep(float px) {
-        sMinStepPx = px;
-    }
-
-    // it's the variable-width brush algorithm from the Markers app, basically
-    public static void drawPath(Canvas c, Path p, float r1, float r2, Paint pt) {
-        pm.setPath(p,false);
-        final float len = pm.getLength();
-        float t=0;
-        boolean last=false;
-        while (true) {
-            if (t>=len) {
-                t=len;
-                last=true;
-            }
-            pm.getPosTan(t, pos, tan);
-            float r = len > 0 ? lerp(t/len, r1, r2) : r1;
-            c.drawCircle(pos[0], pos[1], r, pt);
-            t += Math.max(r*0.25f, sMinStepPx); // walk forward 1/4 radius, not too small though
-            if (last) break;
-        }
-    }
-}
diff --git a/packages/EasterEgg/src/com/android/egg/paint/BrushPropertyDrawable.kt b/packages/EasterEgg/src/com/android/egg/paint/BrushPropertyDrawable.kt
new file mode 100644
index 0000000..4a02ee6
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/paint/BrushPropertyDrawable.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.egg.paint
+
+import android.content.Context
+import android.graphics.*
+import android.graphics.PixelFormat.TRANSLUCENT
+import android.graphics.drawable.Drawable
+import android.util.DisplayMetrics
+
+class BrushPropertyDrawable : Drawable {
+    val framePaint = Paint(Paint.ANTI_ALIAS_FLAG).also {
+        it.color = Color.BLACK
+        it.style = Paint.Style.FILL
+    }
+    val wellPaint = Paint(Paint.ANTI_ALIAS_FLAG).also {
+        it.color = Color.RED
+        it.style = Paint.Style.FILL
+    }
+
+    constructor(context: Context) {
+        _size = (24 * context.resources.displayMetrics.density).toInt()
+    }
+
+    private var _size = 24
+    private var _scale = 1f
+
+    fun setFrameColor(color: Int) {
+        framePaint.color = color
+        invalidateSelf()
+    }
+
+    fun setWellColor(color: Int) {
+        wellPaint.color = color
+        invalidateSelf()
+    }
+
+    fun setWellScale(scale: Float) {
+        _scale = scale
+        invalidateSelf()
+    }
+
+    override fun getIntrinsicWidth(): Int {
+        return _size
+    }
+
+    override fun getIntrinsicHeight(): Int {
+        return _size
+    }
+
+    override fun draw(c: Canvas?) {
+        c?.let {
+            val w = bounds.width().toFloat()
+            val h = bounds.height().toFloat()
+            val inset = _size / 12 // 2dp in a 24x24 icon
+            val r = Math.min(w, h) / 2
+
+            c.drawCircle(w/2, h/2, (r - inset) * _scale + 1 , wellPaint)
+
+            val p = Path()
+            p.addCircle(w/2, h/2, r, Path.Direction.CCW)
+            p.addCircle(w/2, h/2, r - inset, Path.Direction.CW)
+            c.drawPath(p, framePaint)
+        }
+    }
+
+    override fun setAlpha(p0: Int) {
+        //
+    }
+
+    override fun getOpacity(): Int {
+        return TRANSLUCENT
+    }
+
+    override fun setColorFilter(p0: ColorFilter?) {
+        //
+    }
+
+}
\ No newline at end of file
diff --git a/packages/EasterEgg/src/com/android/egg/paint/CutoutAvoidingToolbar.kt b/packages/EasterEgg/src/com/android/egg/paint/CutoutAvoidingToolbar.kt
new file mode 100644
index 0000000..164fc5a
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/paint/CutoutAvoidingToolbar.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.egg.paint
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.*
+import android.view.ViewGroup.LayoutParams.MATCH_PARENT
+import android.widget.LinearLayout
+
+class CutoutAvoidingToolbar : LinearLayout {
+    private var _insets: WindowInsets? = null
+
+    constructor(context: Context) : super(context) {
+        init(null, 0)
+    }
+
+    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
+        init(attrs, 0)
+    }
+
+    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
+        init(attrs, defStyle)
+    }
+
+    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
+        super.onSizeChanged(w, h, oldw, oldh)
+        adjustLayout()
+    }
+
+    override fun onApplyWindowInsets(insets: WindowInsets?): WindowInsets {
+        _insets = insets
+        adjustLayout()
+        return super.onApplyWindowInsets(insets)
+    }
+
+    fun adjustLayout() {
+        _insets?.displayCutout?.boundingRects?.let {
+            var cutoutCenter = 0
+            var cutoutLeft = 0
+            var cutoutRight = 0
+
+            // collect at most three cutouts
+            for (r in it) {
+                if (r.top > 0) continue
+
+                if (r.left == left) {
+                    cutoutLeft = r.width()
+                } else if (r.right == right) {
+                    cutoutRight = r.width()
+                } else {
+                    cutoutCenter = r.width()
+                }
+            }
+
+            // apply to layout
+            (findViewWithTag("cutoutLeft") as View?)?.let {
+                it.layoutParams = LayoutParams(cutoutLeft, MATCH_PARENT)
+            }
+            (findViewWithTag("cutoutCenter") as View?)?.let {
+                it.layoutParams = LayoutParams(cutoutCenter, MATCH_PARENT)
+            }
+            (findViewWithTag("cutoutRight") as View?)?.let {
+                it.layoutParams = LayoutParams(cutoutRight, MATCH_PARENT)
+            }
+
+            requestLayout()
+        }
+    }
+
+    private fun init(attrs: AttributeSet?, defStyle: Int) {
+    }
+
+}
diff --git a/packages/EasterEgg/src/com/android/egg/paint/PaintActivity.java b/packages/EasterEgg/src/com/android/egg/paint/PaintActivity.java
new file mode 100644
index 0000000..ac47fbd
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/paint/PaintActivity.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.egg.paint;
+
+import static android.view.MotionEvent.ACTION_CANCEL;
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_MOVE;
+import static android.view.MotionEvent.ACTION_UP;
+
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.animation.OvershootInterpolator;
+import android.widget.FrameLayout;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.widget.Magnifier;
+
+import com.android.egg.R;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.stream.IntStream;
+
+public class PaintActivity extends Activity {
+    private static final float MAX_BRUSH_WIDTH_DP = 100f;
+    private static final float MIN_BRUSH_WIDTH_DP = 1f;
+
+    private static final int NUM_BRUSHES = 6;
+    private static final int NUM_COLORS = 6;
+
+    private Painting painting = null;
+    private CutoutAvoidingToolbar toolbar = null;
+    private LinearLayout brushes = null;
+    private LinearLayout colors = null;
+    private Magnifier magnifier = null;
+    private boolean sampling = false;
+
+    private View.OnClickListener buttonHandler = new View.OnClickListener() {
+        @Override
+        public void onClick(View view) {
+            switch (view.getId()) {
+                case R.id.btnBrush:
+                    view.setSelected(true);
+                    hideToolbar(colors);
+                    toggleToolbar(brushes);
+                    break;
+                case R.id.btnColor:
+                    view.setSelected(true);
+                    hideToolbar(brushes);
+                    toggleToolbar(colors);
+                    break;
+                case R.id.btnClear:
+                    painting.clear();
+                    break;
+                case R.id.btnSample:
+                    sampling = true;
+                    view.setSelected(true);
+                    break;
+                case R.id.btnZen:
+                    painting.setZenMode(!painting.getZenMode());
+                    view.animate()
+                            .setStartDelay(200)
+                            .setInterpolator(new OvershootInterpolator())
+                            .rotation(painting.getZenMode() ? 0f : 90f);
+                    break;
+            }
+        }
+    };
+
+    private void showToolbar(View bar) {
+        if (bar.getVisibility() != View.GONE) return;
+        bar.setVisibility(View.VISIBLE);
+        bar.setTranslationY(toolbar.getHeight()/2);
+        bar.animate()
+                .translationY(toolbar.getHeight())
+                .alpha(1f)
+                .setDuration(220)
+                .start();
+    }
+
+    private void hideToolbar(View bar) {
+        if (bar.getVisibility() != View.VISIBLE) return;
+        bar.animate()
+                .translationY(toolbar.getHeight()/2)
+                .alpha(0f)
+                .setDuration(150)
+                .withEndAction(new Runnable() {
+                    @Override
+                    public void run() {
+                        bar.setVisibility(View.GONE);
+                    }
+                })
+                .start();
+    }
+
+    private void toggleToolbar(View bar) {
+        if (bar.getVisibility() == View.VISIBLE) {
+            hideToolbar(bar);
+        } else {
+            showToolbar(bar);
+        }
+    }
+
+    private BrushPropertyDrawable widthButtonDrawable;
+    private BrushPropertyDrawable colorButtonDrawable;
+    private float maxBrushWidth, minBrushWidth;
+    private int nightMode = Configuration.UI_MODE_NIGHT_UNDEFINED;
+
+    static final float lerp(float f, float a, float b) {
+        return a + (b-a) * f;
+    }
+
+    void setupViews(Painting oldPainting) {
+        setContentView(R.layout.activity_paint);
+
+        painting = oldPainting != null ? oldPainting : new Painting(this);
+        ((FrameLayout) findViewById(R.id.contentView)).addView(painting,
+                new FrameLayout.LayoutParams(
+                        ViewGroup.LayoutParams.MATCH_PARENT,
+                        ViewGroup.LayoutParams.MATCH_PARENT));
+
+        painting.setPaperColor(getColor(R.color.paper_color));
+        painting.setPaintColor(getColor(R.color.paint_color));
+
+        toolbar = findViewById(R.id.toolbar);
+        brushes = findViewById(R.id.brushes);
+        colors = findViewById(R.id.colors);
+
+        magnifier = new Magnifier(painting);
+
+        painting.setOnTouchListener(
+                new View.OnTouchListener() {
+                    @Override
+                    public boolean onTouch(View view, MotionEvent event) {
+                        switch (event.getActionMasked()) {
+                            case ACTION_DOWN:
+                            case ACTION_MOVE:
+                                if (sampling) {
+                                    magnifier.show(event.getX(), event.getY());
+                                    colorButtonDrawable.setWellColor(
+                                            painting.sampleAt(event.getX(), event.getY()));
+                                    return true;
+                                }
+                                break;
+                            case ACTION_CANCEL:
+                                if (sampling) {
+                                    findViewById(R.id.btnSample).setSelected(false);
+                                    sampling = false;
+                                    magnifier.dismiss();
+                                }
+                                break;
+                            case ACTION_UP:
+                                if (sampling) {
+                                    findViewById(R.id.btnSample).setSelected(false);
+                                    sampling = false;
+                                    magnifier.dismiss();
+                                    painting.setPaintColor(
+                                            painting.sampleAt(event.getX(), event.getY()));
+                                    refreshBrushAndColor();
+                                }
+                                break;
+                        }
+                        return false; // allow view to continue handling
+                    }
+                });
+
+        findViewById(R.id.btnBrush).setOnClickListener(buttonHandler);
+        findViewById(R.id.btnColor).setOnClickListener(buttonHandler);
+        findViewById(R.id.btnClear).setOnClickListener(buttonHandler);
+        findViewById(R.id.btnSample).setOnClickListener(buttonHandler);
+        findViewById(R.id.btnZen).setOnClickListener(buttonHandler);
+
+        findViewById(R.id.btnColor).setOnLongClickListener(new View.OnLongClickListener() {
+            @Override
+            public boolean onLongClick(View view) {
+                colors.removeAllViews();
+                showToolbar(colors);
+                refreshBrushAndColor();
+                return true;
+            }
+        });
+
+        findViewById(R.id.btnClear).setOnLongClickListener(new View.OnLongClickListener() {
+            @Override
+            public boolean onLongClick(View view) {
+                painting.invertContents();
+                return true;
+            }
+        });
+
+        widthButtonDrawable = new BrushPropertyDrawable(this);
+        widthButtonDrawable.setFrameColor(getColor(R.color.toolbar_icon_color));
+        colorButtonDrawable = new BrushPropertyDrawable(this);
+        colorButtonDrawable.setFrameColor(getColor(R.color.toolbar_icon_color));
+
+        ((ImageButton) findViewById(R.id.btnBrush)).setImageDrawable(widthButtonDrawable);
+        ((ImageButton) findViewById(R.id.btnColor)).setImageDrawable(colorButtonDrawable);
+
+        refreshBrushAndColor();
+    }
+
+    private void refreshBrushAndColor() {
+        final LinearLayout.LayoutParams button_lp = new LinearLayout.LayoutParams(
+                0, ViewGroup.LayoutParams.WRAP_CONTENT);
+        button_lp.weight = 1f;
+        if (brushes.getChildCount() == 0) {
+            for (int i = 0; i < NUM_BRUSHES; i++) {
+                final BrushPropertyDrawable icon = new BrushPropertyDrawable(this);
+                icon.setFrameColor(getColor(R.color.toolbar_icon_color));
+                // exponentially increasing brush size
+                final float width = lerp(
+                        (float) Math.pow((float) i / NUM_BRUSHES, 2f), minBrushWidth,
+                        maxBrushWidth);
+                icon.setWellScale(width / maxBrushWidth);
+                icon.setWellColor(getColor(R.color.toolbar_icon_color));
+                final ImageButton button = new ImageButton(this);
+                button.setImageDrawable(icon);
+                button.setBackground(getDrawable(R.drawable.toolbar_button_bg));
+                button.setOnClickListener(
+                        new View.OnClickListener() {
+                            @Override
+                            public void onClick(View view) {
+                                brushes.setSelected(false);
+                                hideToolbar(brushes);
+                                painting.setBrushWidth(width);
+                                refreshBrushAndColor();
+                            }
+                        });
+                brushes.addView(button, button_lp);
+            }
+        }
+
+        if (colors.getChildCount() == 0) {
+            final Palette pal = new Palette(NUM_COLORS);
+            for (final int c : IntStream.concat(
+                    IntStream.of(Color.BLACK, Color.WHITE),
+                    Arrays.stream(pal.getColors())
+            ).toArray()) {
+                final BrushPropertyDrawable icon = new BrushPropertyDrawable(this);
+                icon.setFrameColor(getColor(R.color.toolbar_icon_color));
+                icon.setWellColor(c);
+                final ImageButton button = new ImageButton(this);
+                button.setImageDrawable(icon);
+                button.setBackground(getDrawable(R.drawable.toolbar_button_bg));
+                button.setOnClickListener(
+                    new View.OnClickListener() {
+                        @Override
+                        public void onClick(View view) {
+                            colors.setSelected(false);
+                            hideToolbar(colors);
+                            painting.setPaintColor(c);
+                            refreshBrushAndColor();
+                        }
+                    });
+                colors.addView(button, button_lp);
+            }
+        }
+
+        widthButtonDrawable.setWellScale(painting.getBrushWidth() / maxBrushWidth);
+        widthButtonDrawable.setWellColor(painting.getPaintColor());
+        colorButtonDrawable.setWellColor(painting.getPaintColor());
+    }
+
+    private void refreshNightMode(Configuration config) {
+        int newNightMode =
+                (config.uiMode & Configuration.UI_MODE_NIGHT_MASK);
+        if (nightMode != newNightMode) {
+            if (nightMode != Configuration.UI_MODE_NIGHT_UNDEFINED) {
+                painting.invertContents();
+
+                ((ViewGroup) painting.getParent()).removeView(painting);
+                setupViews(painting);
+
+                final View decorView = getWindow().getDecorView();
+                int decorSUIV = decorView.getSystemUiVisibility();
+
+                if (newNightMode == Configuration.UI_MODE_NIGHT_YES) {
+                    decorView.setSystemUiVisibility(
+                            decorSUIV & ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
+                } else {
+                    decorView.setSystemUiVisibility(
+                            decorSUIV | View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
+                }
+            }
+            nightMode = newNightMode;
+        }
+    }
+
+    public PaintActivity() {
+
+    }
+
+    @Override
+    public void onTrimMemory(int level) {
+        super.onTrimMemory(level);
+
+        painting.onTrimMemory();
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+
+        refreshNightMode(newConfig);
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        WindowManager.LayoutParams lp = getWindow().getAttributes();
+        lp.flags = lp.flags
+                | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
+        getWindow().setAttributes(lp);
+
+        maxBrushWidth = MAX_BRUSH_WIDTH_DP * getResources().getDisplayMetrics().density;
+        minBrushWidth = MIN_BRUSH_WIDTH_DP * getResources().getDisplayMetrics().density;
+
+        setupViews(null);
+        refreshNightMode(getResources().getConfiguration());
+    }
+
+    @Override
+    public void onPostResume() {
+        super.onPostResume();
+    }
+
+}
diff --git a/packages/EasterEgg/src/com/android/egg/paint/Painting.kt b/packages/EasterEgg/src/com/android/egg/paint/Painting.kt
new file mode 100644
index 0000000..a4a3d3d
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/paint/Painting.kt
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.egg.paint
+
+import android.content.Context
+import android.content.res.Resources
+import android.graphics.*
+import android.provider.Settings
+import android.util.AttributeSet
+import android.util.DisplayMetrics
+import android.view.MotionEvent
+import android.view.View
+import android.view.WindowInsets
+import java.util.concurrent.TimeUnit
+import android.util.Log
+import android.provider.Settings.System
+
+import org.json.JSONObject
+
+fun hypot(x: Float, y: Float): Float {
+    return Math.hypot(x.toDouble(), y.toDouble()).toFloat()
+}
+
+fun invlerp(x: Float, a: Float, b: Float): Float {
+    return if (b > a) {
+        (x - a) / (b - a)
+    } else 1.0f
+}
+
+public class Painting : View, SpotFilter.Plotter {
+    companion object {
+        val FADE_MINS = TimeUnit.MINUTES.toMillis(3) // about how long a drawing should last
+        val ZEN_RATE = TimeUnit.SECONDS.toMillis(2)  // how often to apply the fade
+        val ZEN_FADE = Math.max(1f, ZEN_RATE / FADE_MINS * 255f)
+
+        val FADE_TO_WHITE_CF = ColorMatrixColorFilter(ColorMatrix(floatArrayOf(
+                1f, 0f, 0f, 0f, ZEN_FADE,
+                0f, 1f, 0f, 0f, ZEN_FADE,
+                0f, 0f, 1f, 0f, ZEN_FADE,
+                0f, 0f, 0f, 1f, 0f
+        )))
+
+        val FADE_TO_BLACK_CF = ColorMatrixColorFilter(ColorMatrix(floatArrayOf(
+                1f, 0f, 0f, 0f, -ZEN_FADE,
+                0f, 1f, 0f, 0f, -ZEN_FADE,
+                0f, 0f, 1f, 0f, -ZEN_FADE,
+                0f, 0f, 0f, 1f, 0f
+        )))
+
+        val INVERT_CF = ColorMatrixColorFilter(ColorMatrix(floatArrayOf(
+                -1f, 0f, 0f, 0f, 255f,
+                0f, -1f, 0f, 0f, 255f,
+                0f, 0f, -1f, 0f, 255f,
+                0f, 0f, 0f, 1f, 0f
+        )))
+
+        val TOUCH_STATS = "touch.stats" // Settings.System key
+    }
+
+    var devicePressureMin = 0f; // ideal value
+    var devicePressureMax = 1f; // ideal value
+
+    var zenMode = true
+        set(value) {
+            if (field != value) {
+                field = value
+                removeCallbacks(fadeRunnable)
+                if (value && isAttachedToWindow) {
+                    handler.postDelayed(fadeRunnable, ZEN_RATE)
+                }
+            }
+        }
+
+    var bitmap: Bitmap? = null
+    var paperColor : Int = 0xFFFFFFFF.toInt()
+
+    private var _paintCanvas: Canvas? = null
+    private val _bitmapLock = Object()
+    
+    private var _drawPaint = Paint(Paint.ANTI_ALIAS_FLAG)
+    private var _lastX = 0f
+    private var _lastY = 0f
+    private var _lastR = 0f
+    private var _insets: WindowInsets? = null
+
+    private var _brushWidth = 100f
+
+    private var _filter = SpotFilter(10, 0.5f, 0.9f, this)
+
+    private val fadeRunnable = object : Runnable {
+        private val pt = Paint()
+        override fun run() {
+            val c = _paintCanvas
+            if (c != null) {
+                pt.colorFilter =
+                    if (paperColor.and(0xFF) > 0x80)
+                        FADE_TO_WHITE_CF
+                    else
+                        FADE_TO_BLACK_CF
+
+                synchronized(_bitmapLock) {
+                    c.drawBitmap(bitmap, 0f, 0f, pt)
+                }
+                invalidate()
+            }
+            postDelayed(this, ZEN_RATE)
+        }
+    }
+
+    constructor(context: Context) : super(context) {
+        init(null, 0)
+    }
+
+    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
+        init(attrs, 0)
+    }
+
+    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
+        init(attrs, defStyle)
+    }
+
+    private fun init(attrs: AttributeSet?, defStyle: Int) {
+        loadDevicePressureData()
+    }
+
+    override fun onAttachedToWindow() {
+        super.onAttachedToWindow()
+
+        setupBitmaps()
+
+        if (zenMode) {
+            handler.postDelayed(fadeRunnable, ZEN_RATE)
+        }
+    }
+
+    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
+        super.onSizeChanged(w, h, oldw, oldh)
+        setupBitmaps()
+    }
+
+    override fun onDetachedFromWindow() {
+        if (zenMode) {
+            removeCallbacks(fadeRunnable)
+        }
+        super.onDetachedFromWindow()
+    }
+
+    fun onTrimMemory() {
+    }
+
+    override fun onApplyWindowInsets(insets: WindowInsets?): WindowInsets {
+        _insets = insets
+        if (insets != null && _paintCanvas == null) {
+            setupBitmaps()
+        }
+        return super.onApplyWindowInsets(insets)
+    }
+
+    private fun powf(a: Float, b: Float): Float {
+        return Math.pow(a.toDouble(), b.toDouble()).toFloat()
+    }
+
+    override fun plot(s: MotionEvent.PointerCoords) {
+        val c = _paintCanvas
+        if (c == null) return
+        synchronized(_bitmapLock) {
+            var x = _lastX
+            var y = _lastY
+            var r = _lastR
+            val newR = Math.max(1f, powf(adjustPressure(s.pressure), 2f).toFloat() * _brushWidth)
+
+            if (r >= 0) {
+                val d = hypot(s.x - x, s.y - y)
+                if (d > 1f && (r + newR) > 1f) {
+                    val N = (2 * d / Math.min(4f, r + newR)).toInt()
+
+                    val stepX = (s.x - x) / N
+                    val stepY = (s.y - y) / N
+                    val stepR = (newR - r) / N
+                    for (i in 0 until N - 1) { // we will draw the last circle below
+                        x += stepX
+                        y += stepY
+                        r += stepR
+                        c.drawCircle(x, y, r, _drawPaint)
+                    }
+                }
+            }
+
+            c.drawCircle(s.x, s.y, newR, _drawPaint)
+            _lastX = s.x
+            _lastY = s.y
+            _lastR = newR
+        }
+    }
+
+    private fun loadDevicePressureData() {
+        try {
+            val touchDataJson = Settings.System.getString(context.contentResolver, TOUCH_STATS)
+            val touchData = JSONObject(
+                    if (touchDataJson != null) touchDataJson else "{}")
+            if (touchData.has("min")) devicePressureMin = touchData.getDouble("min").toFloat()
+            if (touchData.has("max")) devicePressureMax = touchData.getDouble("max").toFloat()
+            if (devicePressureMin < 0) devicePressureMin = 0f
+            if (devicePressureMax < devicePressureMin) devicePressureMax = devicePressureMin + 1f
+        } catch (e: Exception) {
+        }
+    }
+
+    private fun adjustPressure(pressure: Float): Float {
+        if (pressure > devicePressureMax) devicePressureMax = pressure
+        if (pressure < devicePressureMin) devicePressureMin = pressure
+        return invlerp(pressure, devicePressureMin, devicePressureMax)
+    }
+
+    override fun onTouchEvent(event: MotionEvent?): Boolean {
+        val c = _paintCanvas
+        if (event == null || c == null) return super.onTouchEvent(event)
+
+        /*
+        val pt = Paint(Paint.ANTI_ALIAS_FLAG)
+        pt.style = Paint.Style.STROKE
+        pt.color = 0x800000FF.toInt()
+        _paintCanvas?.drawCircle(event.x, event.y, 20f, pt)
+        */
+
+        when (event.actionMasked) {
+            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
+                _filter.add(event)
+                _filter.finish()
+                invalidate()
+            }
+
+            MotionEvent.ACTION_DOWN -> {
+                _lastR = -1f
+                _filter.add(event)
+                invalidate()
+            }
+
+            MotionEvent.ACTION_MOVE -> {
+                _filter.add(event)
+
+                invalidate()
+            }
+        }
+
+        return true
+    }
+
+    override fun onDraw(canvas: Canvas) {
+        super.onDraw(canvas)
+
+        bitmap?.let {
+            canvas.drawBitmap(bitmap, 0f, 0f, _drawPaint);
+        }
+    }
+
+    // public api
+    fun clear() {
+        bitmap = null
+        setupBitmaps()
+        invalidate()
+    }
+
+    fun sampleAt(x: Float, y: Float): Int {
+        val localX = (x - left).toInt()
+        val localY = (y - top).toInt()
+        return bitmap?.getPixel(localX, localY) ?: Color.BLACK
+    }
+
+    fun setPaintColor(color: Int) {
+        _drawPaint.color = color
+    }
+
+    fun getPaintColor(): Int {
+        return _drawPaint.color
+    }
+
+    fun setBrushWidth(w: Float) {
+        _brushWidth = w
+    }
+
+    fun getBrushWidth(): Float {
+        return _brushWidth
+    }
+
+    private fun setupBitmaps() {
+        val dm = DisplayMetrics()
+        display.getRealMetrics(dm)
+        val w = dm.widthPixels
+        val h = dm.heightPixels
+        val oldBits = bitmap
+        var bits = oldBits
+        if (bits == null || bits.width != w || bits.height != h) {
+            bits = Bitmap.createBitmap(
+                    w,
+                    h,
+                    Bitmap.Config.ARGB_8888
+            )
+        }
+        if (bits == null) return
+
+        val c = Canvas(bits)
+
+        if (oldBits != null) {
+            if (oldBits.width < oldBits.height != bits.width < bits.height) {
+                // orientation change. let's rotate things so they fit better
+                val matrix = Matrix()
+                if (bits.width > bits.height) {
+                    // now landscape
+                    matrix.postRotate(-90f)
+                    matrix.postTranslate(0f, bits.height.toFloat())
+                } else {
+                    // now portrait
+                    matrix.postRotate(90f)
+                    matrix.postTranslate(bits.width.toFloat(), 0f)
+                }
+                if (bits.width != oldBits.height || bits.height != oldBits.width) {
+                    matrix.postScale(
+                            bits.width.toFloat()/oldBits.height,
+                            bits.height.toFloat()/oldBits.width)
+                }
+                c.matrix = matrix
+            }
+            // paint the old artwork atop the new
+            c.drawBitmap(oldBits, 0f, 0f, _drawPaint)
+            c.matrix = Matrix()
+        } else {
+            c.drawColor(paperColor)
+        }
+
+        bitmap = bits
+        _paintCanvas = c
+    }
+
+    fun invertContents() {
+        val invertPaint = Paint()
+        invertPaint.colorFilter = INVERT_CF
+        synchronized(_bitmapLock) {
+            _paintCanvas?.drawBitmap(bitmap, 0f, 0f, invertPaint)
+        }
+        invalidate()
+    }
+}
+
diff --git a/packages/EasterEgg/src/com/android/egg/paint/Palette.kt b/packages/EasterEgg/src/com/android/egg/paint/Palette.kt
new file mode 100644
index 0000000..7043efe
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/paint/Palette.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.egg.paint
+
+import android.graphics.Color
+
+class Palette {
+    var colors : IntArray
+    var lightest = 0
+    var darkest = 0
+
+    /**
+     * rough luminance calculation
+     * https://www.w3.org/TR/AERT/#color-contrast
+     */
+    private fun lum(rgb: Int): Float {
+        return (Color.red(rgb) * 299f + Color.green(rgb) * 587f + Color.blue(rgb) * 114f) / 1000f
+    }
+
+    /**
+     * create a random evenly-spaced color palette
+     * guaranteed to contrast!
+     */
+    fun randomize(S: Float, V: Float) {
+        val hsv = floatArrayOf((Math.random() * 360f).toFloat(), S, V)
+        val count = colors.size
+        colors[0] = Color.HSVToColor(hsv)
+        lightest = 0
+        darkest = 0
+
+        for (i in 0 until count) {
+            hsv[0] = (hsv[0] + 360f / count).rem(360f)
+            val color = Color.HSVToColor(hsv)
+            colors[i] = color
+
+            val lum = lum(colors[i])
+            if (lum < lum(colors[darkest])) darkest = i
+            if (lum > lum(colors[lightest])) lightest = i
+        }
+    }
+
+    override fun toString() : String {
+        val str = StringBuilder("Palette{ ")
+        for (c in colors) {
+            str.append(String.format("#%08x ", c))
+        }
+        str.append("}")
+        return str.toString()
+    }
+
+    constructor(count: Int) {
+        colors = IntArray(count)
+        randomize(1f, 1f)
+    }
+
+    constructor(count: Int, S: Float, V: Float) {
+        colors = IntArray(count)
+        randomize(S, V)
+    }
+
+    constructor(_colors: IntArray) {
+        colors = _colors
+        for (i in 0 until colors.size) {
+            val lum = lum(colors[i])
+            if (lum < lum(colors[darkest])) darkest = i
+            if (lum > lum(colors[lightest])) lightest = i
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/EasterEgg/src/com/android/egg/paint/SpotFilter.kt b/packages/EasterEgg/src/com/android/egg/paint/SpotFilter.kt
new file mode 100644
index 0000000..2c15c0d
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/paint/SpotFilter.kt
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.egg.paint
+
+import java.util.LinkedList
+
+import android.view.MotionEvent
+
+class SpotFilter(internal var mBufSize: Int, posDecay: Float, pressureDecay: Float, internal var mPlotter: Plotter) {
+    val spots = LinkedList<MotionEvent.PointerCoords>() // newest at front
+    val tmpSpot = MotionEvent.PointerCoords()
+    var lastTool = MotionEvent.TOOL_TYPE_UNKNOWN
+
+    val posDecay: Float
+    val pressureDecay: Float
+
+    interface Plotter {
+        fun plot(s: MotionEvent.PointerCoords)
+    }
+
+    init {
+        this.posDecay = if (posDecay in 0f..1f) posDecay else 1f
+        this.pressureDecay = if (pressureDecay in 0f..1f) pressureDecay else 1f
+    }
+
+    fun filterInto(out: MotionEvent.PointerCoords, tool: Int): MotionEvent.PointerCoords {
+        lastTool = tool
+
+        var wi = 1f // weight for ith component (position)
+        var w = 0f // total weight
+        var wi_press = 1f // weight for ith component (pressure)
+        var w_press = 0f // total weight (pressure)
+
+        var x = 0f
+        var y = 0f
+        var pressure = 0f
+        var size = 0f
+        for (pi in spots) {
+            x += pi.x * wi
+            y += pi.y * wi
+
+            pressure += pi.pressure * wi_press
+            size += pi.size * wi_press
+
+            w += wi
+            wi *= posDecay // exponential backoff
+
+            w_press += wi_press
+            wi_press *= pressureDecay
+
+            if (PRECISE_STYLUS_INPUT && tool == MotionEvent.TOOL_TYPE_STYLUS) {
+                // just take the newest one, no need to average
+                break
+            }
+        }
+
+        out.x = x / w
+        out.y = y / w
+        out.pressure = pressure / w_press
+        out.size = size / w_press
+        return out
+    }
+
+    protected fun addInternal(c: MotionEvent.PointerCoords, tool: Int) {
+        val coord =
+                if (spots.size == mBufSize) {
+                    spots.removeLast()
+                } else {
+                    MotionEvent.PointerCoords()
+                }
+        coord.copyFrom(c)
+
+        spots.add(0, coord)
+
+        filterInto(tmpSpot, tool)
+        mPlotter.plot(tmpSpot)
+    }
+
+    fun add(cv: List<MotionEvent.PointerCoords>, tool: Int) {
+        for (c in cv) {
+            addInternal(c, tool)
+        }
+    }
+
+    fun add(evt: MotionEvent) {
+        val tool = evt.getToolType(0)
+        for (i in 0 until evt.historySize) {
+            evt.getHistoricalPointerCoords(0, i, tmpSpot)
+            addInternal(tmpSpot, tool)
+        }
+        evt.getPointerCoords(0, tmpSpot)
+        addInternal(tmpSpot, tool)
+    }
+
+    fun finish() {
+        while (spots.size > 0) {
+            filterInto(tmpSpot, lastTool)
+            spots.removeLast()
+            mPlotter.plot(tmpSpot)
+        }
+
+        spots.clear()
+    }
+
+    companion object {
+        var PRECISE_STYLUS_INPUT = true
+    }
+}
+
+
diff --git a/packages/EasterEgg/src/com/android/egg/paint/ToolbarView.kt b/packages/EasterEgg/src/com/android/egg/paint/ToolbarView.kt
new file mode 100644
index 0000000..86b11e7
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/paint/ToolbarView.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.egg.paint
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.Rect
+import android.graphics.drawable.Drawable
+import android.text.TextPaint
+import android.transition.ChangeBounds
+import android.transition.Transition
+import android.transition.TransitionListenerAdapter
+import android.transition.TransitionManager
+import android.util.AttributeSet
+import android.view.*
+import android.view.animation.OvershootInterpolator
+import android.widget.FrameLayout
+
+class ToolbarView : FrameLayout {
+    var inTransition = false
+    var transitionListener: Transition.TransitionListener = object : TransitionListenerAdapter() {
+        override fun onTransitionStart(transition: Transition?) {
+            inTransition = true
+        }
+        override fun onTransitionEnd(transition: Transition?) {
+            inTransition = false
+        }
+    }
+
+    constructor(context: Context) : super(context) {
+        init(null, 0)
+    }
+
+    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
+        init(attrs, 0)
+    }
+
+    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
+        init(attrs, defStyle)
+    }
+
+    override fun onApplyWindowInsets(insets: WindowInsets?): WindowInsets {
+        var lp = layoutParams as FrameLayout.LayoutParams?
+        if (lp != null && insets != null) {
+            if (insets.hasStableInsets()) {
+                lp.topMargin = insets.stableInsetTop
+                lp.bottomMargin = insets.stableInsetBottom
+            } else {
+                lp.topMargin = insets.systemWindowInsetTop
+                lp.bottomMargin = insets.systemWindowInsetBottom
+            }
+            layoutParams = lp
+        }
+
+        return super.onApplyWindowInsets(insets)
+    }
+
+    private fun init(attrs: AttributeSet?, defStyle: Int) {
+    }
+
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
index 7234788..c9990e5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
@@ -16,6 +16,7 @@
 
 package com.android.settingslib.fuelgauge;
 
+import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -89,6 +90,13 @@
         if (TextUtils.equals(pkg, defaultDialer)) {
             return true;
         }
+
+        final DevicePolicyManager devicePolicyManager = mAppContext.getSystemService(
+                DevicePolicyManager.class);
+        if (devicePolicyManager.packageHasActiveAdmins(pkg)) {
+            return true;
+        }
+
         return false;
     }
 
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
index a23eebc..5c93258 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
@@ -21,8 +21,10 @@
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 
+import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -51,7 +53,8 @@
 
     @Mock
     private IDeviceIdleController mDeviceIdleService;
-
+    @Mock
+    private DevicePolicyManager mDevicePolicyManager;
     private PowerWhitelistBackend mPowerWhitelistBackend;
     private ShadowPackageManager mPackageManager;
     private Context mContext;
@@ -59,7 +62,9 @@
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
+        mContext = spy(RuntimeEnvironment.application);
+        doReturn(mContext).when(mContext).getApplicationContext();
+        doReturn(mDevicePolicyManager).when(mContext).getSystemService(DevicePolicyManager.class);
         doReturn(new String[] {}).when(mDeviceIdleService).getFullPowerWhitelist();
         doReturn(new String[] {}).when(mDeviceIdleService).getSystemPowerWhitelist();
         doReturn(new String[] {}).when(mDeviceIdleService).getSystemPowerWhitelistExceptIdle();
@@ -68,6 +73,7 @@
         mPackageManager = Shadow.extract(mContext.getPackageManager());
         mPackageManager.setSystemFeature(PackageManager.FEATURE_TELEPHONY, true);
 
+
         mPowerWhitelistBackend = new PowerWhitelistBackend(mContext, mDeviceIdleService);
     }
 
@@ -123,6 +129,13 @@
     }
 
     @Test
+    public void isWhitelisted_shouldWhitelistActiveDeviceAdminApp() {
+        doReturn(true).when(mDevicePolicyManager).packageHasActiveAdmins(PACKAGE_ONE);
+
+        assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue();
+    }
+
+    @Test
     public void testIsSystemWhitelisted() throws Exception {
         doReturn(new String[] {PACKAGE_ONE}).when(mDeviceIdleService).getSystemPowerWhitelist();
         mPowerWhitelistBackend.refreshList();
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index f728684..9d398b5 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -841,7 +841,19 @@
             WifiConfiguration config = WifiConfiguration
                     .getWifiConfigFromBackup(new DataInputStream(new ByteArrayInputStream(data)));
             if (DEBUG) Log.d(TAG, "Successfully unMarshaled WifiConfiguration ");
+            int originalApBand = config.apBand;
             mWifiManager.setWifiApConfiguration(config);
+
+            // Depending on device hardware, we may need to notify the user of a setting change for
+            // the apBand preference
+            boolean dualMode = mWifiManager.isDualModeSupported();
+            int storedApBand = mWifiManager.getWifiApConfiguration().apBand;
+            if (dualMode) {
+                if (storedApBand != originalApBand) {
+                    Log.d(TAG, "restored ap configuration requires a conversion, notify the user");
+                    mWifiManager.notifyUserOfApBandConversion();
+                }
+            }
         } catch (IOException | BackupUtils.BadVersionException e) {
             Log.e(TAG, "Failed to unMarshal SoftAPConfiguration " + e.getMessage());
         }
diff --git a/packages/SystemUI/res/drawable-hdpi/qs_scrubber_track.9.png b/packages/SystemUI/res/drawable-hdpi/qs_scrubber_track.9.png
deleted file mode 100644
index 0899d35..0000000
--- a/packages/SystemUI/res/drawable-hdpi/qs_scrubber_track.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/qs_scrubber_track.9.png b/packages/SystemUI/res/drawable-mdpi/qs_scrubber_track.9.png
deleted file mode 100644
index 2266449..0000000
--- a/packages/SystemUI/res/drawable-mdpi/qs_scrubber_track.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/qs_scrubber_track.9.png b/packages/SystemUI/res/drawable-xhdpi/qs_scrubber_track.9.png
deleted file mode 100644
index 3328add..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/qs_scrubber_track.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/qs_scrubber_track.9.png b/packages/SystemUI/res/drawable-xxhdpi/qs_scrubber_track.9.png
deleted file mode 100644
index ed651da..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/qs_scrubber_track.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/qs_scrubber_track.9.png b/packages/SystemUI/res/drawable-xxxhdpi/qs_scrubber_track.9.png
deleted file mode 100644
index 06e1202..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/qs_scrubber_track.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_qs_auto_rotate.xml b/packages/SystemUI/res/drawable/ic_qs_auto_rotate.xml
index 9c24c2c..47e1059 100644
--- a/packages/SystemUI/res/drawable/ic_qs_auto_rotate.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_auto_rotate.xml
@@ -22,5 +22,5 @@
     android:viewportHeight="24.0">
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M12.72,23H11C5.49,23 1,18.51 1,13h2c0,3.78 2.63,6.95 6.15,7.79L8.13,19L9.87,18L12.72,23zM13,1h-1.72l2.85,5L15.87,5l-1.02,-1.79C18.37,4.05 21,7.22 21,11h2C23,5.49 18.51,1 13,1zM10.23,6L18,13.76L13.77,18L6,10.24L10.23,6C10.23,6 10.23,6 10.23,6M10.23,4C9.72,4 9.21,4.2 8.82,4.59L4.59,8.82c-0.78,0.78 -0.78,2.04 0,2.82l7.77,7.77c0.39,0.39 0.9,0.59 1.41,0.59c0.51,0 1.02,-0.2 1.41,-0.59l4.24,-4.24c0.78,-0.78 0.78,-2.04 0,-2.82l-7.77,-7.77C11.26,4.2 10.75,4 10.23,4L10.23,4z"/>
+        android:pathData="M7.4,10.94H2.45V5.99l2,0.01v1.53l4.61,-4.61c0.64,-0.64 1.67,-0.66 2.29,-0.04l8.18,8.18h-2.83l-6.48,-6.48L5.86,8.95H7.4V10.94zM16.6,13.06l0.01,2h1.53l-4.36,4.36l-6.48,-6.48H4.46l8.19,8.19c0.62,0.62 1.65,0.6 2.29,-0.04l4.61,-4.61l0.01,0.01v1.53h1.99v-4.95H16.6z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_rotate_button.xml b/packages/SystemUI/res/drawable/ic_sysbar_rotate_button.xml
index 2cd7883..3304c19 100644
--- a/packages/SystemUI/res/drawable/ic_sysbar_rotate_button.xml
+++ b/packages/SystemUI/res/drawable/ic_sysbar_rotate_button.xml
@@ -17,16 +17,16 @@
 <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt">
     <aapt:attr name="android:drawable">
         <vector android:name="root"
-                android:width="21dp"
-                android:height="21dp"
-                android:viewportWidth="24.0"
-                android:viewportHeight="24.0">
+                android:width="28dp"
+                android:height="28dp"
+                android:viewportWidth="28.0"
+                android:viewportHeight="28.0">
             <!-- Use scaleX to flip icon so arrows always point in the direction of motion -->
-            <group android:name="icon" android:pivotX="12" android:pivotY="12"
+            <group android:name="icon" android:pivotX="14" android:pivotY="14"
                    android:scaleX="?attr/rotateButtonScaleX">
                 <!-- Tint color to be set directly -->
                 <path android:fillColor="#FFFFFFFF"
-                      android:pathData="M19,12c0,1.72 -0.63,3.3 -1.66,4.52l-1.44,-1.44C16.58,14.23 17,13.17 17,12c0,-2.76 -2.24,-5 -5,-5c-0.06,0 -0.11,0.01 -0.17,0.01l1.08,1.08L11.5,9.5L8,6l3.5,-3.5l1.41,1.42l-1.09,1.09C11.88,5.01 11.94,5 12,5C15.87,5 19,8.13 19,12zM12.5,14.51l-1.41,1.41l1.06,1.06C12.1,16.99 12.05,17 12,17c-2.76,0 -5,-2.24 -5,-5c0,-1.17 0.42,-2.23 1.09,-3.08L6.66,7.48C5.62,8.7 5,10.28 5,12c0,3.87 3.13,7 7,7c0.06,0 0.13,-0.01 0.19,-0.01v0l-1.1,1.1l1.41,1.41L16,18L12.5,14.51z"/>
+                      android:pathData="M12.02,10.83L9.25,8.06l2.77,-2.77l1.12,1.12l-0.85,0.86h5.16c0.72,0 1.31,0.56 1.31,1.26v9.16l-1.58,-1.58V8.85h-4.89l0.86,0.86L12.02,10.83zM15.98,17.17l-1.12,1.12l0.85,0.86h-4.88v-7.26L9.25,10.3v9.17c0,0.7 0.59,1.26 1.31,1.26h5.16v0.01l-0.85,0.85l1.12,1.12l2.77,-2.77L15.98,17.17z"/>
             </group>
         </vector>
     </aapt:attr>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 975055c..07f1ee0 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -137,8 +137,10 @@
 
     <color name="remote_input_accent">#eeeeee</color>
 
-    <color name="quick_step_track_background_dark">#61000000</color>
-    <color name="quick_step_track_background_light">#33FFFFFF</color>
+    <color name="quick_step_track_background_background_dark">#1F000000</color>
+    <color name="quick_step_track_background_background_light">#33FFFFFF</color>
+    <color name="quick_step_track_background_foreground_dark">#38000000</color>
+    <color name="quick_step_track_background_foreground_light">#59FFFFFF</color>
 
     <!-- Keyboard shortcuts colors -->
     <color name="ksh_application_group_color">#fff44336</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index f00957a..3c84e5a 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -252,6 +252,9 @@
          -->
     <dimen name="qs_header_system_icons_area_height">48dp</dimen>
 
+    <!-- How far the quick-quick settings panel extends below the status bar -->
+    <dimen name="qs_quick_header_panel_height">128dp</dimen>
+
     <!-- The height of the container that holds the system icons in the quick settings header in the
          car setting. -->
     <dimen name="car_qs_header_system_icons_area_height">54dp</dimen>
@@ -764,9 +767,6 @@
     <dimen name="volume_expander_margin_end">2dp</dimen>
     <dimen name="volume_expander_margin_top">6dp</dimen>
 
-    <!-- Padding between icon and text for managed profile toast -->
-    <dimen name="managed_profile_toast_padding">4dp</dimen>
-
     <!-- Thickness of the assist disclosure beams -->
     <dimen name="assist_disclosure_thickness">2.5dp</dimen>
 
@@ -922,14 +922,18 @@
 
     <dimen name="global_actions_top_padding">120dp</dimen>
 
-    <!-- the maximum offset in either direction that elements are moved horizontally to prevent
-            burn-in on AOD -->
+    <!-- The maximum offset in either direction that elements are moved horizontally to prevent
+         burn-in on AOD. -->
     <dimen name="burn_in_prevention_offset_x">8dp</dimen>
 
-    <!-- the maximum offset in either direction that elements are moved vertically to prevent
-            burn-in on AOD -->
+    <!-- The maximum offset in either direction that elements are moved vertically to prevent
+         burn-in on AOD. -->
     <dimen name="burn_in_prevention_offset_y">50dp</dimen>
 
+    <!-- The maximum offset in either direction that the charging indication moves vertically
+         to prevent burn-in on AOD. -->
+    <dimen name="charging_indication_burn_in_prevention_offset_y">5dp</dimen>
+
     <dimen name="corner_size">8dp</dimen>
     <dimen name="top_padding">0dp</dimen>
     <dimen name="bottom_padding">48dp</dimen>
@@ -1012,4 +1016,7 @@
     <!-- How much into a DisplayCutout's bounds we can go, on each side -->
     <dimen name="display_cutout_margin_consumption">0px</dimen>
 
+    <!-- How much we expand the touchable region of the status bar below the notch to catch touches
+         that just start below the notch. -->
+    <dimen name="display_cutout_touchable_region_size">12dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index edf56af..18f378e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1326,9 +1326,6 @@
     <!-- Hide quick settings tile confirmation button -->
     <string name="quick_settings_reset_confirmation_button">Hide</string>
 
-    <!-- Toast shown when user unlocks screen and managed profile activity is in the foreground -->
-    <string name="managed_profile_foreground_toast">You\'re using your work profile</string>
-
     <!-- volume stream names. All nouns. -->
     <string name="stream_voice_call">Call</string> <!-- STREAM_VOICE_CALL -->
     <string name="stream_system">System</string> <!-- STREAM_SYSTEM -->
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
index cd831d1..d38cc0f 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
@@ -54,6 +54,7 @@
     public static final int HIT_TARGET_HOME = 2;
     public static final int HIT_TARGET_OVERVIEW = 3;
     public static final int HIT_TARGET_ROTATION = 4;
+    public static final int HIT_TARGET_DEAD_ZONE = 5;
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({FLAG_DISABLE_SWIPE_UP,
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierText.java b/packages/SystemUI/src/com/android/keyguard/CarrierText.java
index 5b0f1c3..66475e2 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierText.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierText.java
@@ -334,8 +334,10 @@
                 break;
 
             case SimPermDisabled:
-                carrierText = getContext().getText(
-                        R.string.keyguard_permanent_disabled_sim_message_short);
+                carrierText = makeCarrierStringOnEmergencyCapable(
+                        getContext().getText(
+                                R.string.keyguard_permanent_disabled_sim_message_short),
+                        text);
                 break;
 
             case SimMissingLocked:
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 41df196..4014946 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -73,6 +73,7 @@
 
     private ArraySet<View> mVisibleInDoze;
     private boolean mPulsing;
+    private boolean mWasPulsing;
     private float mDarkAmount = 0;
     private int mTextColor;
     private float mWidgetPadding;
@@ -198,6 +199,9 @@
         mClockView.setElegantTextHeight(false);
     }
 
+    /**
+     * Moves clock and separator, adjusting margins when slice content changes.
+     */
     private void onSliceContentChanged() {
         boolean smallClock = mKeyguardSlice.hasHeader() || mPulsing;
         float clockScale = smallClock ? mSmallClockScale : 1;
@@ -220,11 +224,12 @@
     @Override
     public void onLayoutChange(View view, int left, int top, int right, int bottom,
             int oldLeft, int oldTop, int oldRight, int oldBottom) {
-        int heightOffset = mPulsing ? 0 : getHeight() - mLastLayoutHeight;
+        int heightOffset = mPulsing || mWasPulsing ? 0 : getHeight() - mLastLayoutHeight;
         boolean hasHeader = mKeyguardSlice.hasHeader();
         boolean smallClock = hasHeader || mPulsing;
         long duration = KeyguardSliceView.DEFAULT_ANIM_DURATION;
-        long delay = smallClock ? 0 : duration / 4;
+        long delay = smallClock || mWasPulsing ? 0 : duration / 4;
+        mWasPulsing = false;
 
         boolean shouldAnimate = mKeyguardSlice.getLayoutTransition() != null
                 && mKeyguardSlice.getLayoutTransition().isRunning();
@@ -448,7 +453,18 @@
     }
 
     public void setPulsing(boolean pulsing, boolean animate) {
+        if (mPulsing == pulsing) {
+            return;
+        }
+        if (mPulsing) {
+            mWasPulsing = true;
+        }
         mPulsing = pulsing;
+        // Animation can look really weird when the slice has a header, let's hide the views
+        // immediately instead of fading them away.
+        if (mKeyguardSlice.hasHeader()) {
+            animate = false;
+        }
         mKeyguardSlice.setPulsing(pulsing, animate);
         updateDozeVisibleViews();
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 62cd13b..ef3aa42 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1589,6 +1589,10 @@
         }
     }
 
+    public boolean isKeyguardVisible() {
+        return mKeyguardIsVisible;
+    }
+
     /**
      * Notifies that the visibility state of Keyguard has changed.
      *
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 59501f0..81dd5eb 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -55,6 +55,7 @@
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
 import com.android.systemui.util.Utils.DisableStateTracker;
+import com.android.systemui.R;
 
 import java.text.NumberFormat;
 
@@ -72,6 +73,7 @@
     private int mTextColor;
     private int mLevel;
     private boolean mForceShowPercent;
+    private boolean mShowPercentAvailable;
 
     private int mDarkModeBackgroundColor;
     private int mDarkModeFillColor;
@@ -111,6 +113,9 @@
         atts.recycle();
 
         mSettingObserver = new SettingObserver(new Handler(context.getMainLooper()));
+        mShowPercentAvailable = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_battery_percentage_setting_available);
+
 
         addOnAttachStateChangeListener(
                 new DisableStateTracker(DISABLE_NONE, DISABLE2_SYSTEM_ICONS));
@@ -259,8 +264,11 @@
 
     private void updateShowPercent() {
         final boolean showing = mBatteryPercentView != null;
-        if (0 != Settings.System.getIntForUser(getContext().getContentResolver(),
-                SHOW_BATTERY_PERCENT, 0, mUser) || mForceShowPercent) {
+        final boolean systemSetting = 0 != Settings.System
+                .getIntForUser(getContext().getContentResolver(),
+                SHOW_BATTERY_PERCENT, 0, mUser);
+
+        if ((mShowPercentAvailable && systemSetting) || mForceShowPercent) {
             if (!showing) {
                 mBatteryPercentView = loadPercentView();
                 if (mTextColor != 0) mBatteryPercentView.setTextColor(mTextColor);
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index b8a57bf..50d862d 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -290,7 +290,7 @@
                         || dh != mLastSurfaceHeight;
 
                 boolean redrawNeeded = surfaceDimensionsChanged || newRotation != mLastRotation
-                        || mSurfaceRedrawNeeded;
+                        || mSurfaceRedrawNeeded || mNeedsDrawAfterLoadingWallpaper;
                 if (!redrawNeeded && !mOffsetsChanged) {
                     if (DEBUG) {
                         Log.d(TAG, "Suppressed drawFrame since redraw is not needed "
diff --git a/packages/SystemUI/src/com/android/systemui/Interpolators.java b/packages/SystemUI/src/com/android/systemui/Interpolators.java
index aeef496..eb704c8 100644
--- a/packages/SystemUI/src/com/android/systemui/Interpolators.java
+++ b/packages/SystemUI/src/com/android/systemui/Interpolators.java
@@ -31,6 +31,13 @@
  */
 public class Interpolators {
     public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
+
+    /**
+     * Like {@link #FAST_OUT_SLOW_IN}, but used in case the animation is played in reverse (i.e. t
+     * goes from 1 to 0 instead of 0 to 1).
+     */
+    public static final Interpolator FAST_OUT_SLOW_IN_REVERSE =
+            new PathInterpolator(0.8f, 0f, 0.6f, 1f);
     public static final Interpolator FAST_OUT_LINEAR_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
     public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f);
     public static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
@@ -51,4 +58,11 @@
      */
     public static final Interpolator TOUCH_RESPONSE =
             new PathInterpolator(0.3f, 0f, 0.1f, 1f);
+
+    /**
+     * Like {@link #TOUCH_RESPONSE}, but used in case the animation is played in reverse (i.e. t
+     * goes from 1 to 0 instead of 0 to 1).
+     */
+    public static final Interpolator TOUCH_RESPONSE_REVERSE =
+            new PathInterpolator(0.9f, 0f, 0.7f, 1f);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index efaf557..194679c 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -52,6 +52,7 @@
 import android.view.View.OnLayoutChangeListener;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
+import android.view.ViewTreeObserver;
 import android.view.WindowManager;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
@@ -89,6 +90,9 @@
     private float mDensity;
     private WindowManager mWindowManager;
     private int mRotation;
+    private DisplayCutoutView mCutoutTop;
+    private DisplayCutoutView mCutoutBottom;
+    private boolean mPendingRotationChange;
 
     @Override
     public void start() {
@@ -122,6 +126,22 @@
 
             @Override
             public void onDisplayChanged(int displayId) {
+                if (mOverlay != null && mBottomOverlay != null
+                        && mRotation != RotationUtils.getExactRotation(mContext)) {
+                    // We cannot immediately update the orientation. Otherwise
+                    // WindowManager is still deferring layout until it has finished dispatching
+                    // the config changes, which may cause divergence between what we draw
+                    // (new orientation), and where we are placed on the screen (old orientation).
+                    // Instead we wait until either:
+                    // - we are trying to redraw. This because WM resized our window and told us to.
+                    // - the config change has been dispatched, so WM is no longer deferring layout.
+                    mPendingRotationChange = true;
+                    mOverlay.getViewTreeObserver().addOnPreDrawListener(
+                            new RestartingPreDrawListener(mOverlay));
+                    mBottomOverlay.getViewTreeObserver().addOnPreDrawListener(
+                            new RestartingPreDrawListener(mBottomOverlay));
+
+                }
                 updateOrientation();
             }
         };
@@ -135,14 +155,14 @@
     private void setupDecorations() {
         mOverlay = LayoutInflater.from(mContext)
                 .inflate(R.layout.rounded_corners, null);
-        DisplayCutoutView cutoutTop = new DisplayCutoutView(mContext, true,
-                this::updateWindowVisibilities);
-        ((ViewGroup)mOverlay).addView(cutoutTop);
+        mCutoutTop = new DisplayCutoutView(mContext, true,
+                this::updateWindowVisibilities, this);
+        ((ViewGroup)mOverlay).addView(mCutoutTop);
         mBottomOverlay = LayoutInflater.from(mContext)
                 .inflate(R.layout.rounded_corners, null);
-        DisplayCutoutView cutoutBottom = new DisplayCutoutView(mContext, false,
-                this::updateWindowVisibilities);
-        ((ViewGroup)mBottomOverlay).addView(cutoutBottom);
+        mCutoutBottom = new DisplayCutoutView(mContext, false,
+                this::updateWindowVisibilities, this);
+        ((ViewGroup)mBottomOverlay).addView(mCutoutBottom);
 
         mOverlay.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
         mOverlay.setAlpha(0);
@@ -172,8 +192,8 @@
                 ((ImageView) mOverlay.findViewById(R.id.right)).setImageTintList(tintList);
                 ((ImageView) mBottomOverlay.findViewById(R.id.left)).setImageTintList(tintList);
                 ((ImageView) mBottomOverlay.findViewById(R.id.right)).setImageTintList(tintList);
-                cutoutTop.setColor(tint);
-                cutoutBottom.setColor(tint);
+                mCutoutTop.setColor(tint);
+                mCutoutBottom.setColor(tint);
             }
         };
         setting.setListening(true);
@@ -199,6 +219,7 @@
 
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
+        mPendingRotationChange = false;
         updateOrientation();
         if (shouldDrawCutout() && mOverlay == null) {
             setupDecorations();
@@ -206,6 +227,9 @@
     }
 
     protected void updateOrientation() {
+        if (mPendingRotationChange) {
+            return;
+        }
         int newRotation = RotationUtils.getExactRotation(mContext);
         if (newRotation != mRotation) {
             mRotation = newRotation;
@@ -245,6 +269,9 @@
             updateView(bottomRight, Gravity.TOP | Gravity.LEFT, 0);
         }
 
+        mCutoutTop.setRotation(mRotation);
+        mCutoutBottom.setRotation(mRotation);
+
         updateWindowVisibilities();
     }
 
@@ -416,15 +443,19 @@
         private final Rect mBoundingRect = new Rect();
         private final Path mBoundingPath = new Path();
         private final int[] mLocation = new int[2];
-        private final boolean mStart;
+        private final boolean mInitialStart;
         private final Runnable mVisibilityChangedListener;
+        private final ScreenDecorations mDecorations;
         private int mColor = Color.BLACK;
+        private boolean mStart;
+        private int mRotation;
 
         public DisplayCutoutView(Context context, boolean start,
-                Runnable visibilityChangedListener) {
+                Runnable visibilityChangedListener, ScreenDecorations decorations) {
             super(context);
-            mStart = start;
+            mInitialStart = start;
             mVisibilityChangedListener = visibilityChangedListener;
+            mDecorations = decorations;
             setId(R.id.display_cutout);
         }
 
@@ -475,7 +506,22 @@
             }
         }
 
+        public void setRotation(int rotation) {
+            mRotation = rotation;
+            update();
+        }
+
+        private boolean isStart() {
+            final boolean flipped = (mRotation == RotationUtils.ROTATION_SEASCAPE
+                    || mRotation == RotationUtils.ROTATION_UPSIDE_DOWN);
+            return flipped ? !mInitialStart : mInitialStart;
+        }
+
         private void update() {
+            if (!isAttachedToWindow() || mDecorations.mPendingRotationChange) {
+                return;
+            }
+            mStart = isStart();
             requestLayout();
             getDisplay().getDisplayInfo(mInfo);
             mBounds.setEmpty();
@@ -560,31 +606,34 @@
                     resolveSizeAndState(mBoundingRect.height(), heightMeasureSpec, 0));
         }
 
-        public static void boundsFromDirection(DisplayCutout displayCutout, int gravity, Rect out) {
+        public static void boundsFromDirection(DisplayCutout displayCutout, int gravity,
+                Rect out) {
+            Region bounds = boundsFromDirection(displayCutout, gravity);
+            out.set(bounds.getBounds());
+            bounds.recycle();
+        }
+
+        public static Region boundsFromDirection(DisplayCutout displayCutout, int gravity) {
             Region bounds = displayCutout.getBounds();
             switch (gravity) {
                 case Gravity.TOP:
                     bounds.op(0, 0, Integer.MAX_VALUE, displayCutout.getSafeInsetTop(),
                             Region.Op.INTERSECT);
-                    out.set(bounds.getBounds());
                     break;
                 case Gravity.LEFT:
                     bounds.op(0, 0, displayCutout.getSafeInsetLeft(), Integer.MAX_VALUE,
                             Region.Op.INTERSECT);
-                    out.set(bounds.getBounds());
                     break;
                 case Gravity.BOTTOM:
                     bounds.op(0, displayCutout.getSafeInsetTop() + 1, Integer.MAX_VALUE,
                             Integer.MAX_VALUE, Region.Op.INTERSECT);
-                    out.set(bounds.getBounds());
                     break;
                 case Gravity.RIGHT:
                     bounds.op(displayCutout.getSafeInsetLeft() + 1, 0, Integer.MAX_VALUE,
                             Integer.MAX_VALUE, Region.Op.INTERSECT);
-                    out.set(bounds.getBounds());
                     break;
             }
-            bounds.recycle();
+            return bounds;
         }
 
         private void localBounds(Rect out) {
@@ -635,4 +684,28 @@
         return rotation == RotationUtils.ROTATION_LANDSCAPE || rotation ==
                 RotationUtils.ROTATION_SEASCAPE;
     }
+
+    /**
+     * A pre-draw listener, that cancels the draw and restarts the traversal with the updated
+     * window attributes.
+     */
+    private class RestartingPreDrawListener implements ViewTreeObserver.OnPreDrawListener {
+
+        private final View mView;
+
+        private RestartingPreDrawListener(View view) {
+            mView = view;
+        }
+
+        @Override
+        public boolean onPreDraw() {
+            mPendingRotationChange = false;
+            mView.getViewTreeObserver().removeOnPreDrawListener(this);
+            // This changes the window attributes - we need to restart the traversal for them to
+            // take effect.
+            updateOrientation();
+            mView.invalidate();
+            return false;
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
index 9a43d9e..3c8a461d 100644
--- a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
+++ b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
@@ -21,7 +21,6 @@
 import android.content.Context;
 import android.os.Handler;
 import android.os.RemoteException;
-import android.os.Trace;
 import android.os.UserHandle;
 import android.util.Log;
 import android.view.Display;
@@ -46,7 +45,7 @@
 public class SysuiColorExtractor extends ColorExtractor implements Dumpable {
     private static final String TAG = "SysuiColorExtractor";
     private boolean mWallpaperVisible;
-    private boolean mMediaBackdropVisible;
+    private boolean mHasBackdrop;
     // Colors to return when the wallpaper isn't visible
     private final GradientColors mWpHiddenColors;
 
@@ -165,7 +164,7 @@
                 return mWpHiddenColors;
             }
         } else {
-            if (mMediaBackdropVisible) {
+            if (mHasBackdrop) {
                 return mWpHiddenColors;
             } else {
                 return super.getColors(which, type);
@@ -181,9 +180,9 @@
         }
     }
 
-    public void setMediaBackdropVisible(boolean visible) {
-        if (mMediaBackdropVisible != visible) {
-            mMediaBackdropVisible = visible;
+    public void setHasBackdrop(boolean hasBackdrop) {
+        if (mHasBackdrop != hasBackdrop) {
+            mHasBackdrop = hasBackdrop;
             triggerColorsChanged(WallpaperManager.FLAG_LOCK);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 6809e76..89688fb 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -344,6 +344,11 @@
      */
     private WorkLockActivityController mWorkLockController;
 
+    /**
+     * @see #setPulsing(boolean)
+     */
+    private boolean mPulsing;
+
     private boolean mLockLater;
 
     private boolean mWakeAndUnlocking;
@@ -1798,10 +1803,12 @@
 
                 int flags = 0;
                 if (mStatusBarKeyguardViewManager.shouldDisableWindowAnimationsForUnlock()
-                        || mWakeAndUnlocking) {
-                    flags |= WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
+                        || (mWakeAndUnlocking && !mPulsing)) {
+                    flags |= WindowManagerPolicyConstants
+                            .KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
                 }
-                if (mStatusBarKeyguardViewManager.isGoingToNotificationShade()) {
+                if (mStatusBarKeyguardViewManager.isGoingToNotificationShade()
+                        || (mWakeAndUnlocking && mPulsing)) {
                     flags |= WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
                 }
                 if (mStatusBarKeyguardViewManager.isUnlockWithWallpaper()) {
@@ -2100,10 +2107,20 @@
         pw.print("  mDrawnCallback: "); pw.println(mDrawnCallback);
     }
 
+    /**
+     * @param aodShowing true when AOD - or ambient mode - is showing.
+     */
     public void setAodShowing(boolean aodShowing) {
         setShowingLocked(mShowing, aodShowing);
     }
 
+    /**
+     * @param pulsing true when device temporarily wakes up to display an incoming notification.
+     */
+    public void setPulsing(boolean pulsing) {
+        mPulsing = pulsing;
+    }
+
     private static class StartKeyguardExitAnimParams {
 
         long startTime;
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 6801e69..9a648d1 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -77,6 +77,7 @@
     private int mPlugType = 0;
     private int mInvalidCharger = 0;
     private EnhancedEstimates mEnhancedEstimates;
+    private Estimate mLastEstimate;
     private boolean mLowWarningShownThisChargeCycle;
     private boolean mSevereWarningShownThisChargeCycle;
 
@@ -247,7 +248,8 @@
 
                 // Show the correct version of low battery warning if needed
                 ThreadUtils.postOnBackgroundThread(() -> {
-                    maybeShowBatteryWarning(plugged, oldPlugged, oldBucket, bucket);
+                    maybeShowBatteryWarning(
+                            oldBatteryLevel, plugged, oldPlugged, oldBucket, bucket);
                 });
 
             } else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
@@ -262,14 +264,18 @@
         }
     }
 
-    protected void maybeShowBatteryWarning(boolean plugged, boolean oldPlugged, int oldBucket,
-        int bucket) {
+    protected void maybeShowBatteryWarning(int oldBatteryLevel, boolean plugged, boolean oldPlugged,
+            int oldBucket, int bucket) {
         boolean isPowerSaver = mPowerManager.isPowerSaveMode();
         // only play SFX when the dialog comes up or the bucket changes
         final boolean playSound = bucket != oldBucket || oldPlugged;
         final boolean hybridEnabled = mEnhancedEstimates.isHybridNotificationEnabled();
         if (hybridEnabled) {
-            final Estimate estimate = mEnhancedEstimates.getEstimate();
+            Estimate estimate = mLastEstimate;
+            if (estimate == null || mBatteryLevel != oldBatteryLevel) {
+                estimate = mEnhancedEstimates.getEstimate();
+                mLastEstimate = estimate;
+            }
             // Turbo is not always booted once SysUI is running so we have ot make sure we actually
             // get data back
             if (estimate != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index a9bfa45..36d8326 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -34,6 +34,7 @@
 import android.provider.AlarmClock;
 import android.service.notification.ZenModeConfig;
 import android.support.annotation.VisibleForTesting;
+import android.widget.FrameLayout;
 import android.text.format.DateUtils;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -269,8 +270,22 @@
         updateResources();
     }
 
+    /**
+     * The height of QQS should always be the status bar height + 128dp. This is normally easy, but
+     * when there is a notch involved the status bar can remain a fixed pixel size.
+     */
+    private void updateMinimumHeight() {
+        int sbHeight = mContext.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.status_bar_height);
+        int qqsHeight = mContext.getResources().getDimensionPixelSize(
+                R.dimen.qs_quick_header_panel_height);
+
+        setMinimumHeight(sbHeight + qqsHeight);
+    }
+
     private void updateResources() {
         Resources resources = mContext.getResources();
+        updateMinimumHeight();
 
         // Update height for a few views, especially due to landscape mode restricting space.
         mHeaderTextContainerView.getLayoutParams().height =
@@ -281,10 +296,17 @@
                 com.android.internal.R.dimen.quick_qs_offset_height);
         mSystemIconsView.setLayoutParams(mSystemIconsView.getLayoutParams());
 
-        getLayoutParams().height = resources.getDimensionPixelSize(mQsDisabled
-                ? com.android.internal.R.dimen.quick_qs_offset_height
-                : com.android.internal.R.dimen.quick_qs_total_height);
-        setLayoutParams(getLayoutParams());
+        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
+        if (mQsDisabled) {
+            lp.height = resources.getDimensionPixelSize(
+                    com.android.internal.R.dimen.quick_qs_offset_height);
+        } else {
+            lp.height = Math.max(getMinimumHeight(),
+                    resources.getDimensionPixelSize(
+                            com.android.internal.R.dimen.quick_qs_offset_height));
+        }
+
+        setLayoutParams(lp);
 
         updateStatusIconAlphaAnimator();
         updateHeaderTextContainerAlphaAnimator();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
index cc60f87..42e5adc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
@@ -265,6 +265,8 @@
     @Override
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfo(info);
+        // Clear selected state so it is not announce by talkback.
+        info.setSelected(false);
         if (!TextUtils.isEmpty(mAccessibilityClass)) {
             info.setClassName(mAccessibilityClass);
             if (Switch.class.getName().equals(mAccessibilityClass)) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
index 8d8e206..ce9d7e1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
@@ -479,7 +479,7 @@
                 ViewGroup.LayoutParams.WRAP_CONTENT,
                 ViewGroup.LayoutParams.WRAP_CONTENT,
                 x, -mNavBarHeight / 2,
-                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+                WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
                 flags,
                 PixelFormat.TRANSLUCENT);
         lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
index 39485c3..29e0eda 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
@@ -178,11 +178,7 @@
      * @param translationX how to translate the horizontal position
      */
     public void setPanelTranslation(float translationX) {
-        if (isLayoutRtl()) {
-            setTranslationX(translationX + mCutOutInset);
-        } else {
-            setTranslationX(translationX - mCutOutInset);
-        }
+        setTranslationX(translationX);
         updateDrawingRect();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
index 1287ced..25684ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
@@ -108,16 +108,6 @@
             } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
                 // Start the overview connection to the launcher service
                 Dependency.get(OverviewProxyService.class).startConnectionToCurrentUser();
-            } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
-                try {
-                    final int lastResumedActivityUserId =
-                            ActivityManager.getService().getLastResumedActivityUserId();
-                    if (mUserManager.isManagedProfile(lastResumedActivityUserId)) {
-                        showForegroundManagedProfileActivityToast();
-                    }
-                } catch (RemoteException e) {
-                    // Abandon hope activity manager not running.
-                }
             } else if (NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION.equals(action)) {
                 final IntentSender intentSender = intent.getParcelableExtra(Intent.EXTRA_INTENT);
                 final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
@@ -224,7 +214,6 @@
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_USER_SWITCHED);
         filter.addAction(Intent.ACTION_USER_ADDED);
-        filter.addAction(Intent.ACTION_USER_PRESENT);
         filter.addAction(Intent.ACTION_USER_UNLOCKED);
         mContext.registerReceiver(mBaseBroadcastReceiver, filter);
 
@@ -237,19 +226,6 @@
         mSettingsObserver.onChange(false);  // set up
     }
 
-    private void showForegroundManagedProfileActivityToast() {
-        Toast toast = Toast.makeText(mContext,
-                R.string.managed_profile_foreground_toast,
-                Toast.LENGTH_SHORT);
-        TextView text = toast.getView().findViewById(android.R.id.message);
-        text.setCompoundDrawablesRelativeWithIntrinsicBounds(
-                R.drawable.stat_sys_managed_profile_status, 0, 0, 0);
-        int paddingPx = mContext.getResources().getDimensionPixelSize(
-                R.dimen.managed_profile_toast_padding);
-        text.setCompoundDrawablePadding(paddingPx);
-        toast.show();
-    }
-
     public boolean shouldShowLockscreenNotifications() {
         return mShowLockscreenNotifications;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index fac7768..3063199 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -482,8 +482,8 @@
         iconTransformDistance = Math.min(iconTransformDistance, fullHeight);
         if (isLastChild) {
             fullHeight = Math.min(fullHeight, row.getMinHeight() - getIntrinsicHeight());
-            iconTransformDistance = Math.min(iconTransformDistance,
-                    row.getMinHeight() - getIntrinsicHeight() * icon.getIconScale());
+            iconTransformDistance = Math.min(iconTransformDistance, row.getMinHeight()
+                    - getIntrinsicHeight());
         }
         float viewEnd = viewStart + fullHeight;
         if (expandingAnimated && mAmbientState.getScrollY() == 0
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 27cb077..c0e7ac4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -197,6 +197,7 @@
                 mDarkAmount);
         final int outerBounds = mStatusBarIconSize;
         mIconScale = (float)imageBounds / (float)outerBounds;
+        updatePivot();
     }
 
     private void updateIconScaleForSystemIcons() {
@@ -859,6 +860,12 @@
             mLayoutRunnable.run();
             mLayoutRunnable = null;
         }
+        updatePivot();
+    }
+
+    private void updatePivot() {
+        setPivotX((1 - mIconScale) / 2.0f * getWidth());
+        setPivotY((getHeight() - mIconScale * getWidth()) / 2.0f);
     }
 
     public void executeOnLayout(Runnable runnable) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
index f0b1a82..7cb6a19 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
@@ -210,15 +210,28 @@
             // until the clock and the notifications are faded out.
             mStatusBarWindowManager.setForceDozeBrightness(true);
         }
-        if (!wasDeviceInteractive) {
-            if (DEBUG_FP_WAKELOCK) {
-                Log.i(TAG, "fp wakelock: Authenticated, waking up...");
+        // During wake and unlock, we need to draw black before waking up to avoid abrupt
+        // brightness changes due to display state transitions.
+        boolean alwaysOnEnabled = DozeParameters.getInstance(mContext).getAlwaysOn();
+        boolean delayWakeUp = mode == MODE_WAKE_AND_UNLOCK && alwaysOnEnabled;
+        Runnable wakeUp = ()-> {
+            if (!wasDeviceInteractive) {
+                if (DEBUG_FP_WAKELOCK) {
+                    Log.i(TAG, "fp wakelock: Authenticated, waking up...");
+                }
+                mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.policy:FINGERPRINT");
             }
-            mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.policy:FINGERPRINT");
+            if (delayWakeUp) {
+                mKeyguardViewMediator.onWakeAndUnlocking();
+            }
+            Trace.beginSection("release wake-and-unlock");
+            releaseFingerprintWakeLock();
+            Trace.endSection();
+        };
+
+        if (!delayWakeUp) {
+            wakeUp.run();
         }
-        Trace.beginSection("release wake-and-unlock");
-        releaseFingerprintWakeLock();
-        Trace.endSection();
         switch (mMode) {
             case MODE_DISMISS_BOUNCER:
                 Trace.beginSection("MODE_DISMISS");
@@ -251,7 +264,11 @@
                     mUpdateMonitor.awakenFromDream();
                 }
                 mStatusBarWindowManager.setStatusBarFocusable(false);
-                mKeyguardViewMediator.onWakeAndUnlocking();
+                if (delayWakeUp) {
+                    mHandler.postDelayed(wakeUp, 50);
+                } else {
+                    mKeyguardViewMediator.onWakeAndUnlocking();
+                }
                 if (mStatusBar.getNavigationBarView() != null) {
                     mStatusBar.getNavigationBarView().setWakeAndUnlocking(true);
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index 409a783..4e7f4f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -18,6 +18,7 @@
 
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.view.DisplayCutout;
 import android.view.View;
 import android.view.WindowInsets;
 
@@ -159,8 +160,15 @@
         }
 
         WindowInsets windowInset = mStackScroller.getRootWindowInsets();
-        return windowInset.getSystemWindowInsetLeft() + mStackScroller.getRight()
-                + windowInset.getSystemWindowInsetRight() - realDisplaySize;
+        DisplayCutout cutout = (windowInset != null) ? windowInset.getDisplayCutout() : null;
+        int sysWinLeft = (windowInset != null) ? windowInset.getStableInsetLeft() : 0;
+        int sysWinRight = (windowInset != null) ? windowInset.getStableInsetRight() : 0;
+        int cutoutLeft = (cutout != null) ? cutout.getSafeInsetLeft() : 0;
+        int cutoutRight = (cutout != null) ? cutout.getSafeInsetRight() : 0;
+        int leftInset = Math.max(sysWinLeft, cutoutLeft);
+        int rightInset = Math.max(sysWinRight, cutoutRight);
+
+        return leftInset + mStackScroller.getRight() + rightInset - realDisplaySize;
     }
 
     public void updatePanelTranslation() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index fa0a774..0aad438 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -21,15 +21,22 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.graphics.Region.Op;
 import android.support.v4.util.ArraySet;
 import android.util.Log;
 import android.util.Pools;
+import android.view.DisplayCutout;
+import android.view.Gravity;
 import android.view.View;
 import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.InternalInsetsInfo;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
+import com.android.systemui.ScreenDecorations;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.StatusBarState;
@@ -41,6 +48,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Stack;
 
 /**
@@ -60,6 +68,7 @@
 
     private int mStatusBarHeight;
     private int mHeadsUpInset;
+    private int mDisplayCutoutTouchableRegionSize;
     private boolean mTrackingHeadsUp;
     private HashSet<String> mSwipedOutKeys = new HashSet<>();
     private HashSet<NotificationData.Entry> mEntriesToRemoveAfterExpand = new HashSet<>();
@@ -120,6 +129,8 @@
                 com.android.internal.R.dimen.status_bar_height);
         mHeadsUpInset = mStatusBarHeight + resources.getDimensionPixelSize(
                 R.dimen.heads_up_status_bar_padding);
+        mDisplayCutoutTouchableRegionSize = resources.getDimensionPixelSize(
+                R.dimen.display_cutout_touchable_region_size);
     }
 
     @Override
@@ -128,6 +139,11 @@
         initResources();
     }
 
+    @Override
+    public void onOverlayChanged() {
+        initResources();
+    }
+
     ///////////////////////////////////////////////////////////////////////////////////////////////
     //  Public methods:
 
@@ -301,12 +317,32 @@
 
             info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
             info.touchableRegion.set(minX, 0, maxX, mHeadsUpInset + height);
-        } else if (mHeadsUpGoingAway || mWaitingOnCollapseWhenGoingAway) {
-            info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
-            info.touchableRegion.set(0, 0, mStatusBarWindowView.getWidth(), mStatusBarHeight);
+        } else {
+            setCollapsedTouchableInsets(info);
         }
     }
 
+    private void setCollapsedTouchableInsets(ViewTreeObserver.InternalInsetsInfo info) {
+        info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
+        info.touchableRegion.set(0, 0, mStatusBarWindowView.getWidth(), mStatusBarHeight);
+        updateRegionForNotch(info.touchableRegion);
+    }
+
+    private void updateRegionForNotch(Region region) {
+        DisplayCutout cutout = mStatusBarWindowView.getRootWindowInsets().getDisplayCutout();
+        if (cutout == null) {
+            return;
+        }
+
+        // Expand touchable region such that we also catch touches that just start below the notch
+        // area.
+        Region bounds = ScreenDecorations.DisplayCutoutView.boundsFromDirection(
+                cutout, Gravity.TOP);
+        bounds.translate(0, mDisplayCutoutTouchableRegionSize);
+        region.op(bounds, Op.UNION);
+        bounds.recycle();
+    }
+
     @Override
     public void onConfigChanged(Configuration newConfig) {
         Resources resources = mContext.getResources();
@@ -403,7 +439,8 @@
 
     private void updateTouchableRegionListener() {
         boolean shouldObserve = hasPinnedHeadsUp() || mHeadsUpGoingAway
-                || mWaitingOnCollapseWhenGoingAway;
+                || mWaitingOnCollapseWhenGoingAway
+                || mStatusBarWindowView.getRootWindowInsets().getDisplayCutout() != null;
         if (shouldObserve == mIsObserving) {
             return;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 0716b37..60d62d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -172,6 +172,7 @@
     private int mIndicationBottomMarginAmbient;
     private float mDarkAmount;
     private int mBurnInXOffset;
+    private int mBurnInYOffset;
 
     public KeyguardBottomAreaView(Context context) {
         this(context, null);
@@ -245,6 +246,8 @@
                 R.dimen.keyguard_indication_margin_bottom);
         mIndicationBottomMarginAmbient = getResources().getDimensionPixelSize(
                 R.dimen.keyguard_indication_margin_bottom_ambient);
+        mBurnInYOffset = getResources().getDimensionPixelSize(
+                R.dimen.charging_indication_burn_in_prevention_offset_y);
         updateCameraVisibility();
         mUnlockMethodCache = UnlockMethodCache.getInstance(getContext());
         mUnlockMethodCache.addListener(this);
@@ -317,6 +320,8 @@
                 R.dimen.keyguard_indication_margin_bottom);
         mIndicationBottomMarginAmbient = getResources().getDimensionPixelSize(
                 R.dimen.keyguard_indication_margin_bottom_ambient);
+        mBurnInYOffset = getResources().getDimensionPixelSize(
+                R.dimen.charging_indication_burn_in_prevention_offset_y);
         MarginLayoutParams mlp = (MarginLayoutParams) mIndicationArea.getLayoutParams();
         if (mlp.bottomMargin != mIndicationBottomMargin) {
             mlp.bottomMargin = mIndicationBottomMargin;
@@ -560,12 +565,6 @@
             return;
         }
         mDarkAmount = darkAmount;
-        // Let's randomize the bottom margin every time we wake up to avoid burn-in.
-        if (darkAmount == 0) {
-            mIndicationBottomMarginAmbient = getResources().getDimensionPixelSize(
-                    R.dimen.keyguard_indication_margin_bottom_ambient)
-                    + (int) (Math.random() * mIndicationText.getTextSize());
-        }
         mIndicationArea.setAlpha(MathUtils.lerp(1f, 0.7f, darkAmount));
         mIndicationArea.setTranslationY(MathUtils.lerp(0,
                 mIndicationBottomMargin - mIndicationBottomMarginAmbient, darkAmount));
@@ -841,8 +840,9 @@
     public void dozeTimeTick() {
         if (mDarkAmount == 1) {
             // Move indication every minute to avoid burn-in
-            final int dozeTranslation = mIndicationBottomMargin - mIndicationBottomMarginAmbient;
-            mIndicationArea.setTranslationY(dozeTranslation + (float) Math.random() * 5);
+            int dozeTranslation = mIndicationBottomMargin - mIndicationBottomMarginAmbient;
+            int burnInYOffset = (int) (-mBurnInYOffset + Math.random() * mBurnInYOffset * 2);
+            mIndicationArea.setTranslationY(dozeTranslation + burnInYOffset);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 0bd3cc7..db84222 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -67,6 +67,7 @@
     private static final int LAYOUT_CUTOUT = 1;
     private static final int LAYOUT_NO_CUTOUT = 2;
 
+    private boolean mShowPercentAvailable;
     private boolean mBatteryCharging;
     private boolean mKeyguardUserSwitcherShowing;
     private boolean mBatteryListening;
@@ -165,6 +166,8 @@
                 R.dimen.system_icons_super_container_avatarless_margin_end);
         mCutoutSideNudge = getResources().getDimensionPixelSize(
                 R.dimen.display_cutout_margin_consumption);
+        mShowPercentAvailable = getContext().getResources().getBoolean(
+                com.android.internal.R.bool.config_battery_percentage_setting_available);
     }
 
     private void updateVisibilities() {
@@ -186,7 +189,7 @@
                 mMultiUserSwitch.setVisibility(View.GONE);
             }
         }
-        mBatteryView.setForceShowPercent(mBatteryCharging);
+        mBatteryView.setForceShowPercent(mBatteryCharging && mShowPercentAvailable);
     }
 
     private void updateSystemIconsLayoutParams() {
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 2a1f92f..f8b79c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -18,6 +18,7 @@
 
 import static android.view.MotionEvent.ACTION_DOWN;
 import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_BACK;
+import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_DEAD_ZONE;
 import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_HOME;
 import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_NONE;
 
@@ -328,15 +329,15 @@
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent event) {
-        if (shouldDeadZoneConsumeTouchEvents(event)) {
-            return true;
-        }
+        final boolean deadZoneConsumed = shouldDeadZoneConsumeTouchEvents(event);
         switch (event.getActionMasked()) {
             case ACTION_DOWN:
                 int x = (int) event.getX();
                 int y = (int) event.getY();
                 mDownHitTarget = HIT_TARGET_NONE;
-                if (getBackButton().isVisible() && mBackButtonBounds.contains(x, y)) {
+                if (deadZoneConsumed) {
+                    mDownHitTarget = HIT_TARGET_DEAD_ZONE;
+                } else if (getBackButton().isVisible() && mBackButtonBounds.contains(x, y)) {
                     mDownHitTarget = HIT_TARGET_BACK;
                 } else if (getHomeButton().isVisible() && mHomeButtonBounds.contains(x, y)) {
                     mDownHitTarget = HIT_TARGET_HOME;
@@ -353,9 +354,7 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent event) {
-        if (shouldDeadZoneConsumeTouchEvents(event)) {
-            return true;
-        }
+        shouldDeadZoneConsumeTouchEvents(event);
         if (mGestureHelper.onTouchEvent(event)) {
             return true;
         }
@@ -764,7 +763,7 @@
                 showSwipeUpUI ? mQuickStepAccessibilityDelegate : null);
     }
 
-    private void updateSlippery() {
+    public void updateSlippery() {
         setSlippery(!isQuickStepSwipeUpEnabled() || mPanelView.isFullyExpanded());
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 44d666e..2bfdfeb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -47,6 +47,8 @@
     private final Rect mTintArea = new Rect();
     private NotificationStackScrollLayout mNotificationScrollLayout;
     private Context mContext;
+    private boolean mFullyDark;
+    private boolean mHasShelfIconsWhenFullyDark;
 
     public NotificationIconAreaController(Context context, StatusBar statusBar) {
         mStatusBar = statusBar;
@@ -173,13 +175,40 @@
     public void updateNotificationIcons() {
 
         updateStatusBarIcons();
-        updateIconsForLayout(entry -> entry.expandedIcon, mShelfIcons,
-                NotificationShelf.SHOW_AMBIENT_ICONS, false /* hideDismissed */,
-                false /* hideRepliedMessages */);
+        updateShelfIcons();
+        updateHasShelfIconsWhenFullyDark();
 
         applyNotificationIconsTint();
     }
 
+    private void updateHasShelfIconsWhenFullyDark() {
+        boolean hasIconsWhenFullyDark = false;
+        for (int i = 0; i < mNotificationScrollLayout.getChildCount(); i++) {
+            View view = mNotificationScrollLayout.getChildAt(i);
+            if (view instanceof ExpandableNotificationRow) {
+                NotificationData.Entry ent = ((ExpandableNotificationRow) view).getEntry();
+                if (shouldShowNotificationIcon(ent,
+                        NotificationShelf.SHOW_AMBIENT_ICONS /* showAmbient */,
+                        false /* hideDismissed */,
+                        true /* hideReplied */)) {
+                    hasIconsWhenFullyDark = true;
+                    break;
+                }
+            }
+        }
+        mHasShelfIconsWhenFullyDark = hasIconsWhenFullyDark;
+    }
+
+    public boolean hasShelfIconsWhenFullyDark() {
+        return mHasShelfIconsWhenFullyDark;
+    }
+
+    private void updateShelfIcons() {
+        updateIconsForLayout(entry -> entry.expandedIcon, mShelfIcons,
+                NotificationShelf.SHOW_AMBIENT_ICONS, false /* hideDismissed */,
+                mFullyDark /* hideRepliedMessages */);
+    }
+
     public void updateStatusBarIcons() {
         updateIconsForLayout(entry -> entry.icon, mNotificationIcons,
                 false /* showAmbient */, true /* hideDismissed */, true /* hideRepliedMessages */);
@@ -320,6 +349,11 @@
         v.setDecorColor(mIconTint);
     }
 
+    public void setFullyDark(boolean fullyDark) {
+        mFullyDark = fullyDark;
+        updateShelfIcons();
+    }
+
     public void setDark(boolean dark) {
         mNotificationIcons.setDark(dark, false, 0);
         mShelfIcons.setDark(dark, false, 0);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 2f18aad9..7e6abe9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -47,6 +47,7 @@
 import android.view.ViewGroup;
 import android.view.WindowInsets;
 import android.view.accessibility.AccessibilityManager;
+import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
 
 import com.android.internal.logging.MetricsLogger;
@@ -107,17 +108,20 @@
     private static final AnimationProperties CLOCK_ANIMATION_PROPERTIES = new AnimationProperties()
             .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
     private static final FloatProperty<NotificationPanelView> SET_DARK_AMOUNT_PROPERTY =
-            new FloatProperty<NotificationPanelView>("mDarkAmount") {
+            new FloatProperty<NotificationPanelView>("mInterpolatedDarkAmount") {
+
                 @Override
                 public void setValue(NotificationPanelView object, float value) {
-                    object.setDarkAmount(value);
+                    object.setDarkAmount(value, object.mDarkInterpolator.getInterpolation(value));
                 }
 
                 @Override
                 public Float get(NotificationPanelView object) {
-                    return object.mDarkAmount;
+                    return object.mLinearDarkAmount;
                 }
             };
+
+    private Interpolator mDarkInterpolator;
     private final PowerManager mPowerManager;
     private final AccessibilityManager mAccessibilityManager;
 
@@ -221,6 +225,7 @@
     private boolean mClosingWithAlphaFadeOut;
     private boolean mHeadsUpAnimatingAway;
     private boolean mLaunchingAffordance;
+    private boolean mAffordanceHasPreview;
     private FalsingManager mFalsingManager;
     private String mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE;
 
@@ -236,7 +241,18 @@
     private int mIndicationBottomPadding;
     private int mAmbientIndicationBottomPadding;
     private boolean mIsFullWidth;
-    private float mDarkAmount;
+
+    /**
+     * Current dark amount that follows regular interpolation curve of animation.
+     */
+    private float mInterpolatedDarkAmount;
+
+    /**
+     * Dark amount that animates from 0 to 1 or vice-versa in linear manner, even if the
+     * interpolation curve is different.
+     */
+    private float mLinearDarkAmount;
+
     private float mDarkAmountTarget;
     private boolean mPulsing;
     private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
@@ -391,7 +407,7 @@
                 false);
         addView(mKeyguardBottomArea, index);
         initBottomArea();
-        setDarkAmount(mDarkAmount);
+        setDarkAmount(mLinearDarkAmount, mInterpolatedDarkAmount);
 
         setKeyguardStatusViewVisibility(mStatusBarState, false, false);
         setKeyguardBottomAreaVisibility(mStatusBarState, false);
@@ -505,7 +521,7 @@
                     getExpandedFraction(),
                     totalHeight,
                     mKeyguardStatusView.getHeight(),
-                    mDarkAmount,
+                    mInterpolatedDarkAmount,
                     mStatusBar.isKeyguardCurrentlySecure(),
                     mPulsing,
                     mBouncerTop);
@@ -1916,7 +1932,7 @@
         if (view == null && mQsExpanded) {
             return;
         }
-        if (needsAnimation && mDarkAmount == 0) {
+        if (needsAnimation && mInterpolatedDarkAmount == 0) {
             mAnimateNextPositionUpdate = true;
         }
         ExpandableView firstChildNotGone = mNotificationStackScroller.getFirstChildNotGone();
@@ -2489,7 +2505,7 @@
     }
 
     protected void setVerticalPanelTranslation(float translation) {
-        mNotificationStackScroller.setTranslationX(translation);
+        mNotificationStackScroller.setVerticalPanelTranslation(translation);
         mQsFrame.setTranslationX(translation);
         int size = mVerticalTranslationListener.size();
         for (int i = 0; i < size; i++) {
@@ -2569,6 +2585,7 @@
         } else {
             animate = false;
         }
+        mAffordanceHasPreview = mKeyguardBottomArea.getRightPreview() != null;
         mAffordanceHelper.launchAffordance(animate, getLayoutDirection() == LAYOUT_DIRECTION_RTL);
     }
 
@@ -2614,6 +2631,13 @@
     }
 
     /**
+     * Return true when a bottom affordance is launching an occluded activity with a splash screen.
+     */
+    public boolean isLaunchingAffordanceWithPreview() {
+        return mLaunchingAffordance && mAffordanceHasPreview;
+    }
+
+    /**
      * Whether the camera application can be launched for the camera launch gesture.
      *
      * @param keyguardIsShowing whether keyguard is being shown
@@ -2718,31 +2742,40 @@
         }
         mDarkAmountTarget = darkAmount;
         if (animate) {
+            if (mInterpolatedDarkAmount == 0f || mInterpolatedDarkAmount == 1f) {
+                mDarkInterpolator = dozing
+                        ? Interpolators.FAST_OUT_SLOW_IN
+                        : Interpolators.TOUCH_RESPONSE_REVERSE;
+            }
+            mNotificationStackScroller.notifyDarkAnimationStart(dozing);
             mDarkAnimator = ObjectAnimator.ofFloat(this, SET_DARK_AMOUNT_PROPERTY, darkAmount);
-            mDarkAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
-            mDarkAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_WAKEUP);
+            mDarkAnimator.setInterpolator(Interpolators.LINEAR);
+            mDarkAnimator.setDuration(mNotificationStackScroller.getDarkAnimationDuration(dozing));
             mDarkAnimator.start();
         } else {
-            setDarkAmount(darkAmount);
+            setDarkAmount(darkAmount, darkAmount);
         }
     }
 
-    private void setDarkAmount(float amount) {
-        mDarkAmount = amount;
-        mKeyguardStatusView.setDarkAmount(mDarkAmount);
-        mKeyguardBottomArea.setDarkAmount(mDarkAmount);
+    private void setDarkAmount(float linearAmount, float amount) {
+        mInterpolatedDarkAmount = amount;
+        mLinearDarkAmount = linearAmount;
+        mKeyguardStatusView.setDarkAmount(mInterpolatedDarkAmount);
+        mKeyguardBottomArea.setDarkAmount(mInterpolatedDarkAmount);
         positionClockAndNotifications();
+        mNotificationStackScroller.setDarkAmount(linearAmount, mInterpolatedDarkAmount);
     }
 
     public void setPulsing(boolean pulsing) {
         mPulsing = pulsing;
-        final boolean canAnimatePulse =
-                !DozeParameters.getInstance(mContext).getDisplayNeedsBlanking();
-        if (canAnimatePulse) {
+        DozeParameters dozeParameters = DozeParameters.getInstance(mContext);
+        final boolean animatePulse = !dozeParameters.getDisplayNeedsBlanking()
+                && dozeParameters.getAlwaysOn();
+        if (animatePulse) {
             mAnimateNextPositionUpdate = true;
         }
-        mNotificationStackScroller.setPulsing(pulsing, canAnimatePulse);
-        mKeyguardStatusView.setPulsing(pulsing, canAnimatePulse);
+        mNotificationStackScroller.setPulsing(pulsing, animatePulse);
+        mKeyguardStatusView.setPulsing(pulsing, animatePulse);
     }
 
     public void setAmbientIndicationBottomPadding(int ambientIndicationBottomPadding) {
@@ -2755,7 +2788,7 @@
     public void dozeTimeTick() {
         mKeyguardStatusView.dozeTimeTick();
         mKeyguardBottomArea.dozeTimeTick();
-        if (mDarkAmount > 0) {
+        if (mInterpolatedDarkAmount > 0) {
             positionClockAndNotifications();
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index c4d7e72..6f4a3cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -29,6 +29,7 @@
     private static final boolean SPEW = false;
     private boolean mBouncerShowing;
     private boolean mExpanded;
+    protected float mPanelFraction;
 
     public static final void LOG(String fmt, Object... args) {
         if (!DEBUG) return;
@@ -77,6 +78,14 @@
         if (mPanel != null) mPanel.setImportantForAccessibility(important);
     }
 
+    public float getExpansionFraction() {
+        return mPanelFraction;
+    }
+
+    public boolean isExpanded() {
+        return mExpanded;
+    }
+
     private void updateVisibility() {
         mPanel.setVisibility(mExpanded || mBouncerShowing ? VISIBLE : INVISIBLE);
     }
@@ -131,6 +140,7 @@
         if (SPEW) LOG("panelExpansionChanged: start state=%d", mState);
         PanelView pv = mPanel;
         mExpanded = expanded;
+        mPanelFraction = frac;
         updateVisibility();
         // adjust any other panels that may be partially visible
         if (expanded) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 5477f88..59863ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -59,7 +59,6 @@
     private final PhoneStatusBarTransitions mBarTransitions;
     private ScrimController mScrimController;
     private float mMinFraction;
-    private float mPanelFraction;
     private Runnable mHideExpandedRunnable = new Runnable() {
         @Override
         public void run() {
@@ -269,7 +268,6 @@
     @Override
     public void panelExpansionChanged(float frac, boolean expanded) {
         super.panelExpansionChanged(frac, expanded);
-        mPanelFraction = frac;
         updateScrimFraction();
         if ((frac == 0 || frac == 1) && mBar.getNavigationBarView() != null) {
             mBar.getNavigationBarView().onPanelExpandedChange(expanded);
@@ -331,30 +329,25 @@
         // or letterboxing from the right or left sides.
 
         FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
-        if (mDisplayCutout == null) {
+        if (mDisplayCutout == null || mDisplayCutout.isEmpty()
+                || mLastOrientation != ORIENTATION_PORTRAIT || cornerCutoutMargins == null) {
             lp.leftMargin = 0;
             lp.rightMargin = 0;
             return;
         }
 
-        lp.leftMargin = mDisplayCutout.getSafeInsetLeft();
-        lp.rightMargin = mDisplayCutout.getSafeInsetRight();
+        lp.leftMargin = Math.max(lp.leftMargin, cornerCutoutMargins.first);
+        lp.rightMargin = Math.max(lp.rightMargin, cornerCutoutMargins.second);
 
-        if (cornerCutoutMargins != null) {
-            lp.leftMargin = Math.max(lp.leftMargin, cornerCutoutMargins.first);
-            lp.rightMargin = Math.max(lp.rightMargin, cornerCutoutMargins.second);
-
-            // If we're already inset enough (e.g. on the status bar side), we can have 0 margin
-            WindowInsets insets = getRootWindowInsets();
-            int leftInset = insets.getSystemWindowInsetLeft();
-            int rightInset = insets.getSystemWindowInsetRight();
-            if (lp.leftMargin <= leftInset) {
-                lp.leftMargin = 0;
-            }
-            if (lp.rightMargin <= rightInset) {
-                lp.rightMargin = 0;
-            }
-
+        // If we're already inset enough (e.g. on the status bar side), we can have 0 margin
+        WindowInsets insets = getRootWindowInsets();
+        int leftInset = insets.getSystemWindowInsetLeft();
+        int rightInset = insets.getSystemWindowInsetRight();
+        if (lp.leftMargin <= leftInset) {
+            lp.leftMargin = 0;
+        }
+        if (lp.rightMargin <= rightInset) {
+            lp.rightMargin = 0;
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
index 860b77e..af1d220 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
@@ -22,20 +22,21 @@
 import static com.android.systemui.Interpolators.ALPHA_OUT;
 import static com.android.systemui.OverviewProxyService.DEBUG_OVERVIEW_PROXY;
 import static com.android.systemui.OverviewProxyService.TAG_OPS;
+import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_DEAD_ZONE;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
-import android.animation.ArgbEvaluator;
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Canvas;
-import android.graphics.Color;
 import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.RadialGradient;
 import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
+import android.graphics.Shader;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.util.FloatProperty;
@@ -54,7 +55,6 @@
 import com.android.systemui.shared.recents.IOverviewProxy;
 import com.android.systemui.shared.recents.utilities.Utilities;
 import com.android.systemui.shared.system.NavigationBarCompat;
-import com.android.internal.graphics.ColorUtils;
 
 /**
  * Class to detect gestures on the navigation bar and implement quick scrub.
@@ -65,6 +65,7 @@
     private static final int ANIM_IN_DURATION_MS = 150;
     private static final int ANIM_OUT_DURATION_MS = 134;
     private static final float TRACK_SCALE = 0.95f;
+    private static final float GRADIENT_WIDTH = .75f;
 
     private NavigationBarView mNavigationBarView;
 
@@ -78,23 +79,22 @@
     private boolean mIsRTL;
     private float mTrackAlpha;
     private float mTrackScale = TRACK_SCALE;
-    private int mLightTrackColor;
-    private int mDarkTrackColor;
     private float mDarkIntensity;
+    private RadialGradient mHighlight;
+    private float mHighlightCenter;
     private AnimatorSet mTrackAnimator;
     private ButtonDispatcher mHitTarget;
     private View mCurrentNavigationBarView;
 
     private final Handler mHandler = new Handler();
     private final Rect mTrackRect = new Rect();
-    private final Drawable mTrackDrawable;
     private final OverviewProxyService mOverviewEventSender;
     private final int mTrackThickness;
     private final int mTrackEndPadding;
     private final Context mContext;
     private final Matrix mTransformGlobalMatrix = new Matrix();
     private final Matrix mTransformLocalMatrix = new Matrix();
-    private final ArgbEvaluator mTrackColorEvaluator = new ArgbEvaluator();
+    private final Paint mTrackPaint = new Paint();
 
     private final FloatProperty<QuickStepController> mTrackAlphaProperty =
             new FloatProperty<QuickStepController>("TrackAlpha") {
@@ -155,7 +155,8 @@
         mOverviewEventSender = Dependency.get(OverviewProxyService.class);
         mTrackThickness = res.getDimensionPixelSize(R.dimen.nav_quick_scrub_track_thickness);
         mTrackEndPadding = res.getDimensionPixelSize(R.dimen.nav_quick_scrub_track_edge_padding);
-        mTrackDrawable = context.getDrawable(R.drawable.qs_scrubber_track).mutate();
+        mTrackPaint.setAntiAlias(true);
+        mTrackPaint.setDither(true);
     }
 
     public void setComponents(NavigationBarView navigationBarView) {
@@ -184,6 +185,8 @@
     }
 
     private boolean handleTouchEvent(MotionEvent event) {
+        final boolean deadZoneConsumed =
+                mNavigationBarView.getDownHitTarget() == HIT_TARGET_DEAD_ZONE;
         if (mOverviewEventSender.getProxy() == null || (!mNavigationBarView.isQuickScrubEnabled()
                 && !mNavigationBarView.isQuickStepSwipeUpEnabled())) {
             return false;
@@ -287,6 +290,8 @@
                     } catch (RemoteException e) {
                         Log.e(TAG, "Failed to send progress of quick scrub.", e);
                     }
+                    mHighlightCenter = x;
+                    mNavigationBarView.invalidate();
                 }
                 break;
             }
@@ -302,7 +307,7 @@
                 || action == MotionEvent.ACTION_UP)) {
             proxyMotionEvents(event);
         }
-        return mQuickScrubActive || mQuickStepStarted;
+        return mQuickScrubActive || mQuickStepStarted || deadZoneConsumed;
     }
 
     @Override
@@ -310,18 +315,18 @@
         if (!mNavigationBarView.isQuickScrubEnabled()) {
             return;
         }
-        int color = (int) mTrackColorEvaluator.evaluate(mDarkIntensity, mLightTrackColor,
-                mDarkTrackColor);
-        int colorAlpha = ColorUtils.setAlphaComponent(color,
-                (int) (Color.alpha(color) * mTrackAlpha));
-        mTrackDrawable.setTint(colorAlpha);
+        mTrackPaint.setAlpha(Math.round(255f * mTrackAlpha));
 
         // Scale the track, but apply the inverse scale from the nav bar
+        final float radius = mTrackRect.height() / 2;
         canvas.save();
+        float translate = Utilities.clamp(mHighlightCenter, mTrackRect.left, mTrackRect.right);
+        canvas.translate(translate, 0);
         canvas.scale(mTrackScale / mNavigationBarView.getScaleX(),
                 1f / mNavigationBarView.getScaleY(),
                 mTrackRect.centerX(), mTrackRect.centerY());
-        mTrackDrawable.draw(canvas);
+        canvas.drawRoundRect(mTrackRect.left - translate, mTrackRect.top,
+                mTrackRect.right - translate, mTrackRect.bottom, radius, radius, mTrackPaint);
         canvas.restore();
     }
 
@@ -346,12 +351,20 @@
             x2 = x1 + width - 2 * mTrackEndPadding;
         }
         mTrackRect.set(x1, y1, x2, y2);
-        mTrackDrawable.setBounds(mTrackRect);
+        updateHighlight();
     }
 
     @Override
     public void onDarkIntensityChange(float intensity) {
+        final float oldIntensity = mDarkIntensity;
         mDarkIntensity = intensity;
+
+        // When in quick scrub, invalidate gradient if changing intensity from black to white and
+        // vice-versa
+        if (mNavigationBarView.isQuickScrubEnabled()
+                && Math.round(intensity) != Math.round(oldIntensity)) {
+            updateHighlight();
+        }
         mNavigationBarView.invalidate();
     }
 
@@ -408,10 +421,8 @@
 
     private void startQuickScrub() {
         if (!mQuickScrubActive) {
+            updateHighlight();
             mQuickScrubActive = true;
-            mLightTrackColor = mContext.getColor(R.color.quick_step_track_background_light);
-            mDarkTrackColor = mContext.getColor(R.color.quick_step_track_background_dark);
-
             ObjectAnimator trackAnimator = ObjectAnimator.ofPropertyValuesHolder(this,
                     PropertyValuesHolder.ofFloat(mTrackAlphaProperty, 1f),
                     PropertyValuesHolder.ofFloat(mTrackScaleProperty, 1f));
@@ -424,6 +435,9 @@
             mTrackAnimator.playTogether(trackAnimator, navBarAnimator);
             mTrackAnimator.start();
 
+            // Disable slippery for quick scrub to not cancel outside the nav bar
+            mNavigationBarView.updateSlippery();
+
             try {
                 mOverviewEventSender.getProxy().onQuickScrubStart();
                 if (DEBUG_OVERVIEW_PROXY) {
@@ -483,6 +497,25 @@
         mQuickScrubActive = false;
         mAllowGestureDetection = false;
         mCurrentNavigationBarView = null;
+        updateHighlight();
+    }
+
+    private void updateHighlight() {
+        if (mTrackRect.isEmpty()) {
+            return;
+        }
+        int colorBase, colorGrad;
+        if (mDarkIntensity > 0.5f) {
+            colorBase = mContext.getColor(R.color.quick_step_track_background_background_dark);
+            colorGrad = mContext.getColor(R.color.quick_step_track_background_foreground_dark);
+        } else {
+            colorBase = mContext.getColor(R.color.quick_step_track_background_background_light);
+            colorGrad = mContext.getColor(R.color.quick_step_track_background_foreground_light);
+        }
+        mHighlight = new RadialGradient(0, mTrackRect.height() / 2,
+                mTrackRect.width() * GRADIENT_WIDTH, colorGrad, colorBase,
+                Shader.TileMode.CLAMP);
+        mTrackPaint.setShader(mHighlight);
     }
 
     private boolean proxyMotionEvents(MotionEvent event) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 279ede9..61f0e1cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -29,9 +29,7 @@
 import android.os.Trace;
 import android.util.Log;
 import android.util.MathUtils;
-import android.view.Choreographer;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
@@ -43,12 +41,11 @@
 import com.android.internal.graphics.ColorUtils;
 import com.android.internal.util.function.TriConsumer;
 import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.statusbar.ExpandableNotificationRow;
-import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.statusbar.stack.ViewState;
 import com.android.systemui.util.AlarmTimeout;
@@ -482,21 +479,13 @@
         // Make sure we have the right gradients and their opacities will satisfy GAR.
         if (mNeedsDrawableColorUpdate) {
             mNeedsDrawableColorUpdate = false;
-            final GradientColors currentScrimColors;
-            if (mState == ScrimState.KEYGUARD || mState == ScrimState.BOUNCER_SCRIMMED
-                    || mState == ScrimState.BOUNCER) {
-                // Always animate color changes if we're seeing the keyguard
-                mScrimInFront.setColors(mLockColors, true /* animated */);
-                mScrimBehind.setColors(mLockColors, true /* animated */);
-                currentScrimColors = mLockColors;
-            } else {
-                // Only animate scrim color if the scrim view is actually visible
-                boolean animateScrimInFront = mScrimInFront.getViewAlpha() != 0;
-                boolean animateScrimBehind = mScrimBehind.getViewAlpha() != 0;
-                mScrimInFront.setColors(mSystemColors, animateScrimInFront);
-                mScrimBehind.setColors(mSystemColors, animateScrimBehind);
-                currentScrimColors = mSystemColors;
-            }
+            boolean isKeyguard = mKeyguardUpdateMonitor.isKeyguardVisible() && !mKeyguardOccluded;
+            GradientColors currentScrimColors = isKeyguard ? mLockColors : mSystemColors;
+            // Only animate scrim color if the scrim view is actually visible
+            boolean animateScrimInFront = mScrimInFront.getViewAlpha() != 0 && !mBlankScreen;
+            boolean animateScrimBehind = mScrimBehind.getViewAlpha() != 0 && !mBlankScreen;
+            mScrimInFront.setColors(currentScrimColors, animateScrimInFront);
+            mScrimBehind.setColors(currentScrimColors, animateScrimBehind);
 
             // Calculate minimum scrim opacity for white or black text.
             int textColor = currentScrimColors.supportsDarkText() ? Color.BLACK : Color.WHITE;
@@ -899,6 +888,18 @@
         updateScrims();
     }
 
+    public void setHasBackdrop(boolean hasBackdrop) {
+        for (ScrimState state : ScrimState.values()) {
+            state.setHasBackdrop(hasBackdrop);
+        }
+    }
+
+    public void setLaunchingAffordanceWithPreview(boolean launchingAffordanceWithPreview) {
+        for (ScrimState state : ScrimState.values()) {
+            state.setLaunchingAffordanceWithPreview(launchingAffordanceWithPreview);
+        }
+    }
+
     public interface Callback {
         default void onStart() {
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index 713356b..19015fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -20,7 +20,6 @@
 import android.os.Trace;
 import android.util.MathUtils;
 
-import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.statusbar.stack.StackStateAnimator;
 
@@ -106,8 +105,7 @@
         public void prepare(ScrimState previousState) {
             final boolean alwaysOnEnabled = mDozeParameters.getAlwaysOn();
             mBlankScreen = mDisplayRequiresBlanking;
-            mCurrentBehindAlpha = mWallpaperSupportsAmbientMode
-                    && !mKeyguardUpdateMonitor.hasLockscreenWallpaper() ? 0f : 1f;
+            mCurrentBehindAlpha = mWallpaperSupportsAmbientMode && !mHasBackdrop ? 0f : 1f;
             mCurrentInFrontAlpha = alwaysOnEnabled ? mAodFrontScrimAlpha : 1f;
             mCurrentInFrontTint = Color.BLACK;
             mCurrentBehindTint = Color.BLACK;
@@ -131,8 +129,7 @@
         public void prepare(ScrimState previousState) {
             mCurrentInFrontAlpha = 0;
             mCurrentInFrontTint = Color.BLACK;
-            mCurrentBehindAlpha = mWallpaperSupportsAmbientMode
-                    && !mKeyguardUpdateMonitor.hasLockscreenWallpaper() ? 0f : 1f;
+            mCurrentBehindAlpha = mWallpaperSupportsAmbientMode && !mHasBackdrop ? 0f : 1f;
             mCurrentBehindTint = Color.BLACK;
             mBlankScreen = mDisplayRequiresBlanking;
         }
@@ -147,8 +144,9 @@
             mCurrentBehindAlpha = 0;
             mCurrentInFrontAlpha = 0;
             mAnimationDuration = StatusBar.FADE_KEYGUARD_DURATION;
+            mAnimateChange = !mLaunchingAffordanceWithPreview;
 
-            if (previousState == ScrimState.AOD || previousState == ScrimState.PULSING) {
+            if (previousState == ScrimState.AOD) {
                 // Fade from black to transparent when coming directly from AOD
                 updateScrimColor(mScrimInFront, 1, Color.BLACK);
                 updateScrimColor(mScrimBehind, 1, Color.BLACK);
@@ -178,8 +176,9 @@
     DozeParameters mDozeParameters;
     boolean mDisplayRequiresBlanking;
     boolean mWallpaperSupportsAmbientMode;
-    KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     int mIndex;
+    boolean mHasBackdrop;
+    boolean mLaunchingAffordanceWithPreview;
 
     ScrimState(int index) {
         mIndex = index;
@@ -190,7 +189,6 @@
         mScrimBehind = scrimBehind;
         mDozeParameters = dozeParameters;
         mDisplayRequiresBlanking = dozeParameters.getDisplayNeedsBlanking();
-        mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(scrimInFront.getContext());
     }
 
     public void prepare(ScrimState previousState) {
@@ -253,7 +251,15 @@
         mWallpaperSupportsAmbientMode = wallpaperSupportsAmbientMode;
     }
 
+    public void setLaunchingAffordanceWithPreview(boolean launchingAffordanceWithPreview) {
+        mLaunchingAffordanceWithPreview = launchingAffordanceWithPreview;
+    }
+
     public boolean isLowPowerState() {
         return false;
     }
+
+    public void setHasBackdrop(boolean hasBackdrop) {
+        mHasBackdrop = hasBackdrop;
+    }
 }
\ No newline at end of file
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 7bbeed6..7863465 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -52,6 +52,7 @@
 import android.app.PendingIntent;
 import android.app.StatusBarManager;
 import android.app.TaskStackBuilder;
+import android.app.UiModeManager;
 import android.app.WallpaperColors;
 import android.app.WallpaperInfo;
 import android.app.WallpaperManager;
@@ -326,6 +327,12 @@
     /** If true, the lockscreen will show a distinct wallpaper */
     private static final boolean ENABLE_LOCKSCREEN_WALLPAPER = true;
 
+    /** Whether to force dark theme if Configuration.UI_MODE_NIGHT_YES. */
+    private static final boolean DARK_THEME_IN_NIGHT_MODE = true;
+
+    /** Whether to switch the device into night mode in battery saver. */
+    private static final boolean NIGHT_MODE_IN_BATTERY_SAVER = true;
+
     /**
      * Never let the alpha become zero for surfaces that draw with SRC - otherwise the RenderNode
      * won't draw anything and uninitialized memory will show through
@@ -607,6 +614,12 @@
                         maybeEscalateHeadsUp();
                     }
                 }
+
+                @Override
+                public void onStrongAuthStateChanged(int userId) {
+                    super.onStrongAuthStateChanged(userId);
+                    mEntryManager.updateNotifications();
+                }
             };
 
     private NavigationBarFragment mNavigationBar;
@@ -823,23 +836,31 @@
                 .createNotificationIconAreaController(context, this);
         inflateShelf();
         mNotificationIconAreaController.setupShelf(mNotificationShelf);
+        mStackScroller.setIconAreaController(mNotificationIconAreaController);
         Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mNotificationIconAreaController);
         FragmentHostManager.get(mStatusBarWindow)
                 .addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
                     CollapsedStatusBarFragment statusBarFragment =
                             (CollapsedStatusBarFragment) fragment;
                     statusBarFragment.initNotificationIconArea(mNotificationIconAreaController);
+                    PhoneStatusBarView oldStatusBarView = mStatusBarView;
                     mStatusBarView = (PhoneStatusBarView) fragment.getView();
                     mStatusBarView.setBar(this);
                     mStatusBarView.setPanel(mNotificationPanel);
                     mStatusBarView.setScrimController(mScrimController);
                     mStatusBarView.setBouncerShowing(mBouncerShowing);
+                    if (oldStatusBarView != null) {
+                        float fraction = oldStatusBarView.getExpansionFraction();
+                        boolean expanded = oldStatusBarView.isExpanded();
+                        mStatusBarView.panelExpansionChanged(fraction, expanded);
+                    }
                     if (mHeadsUpAppearanceController != null) {
                         // This view is being recreated, let's destroy the old one
                         mHeadsUpAppearanceController.destroy();
                     }
                     mHeadsUpAppearanceController = new HeadsUpAppearanceController(
                             mNotificationIconAreaController, mHeadsUpManager, mStatusBarWindow);
+                    mStatusBarWindow.setStatusBarView(mStatusBarView);
                     setAreThereNotifications();
                     checkBarModes();
                 }).getFragmentManager()
@@ -917,6 +938,10 @@
                 if (mDozeServiceHost != null) {
                     mDozeServiceHost.firePowerSaveChanged(isPowerSave);
                 }
+                if (NIGHT_MODE_IN_BATTERY_SAVER) {
+                    mContext.getSystemService(UiModeManager.class).setNightMode(
+                        isPowerSave ? UiModeManager.MODE_NIGHT_YES : UiModeManager.MODE_NIGHT_NO);
+                }
             }
 
             @Override
@@ -1645,8 +1670,12 @@
                 && mStatusBarKeyguardViewManager.isOccluded();
 
         final boolean hasArtwork = artworkDrawable != null;
+        mColorExtractor.setHasBackdrop(hasArtwork);
+        if (mScrimController != null) {
+            mScrimController.setHasBackdrop(hasArtwork);
+        }
 
-        if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK) && !mDozing
+        if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK)
                 && (mState != StatusBarState.SHADE || allowWhenShade)
                 && mFingerprintUnlockController.getMode()
                         != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
@@ -1662,7 +1691,6 @@
                     mBackdrop.setAlpha(1f);
                 }
                 mStatusBarWindowManager.setBackdropShowing(true);
-                mColorExtractor.setMediaBackdropVisible(true);
                 metaDataChanged = true;
                 if (DEBUG_MEDIA) {
                     Log.v(TAG, "DEBUG_MEDIA: Fading in album artwork");
@@ -1714,7 +1742,6 @@
                 if (DEBUG_MEDIA) {
                     Log.v(TAG, "DEBUG_MEDIA: Fading out album artwork");
                 }
-                mColorExtractor.setMediaBackdropVisible(false);
                 boolean cannotAnimateDoze = mDozing && !ScrimState.AOD.getAnimateChange();
                 if (mFingerprintUnlockController.getMode()
                         == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
@@ -3112,6 +3139,7 @@
     public void onConfigChanged(Configuration newConfig) {
         updateResources();
         updateDisplaySize(); // populates mDisplayMetrics
+        updateTheme();
 
         if (DEBUG) {
             Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration());
@@ -3846,13 +3874,18 @@
      * Switches theme from light to dark and vice-versa.
      */
     protected void updateTheme() {
-        final boolean inflated = mStackScroller != null;
+        final boolean inflated = mStackScroller != null && mStatusBarWindowManager != null;
 
         // The system wallpaper defines if QS should be light or dark.
         WallpaperColors systemColors = mColorExtractor
                 .getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
-        final boolean useDarkTheme = systemColors != null
+        final boolean wallpaperWantsDarkTheme = systemColors != null
                 && (systemColors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_THEME) != 0;
+        final Configuration config = mContext.getResources().getConfiguration();
+        final boolean nightModeWantsDarkTheme = DARK_THEME_IN_NIGHT_MODE
+                && (config.uiMode & Configuration.UI_MODE_NIGHT_MASK)
+                    == Configuration.UI_MODE_NIGHT_YES;
+        final boolean useDarkTheme = wallpaperWantsDarkTheme || nightModeWantsDarkTheme;
         if (isUsingDarkTheme() != useDarkTheme) {
             mUiOffloadThread.submit(() -> {
                 try {
@@ -4686,7 +4719,6 @@
         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() ==
@@ -4695,7 +4727,7 @@
         }
         if (mDozing != dozing) {
             mDozing = dozing;
-            mKeyguardViewMediator.setAodShowing(mDozing && alwaysOn);
+            mKeyguardViewMediator.setAodShowing(mDozing);
             mStatusBarWindowManager.setDozing(mDozing);
             mStatusBarKeyguardViewManager.setDozing(mDozing);
             if (mAmbientIndicationContainer instanceof DozeReceiver) {
@@ -4720,6 +4752,10 @@
         mScrimController.setExpansionAffectsAlpha(
                 !mFingerprintUnlockController.isFingerprintUnlock());
 
+        boolean launchingAffordanceWithPreview =
+                mNotificationPanel.isLaunchingAffordanceWithPreview();
+        mScrimController.setLaunchingAffordanceWithPreview(launchingAffordanceWithPreview);
+
         if (mBouncerShowing) {
             // Bouncer needs the front scrim when it's on top of an activity,
             // tapping on a notification, editing QS or being dismissed by
@@ -4729,7 +4765,8 @@
                     || mStatusBarKeyguardViewManager.isFullscreenBouncer() ?
                     ScrimState.BOUNCER_SCRIMMED : ScrimState.BOUNCER;
             mScrimController.transitionTo(state);
-        } else if (mLaunchCameraOnScreenTurningOn || isInLaunchTransition()) {
+        } else if (isInLaunchTransition() || mLaunchCameraOnScreenTurningOn
+                || launchingAffordanceWithPreview) {
             mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
         } else if (mBrightnessMirrorVisible) {
             mScrimController.transitionTo(ScrimState.BRIGHTNESS_MIRROR);
@@ -4822,6 +4859,7 @@
                 }
 
                 private void setPulsing(boolean pulsing) {
+                    mKeyguardViewMediator.setPulsing(pulsing);
                     mNotificationPanel.setPulsing(pulsing);
                     mVisualStabilityManager.setPulsing(pulsing);
                     mIgnoreTouchWhilePulsing = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 5001d4f..b49ad46 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -173,7 +173,7 @@
                 || mStatusBar.isFullScreenUserSwitcherState()) {
             mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
         } else if (mShowing && !mDozing) {
-            if (!isWakeAndUnlocking()) {
+            if (!isWakeAndUnlocking() && !mStatusBar.isInLaunchTransition()) {
                 mBouncer.setExpansion(expansion);
             }
             if (expansion != KeyguardBouncer.EXPANSION_HIDDEN && tracking
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index a79a41b..fa763c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -37,6 +37,7 @@
 import android.os.SystemClock;
 import android.util.AttributeSet;
 import android.view.ActionMode;
+import android.view.DisplayCutout;
 import android.view.InputDevice;
 import android.view.InputQueue;
 import android.view.KeyEvent;
@@ -75,6 +76,7 @@
     private NotificationStackScrollLayout mStackScrollLayout;
     private NotificationPanelView mNotificationPanel;
     private View mBrightnessMirror;
+    private PhoneStatusBarView mStatusBarView;
 
     private int mRightInset = 0;
     private int mLeftInset = 0;
@@ -94,6 +96,12 @@
     private boolean mExpandAnimationRunning;
     private boolean mExpandAnimationPending;
 
+    /**
+     * If set to true, the current gesture started below the notch and we need to dispatch touch
+     * events manually as it's outside of the regular view bounds.
+     */
+    private boolean mExpandingBelowNotch;
+
     public StatusBarWindowView(Context context, AttributeSet attrs) {
         super(context, attrs);
         setMotionEventSplittingEnabled(false);
@@ -112,10 +120,21 @@
             boolean paddingChanged = insets.top != getPaddingTop()
                     || insets.bottom != getPaddingBottom();
 
+            int rightCutout = 0;
+            int leftCutout = 0;
+            DisplayCutout displayCutout = getRootWindowInsets().getDisplayCutout();
+            if (displayCutout != null) {
+                leftCutout = displayCutout.getSafeInsetLeft();
+                rightCutout = displayCutout.getSafeInsetRight();
+            }
+
+            int targetLeft = Math.max(insets.left, leftCutout);
+            int targetRight = Math.max(insets.right, rightCutout);
+
             // Super-special right inset handling, because scrims and backdrop need to ignore it.
-            if (insets.right != mRightInset || insets.left != mLeftInset) {
-                mRightInset = insets.right;
-                mLeftInset = insets.left;
+            if (targetRight != mRightInset || targetLeft != mLeftInset) {
+                mRightInset = targetRight;
+                mLeftInset = targetLeft;
                 applyMargins();
             }
             // Drop top inset, and pass through bottom inset.
@@ -186,6 +205,10 @@
         }
     }
 
+    public void setStatusBarView(PhoneStatusBarView statusBarView) {
+        mStatusBarView = statusBarView;
+    }
+
     public void setService(StatusBar service) {
         mService = service;
         setDragDownHelper(new DragDownHelper(getContext(), this, mStackScrollLayout, mService));
@@ -258,7 +281,16 @@
     @Override
     public boolean dispatchTouchEvent(MotionEvent ev) {
         boolean isDown = ev.getActionMasked() == MotionEvent.ACTION_DOWN;
+        boolean isUp = ev.getActionMasked() == MotionEvent.ACTION_UP;
         boolean isCancel = ev.getActionMasked() == MotionEvent.ACTION_CANCEL;
+
+        // Reset manual touch dispatch state here but make sure the UP/CANCEL event still gets
+        // delivered.
+        boolean expandingBelowNotch = mExpandingBelowNotch;
+        if (isUp || isCancel) {
+            mExpandingBelowNotch = false;
+        }
+
         if (!isCancel && mService.shouldIgnoreTouch()) {
             return false;
         }
@@ -291,6 +323,17 @@
             mService.mDozeScrimController.extendPulse();
         }
 
+        // In case we start outside of the view bounds (below the status bar), we need to dispatch
+        // the touch manually as the view system can't accomodate for touches outside of the
+        // regular view bounds.
+        if (isDown && ev.getY() >= mBottom) {
+            mExpandingBelowNotch = true;
+            expandingBelowNotch = true;
+        }
+        if (expandingBelowNotch) {
+            return mStatusBarView.dispatchTouchEvent(ev);
+        }
+
         return super.dispatchTouchEvent(ev);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index 2031b27..59b376f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -113,10 +113,6 @@
 
     @Override
     public void addCallback(Callback callback) {
-        if (callback == null) {
-            Slog.e(TAG, "Attempted to add a null callback.");
-            return;
-        }
         mCallbacks.add(callback);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
index c26568e..e80f483 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
@@ -137,6 +137,10 @@
                 // to look nice
                 customDelay = StackStateAnimator.ANIMATION_DELAY_HEADS_UP_CLICKED
                         + StackStateAnimator.ANIMATION_DELAY_HEADS_UP;
+            } else if (ev.animationType == NotificationStackScrollLayout.AnimationEvent
+                    .ANIMATION_TYPE_PULSE_APPEAR || ev.animationType ==
+                    NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_PULSE_DISAPPEAR) {
+                customDelay = StackStateAnimator.ANIMATION_DURATION_PULSE_APPEAR / 2;
             }
         }
     }
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 9c26c69..ff4f215 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -34,7 +34,6 @@
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
-import android.graphics.Path;
 import android.graphics.PointF;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffXfermode;
@@ -46,11 +45,9 @@
 import android.support.annotation.VisibleForTesting;
 import android.support.v4.graphics.ColorUtils;
 import android.util.AttributeSet;
-import android.util.FloatProperty;
 import android.util.Log;
 import android.util.MathUtils;
 import android.util.Pair;
-import android.util.Property;
 import android.view.ContextThemeWrapper;
 import android.view.InputDevice;
 import android.view.MotionEvent;
@@ -101,6 +98,7 @@
 import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
 import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.phone.NotificationIconAreaController;
 import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.HeadsUpUtil;
@@ -140,7 +138,6 @@
     private boolean mSwipingInProgress;
     private int mCurrentStackHeight = Integer.MAX_VALUE;
     private final Paint mBackgroundPaint = new Paint();
-    private final Path mBackgroundPath = new Path();
     private final boolean mShouldDrawNotificationBackground;
 
     private float mExpandedHeight;
@@ -375,20 +372,22 @@
     private boolean mScrollable;
     private View mForcedScroll;
     private View mNeedingPulseAnimation;
-    private float mDarkAmount = 0f;
-    private static final Property<NotificationStackScrollLayout, Float> DARK_AMOUNT =
-            new FloatProperty<NotificationStackScrollLayout>("darkAmount") {
-                @Override
-                public void setValue(NotificationStackScrollLayout object, float value) {
-                    object.setDarkAmount(value);
-                }
 
-                @Override
-                public Float get(NotificationStackScrollLayout object) {
-                    return object.getDarkAmount();
-                }
-            };
-    private ObjectAnimator mDarkAmountAnimator;
+    /**
+     * @see #setDarkAmount(float, float)
+     */
+    private float mInterpolatedDarkAmount = 0f;
+
+    /**
+     * @see #setDarkAmount(float, float)
+     */
+    private float mLinearDarkAmount = 0f;
+
+    /**
+     * How fast the background scales in the X direction as a factor of the Y expansion.
+     */
+    private float mBackgroundXFactor = 1f;
+
     private boolean mUsingLightTheme;
     private boolean mQsExpanded;
     private boolean mForwardScrollable;
@@ -416,6 +415,10 @@
     private ArrayList<BiConsumer<Float, Float>> mExpandedHeightListeners = new ArrayList<>();
     private int mHeadsUpInset;
     private HeadsUpAppearanceController mHeadsUpAppearanceController;
+    private NotificationIconAreaController mIconAreaController;
+    private float mVerticalPanelTranslation;
+
+    private Interpolator mDarkXInterpolator = Interpolators.FAST_OUT_SLOW_IN;
 
     public NotificationStackScrollLayout(Context context) {
         this(context, null);
@@ -532,10 +535,16 @@
         final int lockScreenRight = getWidth() - mSidePaddings;
         final int lockScreenTop = mCurrentBounds.top;
         final int lockScreenBottom = mCurrentBounds.bottom;
-        final int darkLeft = getWidth() / 2 - mSeparatorWidth / 2;
-        final int darkRight = darkLeft + mSeparatorWidth;
-        final int darkTop = (int) (mRegularTopPadding + mSeparatorThickness / 2f);
-        final int darkBottom = darkTop + mSeparatorThickness;
+        int separatorWidth = 0;
+        int separatorThickness = 0;
+        if (mIconAreaController.hasShelfIconsWhenFullyDark()) {
+            separatorThickness = mSeparatorThickness;
+            separatorWidth = mSeparatorWidth;
+        }
+        final int darkLeft = getWidth() / 2 - separatorWidth / 2;
+        final int darkRight = darkLeft + separatorWidth;
+        final int darkTop = (int) (mRegularTopPadding + separatorThickness / 2f);
+        final int darkBottom = darkTop + separatorThickness;
 
         if (mAmbientState.hasPulsingNotifications()) {
             // No divider, we have a notification icon instead
@@ -545,16 +554,16 @@
                 canvas.drawRect(darkLeft, darkTop, darkRight, darkBottom, mBackgroundPaint);
             }
         } else {
-            float inverseDark = 1 - mDarkAmount;
-            float yProgress = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(inverseDark);
-            float xProgress = Interpolators.FAST_OUT_SLOW_IN
-                    .getInterpolation(inverseDark * 2f);
+            float yProgress = 1 - mInterpolatedDarkAmount;
+            float xProgress = mDarkXInterpolator.getInterpolation(
+                    (1 - mLinearDarkAmount) * mBackgroundXFactor);
 
             mBackgroundAnimationRect.set(
                     (int) MathUtils.lerp(darkLeft, lockScreenLeft, xProgress),
                     (int) MathUtils.lerp(darkTop, lockScreenTop, yProgress),
                     (int) MathUtils.lerp(darkRight, lockScreenRight, xProgress),
                     (int) MathUtils.lerp(darkBottom, lockScreenBottom, yProgress));
+
             if (!mAmbientState.isDark() || mFirstVisibleBackgroundChild != null) {
                 canvas.drawRoundRect(mBackgroundAnimationRect.left, mBackgroundAnimationRect.top,
                         mBackgroundAnimationRect.right, mBackgroundAnimationRect.bottom,
@@ -572,14 +581,15 @@
 
         float alpha =
                 BACKGROUND_ALPHA_DIMMED + (1 - BACKGROUND_ALPHA_DIMMED) * (1.0f - mDimAmount);
-        alpha *= 1f - mDarkAmount;
+        alpha *= 1f - mInterpolatedDarkAmount;
         // We need to manually blend in the background color.
         int scrimColor = mScrimController.getBackgroundColor();
         int awakeColor = ColorUtils.blendARGB(scrimColor, mBgColor, alpha);
 
         // Interpolate between semi-transparent notification panel background color
         // and white AOD separator.
-        float colorInterpolation = Interpolators.DECELERATE_QUINT.getInterpolation(mDarkAmount);
+        float colorInterpolation = Interpolators.DECELERATE_QUINT.getInterpolation(
+                mInterpolatedDarkAmount);
         int color = ColorUtils.blendARGB(awakeColor, Color.WHITE, colorInterpolation);
 
         if (mCachedBackgroundColor != color) {
@@ -723,7 +733,8 @@
     }
 
     private void updateAlgorithmHeightAndPadding() {
-        mTopPadding = (int) MathUtils.lerp(mRegularTopPadding, mDarkTopPadding, mDarkAmount);
+        mTopPadding = (int) MathUtils.lerp(mRegularTopPadding, mDarkTopPadding,
+                mInterpolatedDarkAmount);
         mAmbientState.setLayoutHeight(getLayoutHeight());
         updateAlgorithmLayoutMinHeight();
         mAmbientState.setTopPadding(mTopPadding);
@@ -948,7 +959,7 @@
     }
 
     public void updateClipping() {
-        boolean animatingClipping = mDarkAmount > 0 && mDarkAmount < 1;
+        boolean animatingClipping = mInterpolatedDarkAmount > 0 && mInterpolatedDarkAmount < 1;
         boolean clipped = mRequestedClipBounds != null && !mInHeadsUpPinnedMode
                 && !mHeadsUpAnimatingAway;
         if (mIsClipped != clipped) {
@@ -2041,11 +2052,9 @@
     }
 
     private int getScrollRange() {
-        int contentHeight = getContentHeight();
-        int scrollRange = Math.max(0, contentHeight - mMaxLayoutHeight);
+        int scrollRange = Math.max(0, mContentHeight - mMaxLayoutHeight);
         int imeInset = getImeInset();
-        scrollRange += Math.min(imeInset, Math.max(0,
-                getContentHeight() - (getHeight() - imeInset)));
+        scrollRange += Math.min(imeInset, Math.max(0, mContentHeight - (getHeight() - imeInset)));
         return scrollRange;
     }
 
@@ -2146,10 +2155,6 @@
         return count;
     }
 
-    public int getContentHeight() {
-        return mContentHeight;
-    }
-
     private void updateContentHeight() {
         int height = 0;
         float previousPaddingRequest = mPaddingBetweenElements;
@@ -2213,7 +2218,11 @@
             }
         }
         mIntrinsicContentHeight = height;
-        mContentHeight = height + mTopPadding + mBottomMargin;
+
+        // We don't want to use the toppadding since that might be interpolated and we want
+        // to take the final value of the animation.
+        int topPadding = mAmbientState.isFullyDark() ? mDarkTopPadding : mRegularTopPadding;
+        mContentHeight = height + topPadding + mBottomMargin;
         updateScrollability();
         clampScrollPosition();
         mAmbientState.setLayoutMaxHeight(mContentHeight);
@@ -2410,7 +2419,7 @@
             return;
         }
 
-        final boolean awake = mDarkAmount != 0 || mAmbientState.isDark();
+        final boolean awake = mInterpolatedDarkAmount != 0 || mAmbientState.isDark();
         mScrimController.setExcludedBackgroundArea(
                 mFadingOut || mParentNotFullyVisible || awake || mIsClipped ? null
                         : mCurrentBounds);
@@ -3403,7 +3412,6 @@
                             .animateY(mShelf));
             ev.darkAnimationOriginIndex = mDarkAnimationOriginIndex;
             mAnimationEvents.add(ev);
-            startDarkAmountAnimation();
         }
         mDarkNeedsAnimation = false;
     }
@@ -3979,11 +3987,8 @@
         if (animate && mAnimationsEnabled) {
             mDarkNeedsAnimation = true;
             mDarkAnimationOriginIndex = findDarkAnimationOriginIndex(touchWakeUpScreenLocation);
-            mNeedsAnimation =  true;
+            mNeedsAnimation = true;
         } else {
-            if (mDarkAmountAnimator != null) {
-                mDarkAmountAnimator.cancel();
-            }
             setDarkAmount(dark ? 1f : 0f);
             updateBackground();
         }
@@ -3993,8 +3998,13 @@
         notifyHeightChangeListener(mShelf);
     }
 
-    private void updateAntiBurnInTranslation() {
-        setTranslationX(mAntiBurnInOffsetX * mDarkAmount);
+    private void updatePanelTranslation() {
+        setTranslationX(mVerticalPanelTranslation + mAntiBurnInOffsetX * mInterpolatedDarkAmount);
+    }
+
+    public void setVerticalPanelTranslation(float verticalPanelTranslation) {
+        mVerticalPanelTranslation = verticalPanelTranslation;
+        updatePanelTranslation();
     }
 
     /**
@@ -4008,42 +4018,57 @@
     }
 
     private void setDarkAmount(float darkAmount) {
-        mDarkAmount = darkAmount;
+        setDarkAmount(darkAmount, darkAmount);
+    }
+
+    /**
+     * Sets the current dark amount.
+     *
+     * @param linearDarkAmount The dark amount that follows linear interpoloation in the animation,
+     *                         i.e. animates from 0 to 1 or vice-versa in a linear manner.
+     * @param interpolatedDarkAmount The dark amount that follows the actual interpolation of the
+     *                                animation curve.
+     */
+    public void setDarkAmount(float linearDarkAmount, float interpolatedDarkAmount) {
+        mLinearDarkAmount = linearDarkAmount;
+        mInterpolatedDarkAmount = interpolatedDarkAmount;
         boolean wasFullyDark = mAmbientState.isFullyDark();
-        mAmbientState.setDarkAmount(darkAmount);
-        if (mAmbientState.isFullyDark() != wasFullyDark) {
+        mAmbientState.setDarkAmount(interpolatedDarkAmount);
+        boolean nowFullyDark = mAmbientState.isFullyDark();
+        if (nowFullyDark != wasFullyDark) {
             updateContentHeight();
             DozeParameters dozeParameters = DozeParameters.getInstance(mContext);
-            if (mAmbientState.isFullyDark() && dozeParameters.shouldControlScreenOff()) {
+            if (nowFullyDark && dozeParameters.shouldControlScreenOff()) {
                 mShelf.fadeInTranslating();
             }
+            if (mIconAreaController != null) {
+                mIconAreaController.setFullyDark(nowFullyDark);
+            }
         }
         updateAlgorithmHeightAndPadding();
         updateBackgroundDimming();
-        updateAntiBurnInTranslation();
+        updatePanelTranslation();
         requestChildrenUpdate();
     }
 
-    public float getDarkAmount() {
-        return mDarkAmount;
+    public void notifyDarkAnimationStart(boolean dark) {
+        // We only swap the scaling factor if we're fully dark or fully awake to avoid
+        // interpolation issues when playing with the power button.
+        if (mInterpolatedDarkAmount == 0 || mInterpolatedDarkAmount == 1) {
+            mBackgroundXFactor = dark ? 1.8f : 1.5f;
+            mDarkXInterpolator = dark
+                    ? Interpolators.FAST_OUT_SLOW_IN_REVERSE
+                    : Interpolators.FAST_OUT_SLOW_IN;
+        }
     }
 
-    private void startDarkAmountAnimation() {
-        ObjectAnimator darkAnimator = ObjectAnimator.ofFloat(this, DARK_AMOUNT, mDarkAmount,
-                mAmbientState.isDark() ? 1f : 0);
-        darkAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_WAKEUP);
-        darkAnimator.setInterpolator(Interpolators.ALPHA_IN);
-        darkAnimator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                mDarkAmountAnimator = null;
-            }
-        });
-        if (mDarkAmountAnimator != null) {
-            mDarkAmountAnimator.cancel();
+    public long getDarkAnimationDuration(boolean dark) {
+        long duration = StackStateAnimator.ANIMATION_DURATION_WAKEUP;
+        // Longer animation when sleeping with more than 1 notification
+        if (dark && getNotGoneChildCount() > 2) {
+            duration *= 1.2f;
         }
-        mDarkAmountAnimator = darkAnimator;
-        mDarkAmountAnimator.start();
+        return duration;
     }
 
     private int findDarkAnimationOriginIndex(@Nullable PointF screenLocation) {
@@ -4572,7 +4597,7 @@
 
     public void setAntiBurnInOffsetX(int antiBurnInOffsetX) {
         mAntiBurnInOffsetX = antiBurnInOffsetX;
-        updateAntiBurnInTranslation();
+        updatePanelTranslation();
     }
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -4618,6 +4643,10 @@
         mHeadsUpAppearanceController = headsUpAppearanceController;
     }
 
+    public void setIconAreaController(NotificationIconAreaController controller) {
+        mIconAreaController = controller;
+    }
+
     /**
      * A listener that is notified when the empty space below the notifications is clicked on
      */
@@ -5031,11 +5060,13 @@
                 // ANIMATION_TYPE_PULSE_APPEAR
                 new AnimationFilter()
                         .animateAlpha()
+                        .hasDelays()
                         .animateY(),
 
                 // ANIMATION_TYPE_PULSE_DISAPPEAR
                 new AnimationFilter()
                         .animateAlpha()
+                        .hasDelays()
                         .animateY(),
         };
 
@@ -5099,10 +5130,10 @@
                 StackStateAnimator.ANIMATION_DURATION_STANDARD,
 
                 // ANIMATION_TYPE_PULSE_APPEAR
-                KeyguardSliceView.DEFAULT_ANIM_DURATION,
+                StackStateAnimator.ANIMATION_DURATION_PULSE_APPEAR,
 
                 // ANIMATION_TYPE_PULSE_DISAPPEAR
-                KeyguardSliceView.DEFAULT_ANIM_DURATION / 2,
+                StackStateAnimator.ANIMATION_DURATION_PULSE_APPEAR / 2,
         };
 
         static final int ANIMATION_TYPE_ADD = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index a75d40f..b83a09d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -24,6 +24,7 @@
 import android.view.ViewGroup;
 import android.view.animation.Interpolator;
 
+import com.android.keyguard.KeyguardSliceView;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
@@ -51,6 +52,8 @@
             = (int) (ANIMATION_DURATION_HEADS_UP_APPEAR
                     * HeadsUpAppearInterpolator.getFractionUntilOvershoot());
     public static final int ANIMATION_DURATION_HEADS_UP_DISAPPEAR = 300;
+    public static final int ANIMATION_DURATION_PULSE_APPEAR =
+            KeyguardSliceView.DEFAULT_ANIM_DURATION;
     public static final int ANIMATION_DURATION_BLOCKING_HELPER_FADE = 240;
     public static final int ANIMATION_DELAY_PER_ELEMENT_INTERRUPTING = 80;
     public static final int ANIMATION_DELAY_PER_ELEMENT_MANUAL = 32;
@@ -430,15 +433,26 @@
             } else if (event.animationType == NotificationStackScrollLayout
                     .AnimationEvent.ANIMATION_TYPE_PULSE_APPEAR) {
                 ExpandableViewState viewState = finalState.getViewStateForView(changingView);
-                mTmpState.copyFrom(viewState);
-                mTmpState.yTranslation += mPulsingAppearingTranslation;
-                mTmpState.alpha = 0;
-                mTmpState.applyToView(changingView);
+                if (viewState != null) {
+                    mTmpState.copyFrom(viewState);
+                    mTmpState.yTranslation += mPulsingAppearingTranslation;
+                    mTmpState.alpha = 0;
+                    mTmpState.applyToView(changingView);
+                }
             } else if (event.animationType == NotificationStackScrollLayout
                     .AnimationEvent.ANIMATION_TYPE_PULSE_DISAPPEAR) {
                 ExpandableViewState viewState = finalState.getViewStateForView(changingView);
-                viewState.yTranslation += mPulsingAppearingTranslation;
-                viewState.alpha = 0;
+                if (viewState != null) {
+                    viewState.alpha = 0;
+                    // We want to animate the alpha away before the view starts translating,
+                    // otherwise everything will overlap and look xtra ugly.
+                    float originalYTranslation = viewState.yTranslation;
+                    viewState.yTranslation = changingView.getTranslationY();
+                    mAnimationFilter.animateAlpha = true;
+                    mAnimationProperties.duration = ANIMATION_DURATION_PULSE_APPEAR / 2;
+                    viewState.animateTo(changingView, mAnimationProperties);
+                    viewState.yTranslation = originalYTranslation;
+                }
             } else if (event.animationType == NotificationStackScrollLayout
                     .AnimationEvent.ANIMATION_TYPE_HEADS_UP_APPEAR) {
                 // This item is added, initialize it's properties.
diff --git a/packages/SystemUI/src/com/android/systemui/util/Utils.java b/packages/SystemUI/src/com/android/systemui/util/Utils.java
index eca6127..6812410 100644
--- a/packages/SystemUI/src/com/android/systemui/util/Utils.java
+++ b/packages/SystemUI/src/com/android/systemui/util/Utils.java
@@ -26,11 +26,14 @@
 
     /**
      * Allows lambda iteration over a list. It is done in reverse order so it is safe
-     * to add or remove items during the iteration.
+     * to add or remove items during the iteration.  Skips over null items.
      */
     public static <T> void safeForeach(List<T> list, Consumer<T> c) {
         for (int i = list.size() - 1; i >= 0; i--) {
-            c.accept(list.get(i));
+            T item = list.get(i);
+            if (item != null) {
+                c.accept(item);
+            }
         }
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java b/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java
index 8153953..13dc36d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java
@@ -93,7 +93,7 @@
         SysuiColorExtractor extractor = getTestableExtractor(colors);
         simulateEvent(extractor);
         extractor.setWallpaperVisible(true);
-        extractor.setMediaBackdropVisible(true);
+        extractor.setHasBackdrop(true);
 
         ColorExtractor.GradientColors fallbackColors = extractor.getFallbackColors();
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationTest.java
index 64507be..bb67d6e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationTest.java
@@ -16,7 +16,7 @@
 
 package com.android.systemui.doze;
 
-import static org.junit.Assert.assertTrue;
+import static junit.framework.TestCase.assertEquals;
 
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -42,14 +42,15 @@
     }
 
     @Test
-    public void alwaysOn_onByDefault() throws Exception {
+    public void alwaysOn_followsConfigByDefault() throws Exception {
         if (!mDozeConfig.alwaysOnAvailable()) {
             return;
         }
 
         Settings.Secure.putString(mContext.getContentResolver(), Settings.Secure.DOZE_ALWAYS_ON,
                 null);
-
-        assertTrue(mDozeConfig.alwaysOnEnabled(UserHandle.USER_CURRENT));
+        boolean defaultValue = mContext.getResources()
+                .getBoolean(com.android.internal.R.bool.config_dozeAlwaysOnEnabled);
+        assertEquals(mDozeConfig.alwaysOnEnabled(UserHandle.USER_CURRENT), defaultValue);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
index d19715d..5ecf0c0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
@@ -24,6 +24,7 @@
 
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -66,6 +67,8 @@
     public static final long BELOW_HYBRID_THRESHOLD = TimeUnit.HOURS.toMillis(2);
     public static final long ABOVE_HYBRID_THRESHOLD = TimeUnit.HOURS.toMillis(4);
     private static final long ABOVE_CHARGE_CYCLE_THRESHOLD = Duration.ofHours(8).toMillis();
+    private static final int OLD_BATTERY_LEVEL_NINE = 9;
+    private static final int OLD_BATTERY_LEVEL_10 = 10;
     private HardwarePropertiesManager mHardProps;
     private WarningsUI mMockWarnings;
     private PowerUI mPowerUI;
@@ -307,8 +310,8 @@
                 .thenReturn(new Estimate(BELOW_HYBRID_THRESHOLD, true));
         mPowerUI.mBatteryStatus = BatteryManager.BATTERY_HEALTH_GOOD;
 
-        mPowerUI.maybeShowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
-                ABOVE_WARNING_BUCKET);
+        mPowerUI.maybeShowBatteryWarning(OLD_BATTERY_LEVEL_NINE, UNPLUGGED, UNPLUGGED,
+                ABOVE_WARNING_BUCKET, ABOVE_WARNING_BUCKET);
 
         // reduce battery level to handle time based trigger -> level trigger interactions
         mPowerUI.mBatteryLevel = 10;
@@ -449,6 +452,33 @@
         verify(mMockWarnings, never()).dismissLowBatteryWarning();
     }
 
+    @Test
+    public void testMaybeShowBatteryWarning_onlyQueriesEstimateOnBatteryLevelChangeOrNull() {
+        mPowerUI.start();
+        Estimate estimate = new Estimate(BELOW_HYBRID_THRESHOLD, true);
+        when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true);
+        when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS);
+        when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS);
+        when(mEnhancedEstimates.getEstimate()).thenReturn(estimate);
+        mPowerUI.mBatteryStatus = BatteryManager.BATTERY_HEALTH_GOOD;
+
+        // we expect that the first time it will query even if the level is the same
+        mPowerUI.mBatteryLevel = 9;
+        mPowerUI.maybeShowBatteryWarning(OLD_BATTERY_LEVEL_NINE, UNPLUGGED, UNPLUGGED,
+                ABOVE_WARNING_BUCKET, ABOVE_WARNING_BUCKET);
+        verify(mEnhancedEstimates, times(1)).getEstimate();
+
+        // We should NOT query again if the battery level hasn't changed
+        mPowerUI.maybeShowBatteryWarning(OLD_BATTERY_LEVEL_NINE, UNPLUGGED, UNPLUGGED,
+                ABOVE_WARNING_BUCKET, ABOVE_WARNING_BUCKET);
+        verify(mEnhancedEstimates, times(1)).getEstimate();
+
+        // Battery level has changed, so we should query again
+        mPowerUI.maybeShowBatteryWarning(OLD_BATTERY_LEVEL_10, UNPLUGGED, UNPLUGGED,
+                ABOVE_WARNING_BUCKET, ABOVE_WARNING_BUCKET);
+        verify(mEnhancedEstimates, times(2)).getEstimate();
+    }
+
     private void setCurrentTemp(float temp) {
         when(mHardProps.getDeviceTemperatures(DEVICE_TEMPERATURE_SKIN, TEMPERATURE_CURRENT))
                 .thenReturn(new float[] { temp });
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index e95702c..89d562a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -44,7 +44,6 @@
 
 import com.android.internal.colorextraction.ColorExtractor.GradientColors;
 import com.android.internal.util.function.TriConsumer;
-import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.util.wakelock.WakeLock;
@@ -94,6 +93,7 @@
                     mScrimInFrontColor = scrimInFrontColor;
                 },
                 visible -> mScrimVisibility = visible, mDozeParamenters, mAlarmManager);
+        mScrimController.setHasBackdrop(false);
     }
 
     @Test
@@ -140,12 +140,7 @@
 
     @Test
     public void transitionToAod_withAodWallpaperAndLockScreenWallpaper() {
-        ScrimState.AOD.mKeyguardUpdateMonitor = new KeyguardUpdateMonitor(getContext()) {
-            @Override
-            public boolean hasLockscreenWallpaper() {
-                return true;
-            }
-        };
+        mScrimController.setHasBackdrop(true);
         mScrimController.setWallpaperSupportsAmbientMode(true);
         mScrimController.transitionTo(ScrimState.AOD);
         mScrimController.finishAnimationsImmediately();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 85135ac..94ab9d2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -177,6 +177,14 @@
         verify(mBouncer, never()).setExpansion(anyFloat());
     }
 
+    @Test
+    public void onPanelExpansionChanged_neverTranslatesBouncerWhenLaunchingApp() {
+        when(mStatusBar.isInLaunchTransition()).thenReturn(true);
+        mStatusBarKeyguardViewManager.onPanelExpansionChanged(KeyguardBouncer.EXPANSION_VISIBLE,
+                false /* tracking */);
+        verify(mBouncer, never()).setExpansion(anyFloat());
+    }
+
     private class TestableStatusBarKeyguardViewManager extends StatusBarKeyguardViewManager {
 
         public TestableStatusBarKeyguardViewManager(Context context,
diff --git a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/config.xml
index 80d8066..9254b4d 100644
--- a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/config.xml
+++ b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/config.xml
@@ -37,6 +37,8 @@
         @right
     </string>
 
+    <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">@*android:string/config_mainBuiltInDisplayCutout</string>
+
     <!-- Whether the display cutout region of the main built-in display should be forced to
          black in software (to avoid aliasing or emulate a cutout that is not physically existent).
      -->
diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml
index ca261f9..80c997a 100644
--- a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml
+++ b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml
@@ -49,6 +49,8 @@
         @dp
     </string>
 
+    <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">@*android:string/config_mainBuiltInDisplayCutout</string>
+
     <!-- Whether the display cutout region of the main built-in display should be forced to
          black in software (to avoid aliasing or emulate a cutout that is not physically existent).
      -->
diff --git a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml
index c22b2e7..6fb3c7f 100644
--- a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml
+++ b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml
@@ -40,6 +40,8 @@
         @dp
     </string>
 
+    <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">@*android:string/config_mainBuiltInDisplayCutout</string>
+
     <!-- Whether the display cutout region of the main built-in display should be forced to
          black in software (to avoid aliasing or emulate a cutout that is not physically existent).
      -->
diff --git a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml
index 401e092..7c29ffb 100644
--- a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml
+++ b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml
@@ -40,6 +40,8 @@
         @dp
     </string>
 
+    <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">@*android:string/config_mainBuiltInDisplayCutout</string>
+
     <!-- Whether the display cutout region of the main built-in display should be forced to
          black in software (to avoid aliasing or emulate a cutout that is not physically existent).
      -->
diff --git a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml
index f328b83..5fb8b9e 100644
--- a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml
+++ b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml
@@ -40,6 +40,8 @@
         @dp
     </string>
 
+    <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">@*android:string/config_mainBuiltInDisplayCutout</string>
+
     <!-- Whether the display cutout region of the main built-in display should be forced to
          black in software (to avoid aliasing or emulate a cutout that is not physically existent).
      -->
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 4328d94..143fa86 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -6116,7 +6116,21 @@
     // OS: P
     FIELD_AUTOFILL_SESSION_ID = 1456;
 
+    // NOTIFICATION_SINCE_INTERRUPTION_MILLIS added to P
+    // NOTIFICATION_INTERRUPTION added to P
+
     // ---- End P Constants, all P constants go above this line ----
+
+    // Time since this notification last interrupted (visibly or audible) the user
+    NOTIFICATION_SINCE_INTERRUPTION_MILLIS = 1500;
+
+    // OPEN: Notification interrupted the user, either audibly or visually.
+    //   Tagged data: NOTIFICATION_SINCE_INTERRUPTION_MILLIS
+    // CATEGORY: NOTIFICATION
+    NOTIFICATION_INTERRUPTION = 1501;
+
+    // ---- End Q Constants, all Q constants go above this line ----
+
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
   }
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index a9a14ca..fba639c 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -212,6 +212,10 @@
     // Package: android
     NOTE_AUTO_SAVER_SUGGESTION = 49;
 
+    // Notify the user that their softap config preference has changed.
+    // Package: android
+    NOTE_SOFTAP_CONFIG_CHANGED = 50;
+
     // ADD_NEW_IDS_ABOVE_THIS_LINE
     // Legacy IDs with arbitrary values appear below
     // Legacy IDs existed as stable non-conflicting constants prior to the O release
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index 5a25f48..f5b29e9 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -16,8 +16,16 @@
 
 package com.android.server;
 
+import static android.app.ActivityManager.UID_OBSERVER_ACTIVE;
+import static android.app.ActivityManager.UID_OBSERVER_GONE;
+
+import android.annotation.IntDef;
 import android.annotation.Nullable;
 
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
+import android.app.IActivityManager;
+import android.app.IUidObserver;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -26,24 +34,29 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.MediaStore;
+import android.provider.Settings;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.OsConstants;
-import android.system.StructStat;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.ResolverActivity;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.DumpUtils;
+import com.android.internal.util.function.pooled.PooledLambda;
 
 import dalvik.system.DexFile;
 import dalvik.system.VMRuntime;
@@ -53,12 +66,12 @@
 import java.io.InputStream;
 import java.io.DataInputStream;
 import java.io.IOException;
-import java.io.EOFException;
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 
 import java.util.zip.ZipFile;
-import java.util.zip.ZipException;
 import java.util.zip.ZipEntry;
 
 /**
@@ -70,16 +83,50 @@
 public final class PinnerService extends SystemService {
     private static final boolean DEBUG = false;
     private static final String TAG = "PinnerService";
-    private static final int MAX_CAMERA_PIN_SIZE = 80 * (1 << 20); //80MB max
+
     private static final String PIN_META_FILENAME = "pinlist.meta";
     private static final int PAGE_SIZE = (int) Os.sysconf(OsConstants._SC_PAGESIZE);
+    private static final int MATCH_FLAGS = PackageManager.MATCH_DEFAULT_ONLY
+            | PackageManager.MATCH_DIRECT_BOOT_AWARE
+            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+
+    private static final int KEY_CAMERA = 0;
+    private static final int KEY_HOME = 1;
+
+    private static final int MAX_CAMERA_PIN_SIZE = 80 * (1 << 20); // 80MB max for camera app.
+    private static final int MAX_HOME_PIN_SIZE = 6 * (1 << 20); // 6MB max for home app.
+
+    @IntDef({KEY_CAMERA, KEY_HOME})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface AppKey {}
 
     private final Context mContext;
-    private final boolean mShouldPinCamera;
+    private final ActivityManagerInternal mAmInternal;
+    private final IActivityManager mAm;
 
-    /* These lists protected by PinnerService monitor lock */
-    private final ArrayList<PinnedFile> mPinnedFiles = new ArrayList<PinnedFile>();
-    private final ArrayList<PinnedFile> mPinnedCameraFiles = new ArrayList<PinnedFile>();
+    /** The list of the statically pinned files. */
+    @GuardedBy("this")
+    private final ArrayList<PinnedFile> mPinnedFiles = new ArrayList<>();
+
+    /** The list of the pinned apps. This is a map from {@link AppKey} to a pinned app. */
+    @GuardedBy("this")
+    private final ArrayMap<Integer, PinnedApp> mPinnedApps = new ArrayMap<>();
+
+    /**
+     * The list of the pinned apps that need to be repinned as soon as the all processes of a given
+     * uid are no longer active. Note that with background dex opt, the new dex/vdex files are only
+     * loaded into the processes once it restarts. So in case background dex opt recompiled these
+     * files, we still need to keep the old ones pinned until the processes restart.
+     * <p>
+     * This is a map from uid to {@link AppKey}
+     */
+    @GuardedBy("this")
+    private final ArrayMap<Integer, Integer> mPendingRepin = new ArrayMap<>();
+
+    /**
+     * A set of {@link AppKey} that are configured to be pinned.
+     */
+    private final ArraySet<Integer> mPinKeys = new ArraySet<>();
 
     private BinderService mBinderService;
     private PinnerHandler mPinnerHandler = null;
@@ -87,13 +134,13 @@
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-          // If this user's camera app has been updated, update pinned files accordingly.
-          if (intent.getAction() == Intent.ACTION_PACKAGE_REPLACED) {
+          // If an app has updated, update pinned files accordingly.
+          if (Intent.ACTION_PACKAGE_REPLACED.equals(intent.getAction())) {
                 Uri packageUri = intent.getData();
                 String packageName = packageUri.getSchemeSpecificPart();
                 ArraySet<String> updatedPackages = new ArraySet<>();
                 updatedPackages.add(packageName);
-                update(updatedPackages);
+                update(updatedPackages, true /* force */);
             }
         }
     };
@@ -102,14 +149,28 @@
         super(context);
 
         mContext = context;
-        mShouldPinCamera = context.getResources().getBoolean(
+        boolean shouldPinCamera = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_pinnerCameraApp);
+        boolean shouldPinHome = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_pinnerHomeApp);
+        if (shouldPinCamera) {
+            mPinKeys.add(KEY_CAMERA);
+        }
+        if (shouldPinHome) {
+            mPinKeys.add(KEY_HOME);
+        }
         mPinnerHandler = new PinnerHandler(BackgroundThread.get().getLooper());
 
+        mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
+        mAm = ActivityManager.getService();
+
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
         filter.addDataScheme("package");
         mContext.registerReceiver(mBroadcastReceiver, filter);
+
+        registerUidListener();
+        registerUserSetupCompleteListener();
     }
 
     @Override
@@ -122,32 +183,39 @@
         publishLocalService(PinnerService.class, this);
 
         mPinnerHandler.obtainMessage(PinnerHandler.PIN_ONSTART_MSG).sendToTarget();
-        mPinnerHandler.obtainMessage(PinnerHandler.PIN_CAMERA_MSG, UserHandle.USER_SYSTEM, 0)
-                .sendToTarget();
+        sendPinAppsMessage(UserHandle.USER_SYSTEM);
     }
 
     /**
-     * Pin camera on user switch.
-     * If more than one user is using the device
-     * each user may set a different preference for the camera app.
-     * Make sure that user's preference is pinned into memory.
+     * Repin apps on user switch.
+     * <p>
+     * If more than one user is using the device each user may set a different preference for the
+     * individual apps. Make sure that user's preference is pinned into memory.
      */
     @Override
     public void onSwitchUser(int userHandle) {
-        mPinnerHandler.obtainMessage(PinnerHandler.PIN_CAMERA_MSG, userHandle, 0).sendToTarget();
+        sendPinAppsMessage(userHandle);
+    }
+
+    @Override
+    public void onUnlockUser(int userHandle) {
+        sendPinAppsMessage(userHandle);
     }
 
     /**
      * Update the currently pinned files.
-     * Specifically, this only updates camera pinning.
+     * Specifically, this only updates pinning for the apps that need to be pinned.
      * The other files pinned in onStart will not need to be updated.
      */
-    public void update(ArraySet<String> updatedPackages) {
-        ApplicationInfo cameraInfo = getCameraInfo(UserHandle.USER_SYSTEM);
-        if (cameraInfo != null && updatedPackages.contains(cameraInfo.packageName)) {
-            Slog.i(TAG, "Updating pinned files.");
-            mPinnerHandler.obtainMessage(PinnerHandler.PIN_CAMERA_MSG, UserHandle.USER_SYSTEM, 0)
-                    .sendToTarget();
+    public void update(ArraySet<String> updatedPackages, boolean force) {
+        int currentUser = ActivityManager.getCurrentUser();
+        for (int i = mPinKeys.size() - 1; i >= 0; i--) {
+            int key = mPinKeys.valueAt(i);
+            ApplicationInfo info = getInfoForKey(key, currentUser);
+            if (info != null && updatedPackages.contains(info.packageName)) {
+                Slog.i(TAG, "Updating pinned files for " + info.packageName + " force=" + force);
+                sendPinAppMessage(key, currentUser, force);
+            }
         }
     }
 
@@ -175,24 +243,99 @@
     }
 
     /**
-     * Handler for camera pinning message
+     * Registers a listener to repin the home app when user setup is complete, as the home intent
+     * initially resolves to setup wizard, but once setup is complete, it will resolve to the
+     * regular home app.
      */
-    private void handlePinCamera(int userHandle) {
-        if (!mShouldPinCamera) return;
-        if (!pinCamera(userHandle)) {
-            if (DEBUG) {
-                Slog.v(TAG, "Failed to pin camera.");
+    private void registerUserSetupCompleteListener() {
+        Uri userSetupCompleteUri = Settings.Secure.getUriFor(
+                Settings.Secure.USER_SETUP_COMPLETE);
+        mContext.getContentResolver().registerContentObserver(userSetupCompleteUri,
+                false, new ContentObserver(null) {
+                    @Override
+                    public void onChange(boolean selfChange, Uri uri) {
+                        if (userSetupCompleteUri.equals(uri)) {
+                            sendPinAppMessage(KEY_HOME, ActivityManager.getCurrentUser(),
+                                    true /* force */);
+                        }
+                    }
+                }, UserHandle.USER_ALL);
+    }
+
+    private void registerUidListener() {
+        try {
+            mAm.registerUidObserver(new IUidObserver.Stub() {
+                @Override
+                public void onUidGone(int uid, boolean disabled) throws RemoteException {
+                    mPinnerHandler.sendMessage(PooledLambda.obtainMessage(
+                            PinnerService::handleUidGone, PinnerService.this, uid));
+                }
+
+                @Override
+                public void onUidActive(int uid) throws RemoteException {
+                    mPinnerHandler.sendMessage(PooledLambda.obtainMessage(
+                            PinnerService::handleUidActive, PinnerService.this, uid));
+                }
+
+                @Override
+                public void onUidIdle(int uid, boolean disabled) throws RemoteException {
+                }
+
+                @Override
+                public void onUidStateChanged(int uid, int procState, long procStateSeq)
+                        throws RemoteException {
+                }
+
+                @Override
+                public void onUidCachedChanged(int uid, boolean cached) throws RemoteException {
+                }
+            }, UID_OBSERVER_GONE | UID_OBSERVER_ACTIVE, 0, "system");
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Failed to register uid observer", e);
+        }
+    }
+
+    private void handleUidGone(int uid) {
+        updateActiveState(uid, false /* active */);
+        int key;
+        synchronized (this) {
+
+            // In case we have a pending repin, repin now. See mPendingRepin for more information.
+            key = mPendingRepin.getOrDefault(uid, -1);
+            if (key == -1) {
+                return;
+            }
+            mPendingRepin.remove(uid);
+        }
+        pinApp(key, ActivityManager.getCurrentUser(), false /* force */);
+    }
+
+    private void handleUidActive(int uid) {
+        updateActiveState(uid, true /* active */);
+    }
+
+    private void updateActiveState(int uid, boolean active) {
+        synchronized (this) {
+            for (int i = mPinnedApps.size() - 1; i >= 0; i--) {
+                PinnedApp app = mPinnedApps.valueAt(i);
+                if (app.uid == uid) {
+                    app.active = active;
+                }
             }
         }
     }
 
-    private void unpinCameraApp() {
-        ArrayList<PinnedFile> pinnedCameraFiles;
+    private void unpinApp(@AppKey int key) {
+        ArrayList<PinnedFile> pinnedAppFiles;
         synchronized (this) {
-            pinnedCameraFiles = new ArrayList<>(mPinnedCameraFiles);
-            mPinnedCameraFiles.clear();
+            PinnedApp app = mPinnedApps.get(key);
+            if (app == null) {
+                return;
+            }
+            mPinnedApps.remove(key);
+            pinnedAppFiles = new ArrayList<>(app.mFiles);
         }
-        for (PinnedFile pinnedFile : pinnedCameraFiles) {
+        for (PinnedFile pinnedFile : pinnedAppFiles) {
             pinnedFile.close();
         }
     }
@@ -206,64 +349,167 @@
         //  use INTENT_ACTION_STILL_IMAGE_CAMERA instead of _SECURE.  On a
         //  device without a fbe enabled, the _SECURE intent will never get set.
         Intent cameraIntent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
-        PackageManager pm = mContext.getPackageManager();
-        ResolveInfo cameraResolveInfo = pm.resolveActivityAsUser(cameraIntent,
-                PackageManager.MATCH_DEFAULT_ONLY | PackageManager.MATCH_DIRECT_BOOT_AWARE
-                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
-                userHandle);
-        if (cameraResolveInfo == null ) {
-            //this is not necessarily an error
-            if (DEBUG) {
-              Slog.v(TAG, "Unable to resolve camera intent");
-            }
+        return getApplicationInfoForIntent(cameraIntent, userHandle);
+    }
+
+    private ApplicationInfo getHomeInfo(int userHandle) {
+        Intent intent = mAmInternal.getHomeIntent();
+        return getApplicationInfoForIntent(intent, userHandle);
+    }
+
+    private ApplicationInfo getApplicationInfoForIntent(Intent intent, int userHandle) {
+        if (intent == null) {
             return null;
         }
-
-        if (isResolverActivity(cameraResolveInfo.activityInfo))
-        {
-            if (DEBUG) {
-              Slog.v(TAG, "cameraIntent returned resolverActivity");
-            }
+        ResolveInfo info = mContext.getPackageManager().resolveActivityAsUser(intent,
+                MATCH_FLAGS, userHandle);
+        if (info == null) {
             return null;
         }
+        if (isResolverActivity(info.activityInfo)) {
+            return null;
+        }
+        return info.activityInfo.applicationInfo;
+    }
 
-        return cameraResolveInfo.activityInfo.applicationInfo;
+    private void sendPinAppsMessage(int userHandle) {
+        mPinnerHandler.sendMessage(PooledLambda.obtainMessage(PinnerService::pinApps, this,
+                userHandle));
+    }
+
+    private void pinApps(int userHandle) {
+        for (int i = mPinKeys.size() - 1; i >= 0; i--) {
+            int key = mPinKeys.valueAt(i);
+            pinApp(key, userHandle, true /* force */);
+        }
     }
 
     /**
-     * If the camera app is already pinned, unpin and repin it.
+     * @see #pinApp(int, int, boolean)
      */
-    private boolean pinCamera(int userHandle){
-        ApplicationInfo cameraInfo = getCameraInfo(userHandle);
-        if (cameraInfo == null) {
-            return false;
+    private void sendPinAppMessage(int key, int userHandle, boolean force) {
+        mPinnerHandler.sendMessage(PooledLambda.obtainMessage(PinnerService::pinApp, this,
+                key, userHandle, force));
+    }
+
+    /**
+     * Pins an app of a specific type {@code key}.
+     *
+     * @param force If false, this will not repin the app if it's currently active. See
+     *              {@link #mPendingRepin}.
+     */
+    private void pinApp(int key, int userHandle, boolean force) {
+        int uid = getUidForKey(key);
+
+        // In case the app is currently active, don't repin until next process restart. See
+        // mPendingRepin for more information.
+        if (!force && uid != -1) {
+            synchronized (this) {
+                mPendingRepin.put(uid, key);
+            }
+            return;
+        }
+        unpinApp(key);
+        ApplicationInfo info = getInfoForKey(key, userHandle);
+        if (info != null) {
+            pinApp(key, info);
+        }
+    }
+
+    /**
+     * Checks whether the pinned package with {@code key} is active or not.
+
+     * @return The uid of the pinned app, or {@code -1} otherwise.
+     */
+    private int getUidForKey(@AppKey int key) {
+        synchronized (this) {
+            PinnedApp existing = mPinnedApps.get(key);
+            return existing != null && existing.active
+                    ? existing.uid
+                    : -1;
+        }
+    }
+
+    /**
+     * Retrieves the current application info for the given app type.
+     *
+     * @param key The app type to retrieve the info for.
+     * @param userHandle The user id of the current user.
+     */
+    private @Nullable ApplicationInfo getInfoForKey(@AppKey int key, int userHandle) {
+        switch (key) {
+            case KEY_CAMERA:
+                return getCameraInfo(userHandle);
+            case KEY_HOME:
+                return getHomeInfo(userHandle);
+            default:
+                return null;
+        }
+    }
+
+    /**
+     * @return The app type name for {@code key}.
+     */
+    private String getNameForKey(@AppKey int key) {
+        switch (key) {
+            case KEY_CAMERA:
+                return "Camera";
+            case KEY_HOME:
+                return "Home";
+            default:
+                return null;
+        }
+    }
+
+    /**
+     * @return The maximum amount of bytes to be pinned for an app of type {@code key}.
+     */
+    private int getSizeLimitForKey(@AppKey int key) {
+        switch (key) {
+            case KEY_CAMERA:
+                return MAX_CAMERA_PIN_SIZE;
+            case KEY_HOME:
+                return MAX_HOME_PIN_SIZE;
+            default:
+                return 0;
+        }
+    }
+
+    /**
+     * Pins an application.
+     *
+     * @param key The key of the app to pin.
+     * @param appInfo The corresponding app info.
+     */
+    private void pinApp(@AppKey int key, @Nullable ApplicationInfo appInfo) {
+        if (appInfo == null) {
+            return;
         }
 
-        //unpin after checking that the camera intent has resolved
-        //this prevents us from thrashing when switching users with
-        //FBE enabled, because the intent won't resolve until the unlock
-        unpinCameraApp();
+        PinnedApp pinnedApp = new PinnedApp(appInfo);
+        synchronized (this) {
+            mPinnedApps.put(key, pinnedApp);
+        }
 
-        //pin APK
-        String camAPK = cameraInfo.sourceDir;
-        PinnedFile pf = pinFile(camAPK,
-                                MAX_CAMERA_PIN_SIZE,
-                                /*attemptPinIntrospection=*/true);
+        // pin APK
+        int pinSizeLimit = getSizeLimitForKey(key);
+        String apk = appInfo.sourceDir;
+        PinnedFile pf = pinFile(apk, pinSizeLimit, /*attemptPinIntrospection=*/true);
         if (pf == null) {
-            Slog.e(TAG, "Failed to pin " + camAPK);
-            return false;
+            Slog.e(TAG, "Failed to pin " + apk);
+            return;
         }
         if (DEBUG) {
             Slog.i(TAG, "Pinned " + pf.fileName);
         }
         synchronized (this) {
-            mPinnedCameraFiles.add(pf);
+            pinnedApp.mFiles.add(pf);
         }
 
         // determine the ABI from either ApplicationInfo or Build
         String arch = "arm";
-        if (cameraInfo.primaryCpuAbi != null) {
-            if (VMRuntime.is64BitAbi(cameraInfo.primaryCpuAbi)) {
+        if (appInfo.primaryCpuAbi != null) {
+            if (VMRuntime.is64BitAbi(appInfo.primaryCpuAbi)) {
                 arch = arch + "64";
             }
         } else {
@@ -273,32 +519,29 @@
         }
 
         // get the path to the odex or oat file
-        String baseCodePath = cameraInfo.getBaseCodePath();
+        String baseCodePath = appInfo.getBaseCodePath();
         String[] files = null;
         try {
             files = DexFile.getDexFileOutputPaths(baseCodePath, arch);
         } catch (IOException ioe) {}
         if (files == null) {
-            return true;
+            return;
         }
 
         //not pinning the oat/odex is not a fatal error
         for (String file : files) {
-            pf = pinFile(file, MAX_CAMERA_PIN_SIZE, /*attemptPinIntrospection=*/false);
+            pf = pinFile(file, pinSizeLimit, /*attemptPinIntrospection=*/false);
             if (pf != null) {
                 synchronized (this) {
-                    mPinnedCameraFiles.add(pf);
+                    pinnedApp.mFiles.add(pf);
                 }
                 if (DEBUG) {
                     Slog.i(TAG, "Pinned " + pf.fileName);
                 }
             }
         }
-
-        return true;
     }
 
-
     /** mlock length bytes of fileToPin in memory
      *
      * If attemptPinIntrospection is true, then treat the file to pin as a zip file and
@@ -581,24 +824,38 @@
         }
     }
 
-    private synchronized ArrayList<PinnedFile> snapshotPinnedFiles() {
-        int nrPinnedFiles = mPinnedFiles.size() + mPinnedCameraFiles.size();
-        ArrayList<PinnedFile> pinnedFiles = new ArrayList<>(nrPinnedFiles);
-        pinnedFiles.addAll(mPinnedFiles);
-        pinnedFiles.addAll(mPinnedCameraFiles);
-        return pinnedFiles;
-    }
-
     private final class BinderService extends Binder {
         @Override
         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
-            long totalSize = 0;
-            for (PinnedFile pinnedFile : snapshotPinnedFiles()) {
-                pw.format("%s %s\n", pinnedFile.fileName, pinnedFile.bytesPinned);
-                totalSize += pinnedFile.bytesPinned;
+            synchronized (PinnerService.this) {
+                long totalSize = 0;
+                for (PinnedFile pinnedFile : mPinnedFiles) {
+                    pw.format("%s %s\n", pinnedFile.fileName, pinnedFile.bytesPinned);
+                    totalSize += pinnedFile.bytesPinned;
+                }
+                pw.println();
+                for (int key : mPinnedApps.keySet()) {
+                    PinnedApp app = mPinnedApps.get(key);
+                    pw.print(getNameForKey(key));
+                    pw.print(" uid="); pw.print(app.uid);
+                    pw.print(" active="); pw.print(app.active);
+                    pw.println();
+                    for (PinnedFile pf : mPinnedApps.get(key).mFiles) {
+                        pw.print("  "); pw.format("%s %s\n", pf.fileName, pf.bytesPinned);
+                        totalSize += pf.bytesPinned;
+                    }
+                }
+                pw.format("Total size: %s\n", totalSize);
+                pw.println();
+                if (!mPendingRepin.isEmpty()) {
+                    pw.print("Pending repin: ");
+                    for (int key : mPendingRepin.values()) {
+                        pw.print(getNameForKey(key)); pw.print(' ');
+                    }
+                    pw.println();
+                }
             }
-            pw.format("Total size: %s\n", totalSize);
         }
     }
 
@@ -634,8 +891,30 @@
         int length;
     }
 
+    /**
+     * Represents an app that was pinned.
+     */
+    private final class PinnedApp {
+
+        /**
+         * The uid of the package being pinned. This stays constant while the package stays
+         * installed.
+         */
+        final int uid;
+
+        /** Whether it is currently active, i.e. there is a running process from that package. */
+        boolean active;
+
+        /** List of pinned files. */
+        final ArrayList<PinnedFile> mFiles = new ArrayList<>();
+
+        private PinnedApp(ApplicationInfo appInfo) {
+            uid = appInfo.uid;
+            active = mAmInternal.isUidActive(uid);
+        }
+    }
+
     final class PinnerHandler extends Handler {
-        static final int PIN_CAMERA_MSG  = 4000;
         static final int PIN_ONSTART_MSG = 4001;
 
         public PinnerHandler(Looper looper) {
@@ -645,13 +924,6 @@
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
-
-                case PIN_CAMERA_MSG:
-                {
-                    handlePinCamera(msg.arg1);
-                }
-                break;
-
                 case PIN_ONSTART_MSG:
                 {
                     handlePinOnStart();
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 607db4e..ad9fa40 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1588,10 +1588,10 @@
         // Wakeup apps for the (SUBSCRIPTION_)PHONE_STATE broadcast.
         intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
 
+        // Create a version of the intent with the number always populated.
         Intent intentWithPhoneNumber = new Intent(intent);
-        if (!TextUtils.isEmpty(incomingNumber)) {
-            intentWithPhoneNumber.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber);
-        }
+        intentWithPhoneNumber.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber);
+
         // Send broadcast twice, once for apps that have PRIVILEGED permission and once for those
         // that have the runtime one
         mContext.sendBroadcastAsUser(intentWithPhoneNumber, UserHandle.ALL,
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 928f6ef..7a5d1f5 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2207,6 +2207,9 @@
                     }
                 }
                 callbacks.finishBroadcast();
+                // We have to clean up the RemoteCallbackList here, because otherwise it will
+                // needlessly hold the enclosed callbacks until the remote process dies.
+                callbacks.kill();
             } break;
             case UPDATE_TIME_ZONE: {
                 synchronized (ActivityManagerService.this) {
@@ -22908,6 +22911,7 @@
                 // The process is being computed, so there is a cycle. We cannot
                 // rely on this process's state.
                 app.containsCycle = true;
+
                 return false;
             }
         }
@@ -22932,6 +22936,7 @@
         final int logUid = mCurOomAdjUid;
 
         int prevAppAdj = app.curAdj;
+        int prevProcState = app.curProcState;
 
         if (app.maxAdj <= ProcessList.FOREGROUND_APP_ADJ) {
             // The max adjustment doesn't allow this app to be anything
@@ -23410,11 +23415,16 @@
                         ProcessRecord client = cr.binding.client;
                         computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now);
                         if (client.containsCycle) {
-                            // We've detected a cycle. We should ignore this connection and allow
-                            // this process to retry computeOomAdjLocked later in case a later-checked
-                            // connection from a client  would raise its priority legitimately.
+                            // We've detected a cycle. We should retry computeOomAdjLocked later in
+                            // case a later-checked connection from a client  would raise its
+                            // priority legitimately.
                             app.containsCycle = true;
-                            continue;
+                            // If the client has not been completely evaluated, skip using its
+                            // priority. Else use the conservative value for now and look for a
+                            // better state in the next iteration.
+                            if (client.completedAdjSeq < mAdjSeq) {
+                                continue;
+                            }
                         }
                         int clientAdj = client.curRawAdj;
                         int clientProcState = client.curProcState;
@@ -23637,11 +23647,16 @@
                 }
                 computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now);
                 if (client.containsCycle) {
-                    // We've detected a cycle. We should ignore this connection and allow
-                    // this process to retry computeOomAdjLocked later in case a later-checked
-                    // connection from a client  would raise its priority legitimately.
+                    // We've detected a cycle. We should retry computeOomAdjLocked later in
+                    // case a later-checked connection from a client  would raise its
+                    // priority legitimately.
                     app.containsCycle = true;
-                    continue;
+                    // If the client has not been completely evaluated, skip using its
+                    // priority. Else use the conservative value for now and look for a
+                    // better state in the next iteration.
+                    if (client.completedAdjSeq < mAdjSeq) {
+                        continue;
+                    }
                 }
                 int clientAdj = client.curRawAdj;
                 int clientProcState = client.curProcState;
@@ -23873,8 +23888,8 @@
         app.foregroundActivities = foregroundActivities;
         app.completedAdjSeq = mAdjSeq;
 
-        // if curAdj is less than prevAppAdj, then this process was promoted
-        return app.curAdj < prevAppAdj;
+        // if curAdj or curProcState improved, then this process was promoted
+        return app.curAdj < prevAppAdj || app.curProcState < prevProcState;
     }
 
     /**
@@ -24927,7 +24942,7 @@
         // - Continue retrying until no process was promoted.
         // - Iterate from least important to most important.
         int cycleCount = 0;
-        while (retryCycles) {
+        while (retryCycles && cycleCount < 10) {
             cycleCount++;
             retryCycles = false;
 
@@ -24942,12 +24957,14 @@
             for (int i=0; i<N; i++) {
                 ProcessRecord app = mLruProcesses.get(i);
                 if (!app.killedByAm && app.thread != null && app.containsCycle == true) {
+
                     if (computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now)) {
                         retryCycles = true;
                     }
                 }
             }
         }
+
         for (int i=N-1; i>=0; i--) {
             ProcessRecord app = mLruProcesses.get(i);
             if (!app.killedByAm && app.thread != null) {
@@ -26694,6 +26711,13 @@
         public void enforceCallerIsRecentsOrHasPermission(String permission, String func) {
             ActivityManagerService.this.enforceCallerIsRecentsOrHasPermission(permission, func);
         }
+
+        @Override
+        public Intent getHomeIntent() {
+            synchronized (ActivityManagerService.this) {
+                return ActivityManagerService.this.getHomeIntent();
+            }
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index cc7a230..f58f717 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1658,7 +1658,10 @@
             // Some activity is waiting for another activity to become visible before it's being
             // stopped, which means that we also want to wait with stopping this one to avoid
             // flickers.
-            if (!mStackSupervisor.mActivitiesWaitingForVisibleActivity.isEmpty()) {
+            if (!mStackSupervisor.mActivitiesWaitingForVisibleActivity.isEmpty()
+                    && !mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(r)) {
+                if (DEBUG_SWITCH) Slog.i(TAG_SWITCH, "adding to waiting visible activity=" + r
+                        + " existing=" + mStackSupervisor.mActivitiesWaitingForVisibleActivity);
                 mStackSupervisor.mActivitiesWaitingForVisibleActivity.add(r);
             }
         }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index e034b82..c520101 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1634,6 +1634,8 @@
      * @param markFrozenIfConfigChanged Whether to set {@link ActivityRecord#frozenBeforeDestroy} to
      *                                  {@code true} if config changed.
      * @param deferResume Whether to defer resume while updating config.
+     * @return 'true' if starting activity was kept or wasn't provided, 'false' if it was relaunched
+     *         because of configuration update.
      */
     boolean ensureVisibilityAndConfig(ActivityRecord starting, int displayId,
             boolean markFrozenIfConfigChanged, boolean deferResume) {
@@ -1644,6 +1646,11 @@
         ensureActivitiesVisibleLocked(null /* starting */, 0 /* configChanges */,
                 false /* preserveWindows */, false /* notifyClients */);
 
+        if (displayId == INVALID_DISPLAY) {
+            // The caller didn't provide a valid display id, skip updating config.
+            return true;
+        }
+
         // Force-update the orientation from the WindowManager, since we need the true configuration
         // to send to the client now.
         final Configuration config = mWindowManager.updateOrientationFromAppTokens(
@@ -3930,6 +3937,10 @@
                         stops = new ArrayList<>();
                     }
                     stops.add(s);
+
+                    // Make sure to remove it in all cases in case we entered this block with
+                    // shouldSleepOrShutDown
+                    mActivitiesWaitingForVisibleActivity.remove(s);
                     mStoppingActivities.remove(activityNdx);
                 }
             }
diff --git a/services/core/java/com/android/server/am/AppTaskImpl.java b/services/core/java/com/android/server/am/AppTaskImpl.java
index 5f5a504..bb6c6a0 100644
--- a/services/core/java/com/android/server/am/AppTaskImpl.java
+++ b/services/core/java/com/android/server/am/AppTaskImpl.java
@@ -98,7 +98,7 @@
         final int callingUid = Binder.getCallingUid();
         final long origId = Binder.clearCallingIdentity();
         try {
-            synchronized (this) {
+            synchronized (mService) {
                 mService.mStackSupervisor.startActivityFromRecents(callingPid, callingUid, mTaskId,
                         null);
             }
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 49fa902..9eb22d7 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -543,14 +543,25 @@
         final long idleTimeMs = latest.mControllerIdleTimeMs - lastIdleMs;
         final long scanTimeMs = latest.mControllerScanTimeMs - lastScanMs;
 
-        if (txTimeMs < 0 || rxTimeMs < 0 || scanTimeMs < 0) {
+        if (txTimeMs < 0 || rxTimeMs < 0 || scanTimeMs < 0 || idleTimeMs < 0) {
             // The stats were reset by the WiFi system (which is why our delta is negative).
-            // Returns the unaltered stats.
-            delta.mControllerEnergyUsed = latest.mControllerEnergyUsed;
-            delta.mControllerRxTimeMs = latest.mControllerRxTimeMs;
-            delta.mControllerTxTimeMs = latest.mControllerTxTimeMs;
-            delta.mControllerIdleTimeMs = latest.mControllerIdleTimeMs;
-            delta.mControllerScanTimeMs = latest.mControllerScanTimeMs;
+            // Returns the unaltered stats. The total on time should not exceed the time
+            // duartion between reports.
+            final long totalOnTimeMs = latest.mControllerTxTimeMs + latest.mControllerRxTimeMs
+                        + latest.mControllerIdleTimeMs;
+            if (totalOnTimeMs <= timePeriodMs + MAX_WIFI_STATS_SAMPLE_ERROR_MILLIS) {
+                delta.mControllerEnergyUsed = latest.mControllerEnergyUsed;
+                delta.mControllerRxTimeMs = latest.mControllerRxTimeMs;
+                delta.mControllerTxTimeMs = latest.mControllerTxTimeMs;
+                delta.mControllerIdleTimeMs = latest.mControllerIdleTimeMs;
+                delta.mControllerScanTimeMs = latest.mControllerScanTimeMs;
+            } else {
+                delta.mControllerEnergyUsed = 0;
+                delta.mControllerRxTimeMs = 0;
+                delta.mControllerTxTimeMs = 0;
+                delta.mControllerIdleTimeMs = 0;
+                delta.mControllerScanTimeMs = 0;
+            }
             Slog.v(TAG, "WiFi energy data was reset, new WiFi energy data is " + delta);
         } else {
             final long totalActiveTimeMs = txTimeMs + rxTimeMs;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 0b9832d..592453f 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -236,7 +236,6 @@
     private static final int MSG_PERSIST_RINGER_MODE = 3;
     private static final int MSG_AUDIO_SERVER_DIED = 4;
     private static final int MSG_PLAY_SOUND_EFFECT = 5;
-    private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
     private static final int MSG_LOAD_SOUND_EFFECTS = 7;
     private static final int MSG_SET_FORCE_USE = 8;
     private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
@@ -268,6 +267,7 @@
     private static final int MSG_A2DP_DEVICE_CONFIG_CHANGE = 103;
     private static final int MSG_DISABLE_AUDIO_FOR_UID = 104;
     private static final int MSG_SET_HEARING_AID_CONNECTION_STATE = 105;
+    private static final int MSG_BTA2DP_DOCK_TIMEOUT = 106;
     // end of messages handled under wakelock
 
     private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
@@ -2632,6 +2632,7 @@
         broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, ringerMode);
     }
 
+    @GuardedBy("mSettingsLock")
     private void muteRingerModeStreams() {
         // Mute stream if not previously muted by ringer mode and (ringer mode
         // is not RINGER_MODE_NORMAL OR stream is zen muted) and stream is affected by ringer mode.
@@ -2719,10 +2720,9 @@
         synchronized(mSettingsLock) {
             change = mRingerMode != ringerMode;
             mRingerMode = ringerMode;
+            muteRingerModeStreams();
         }
 
-        muteRingerModeStreams();
-
         // Post a persist ringer mode msg
         if (persist) {
             sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
@@ -3811,6 +3811,10 @@
                             int delay = checkSendBecomingNoisyIntent(
                                     AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, intState,
                                     AudioSystem.DEVICE_NONE);
+                            final String addr = btDevice == null ? "null" : btDevice.getAddress();
+                            mDeviceLogger.log(new AudioEventLogger.StringEvent(
+                                    "A2DP service connected: device addr=" + addr
+                                    + " state=" + state));
                             queueMsgUnderWakeLock(mAudioHandler,
                                     MSG_SET_A2DP_SINK_CONNECTION_STATE,
                                     state,
@@ -4521,13 +4525,21 @@
         }
         synchronized (mLastDeviceConnectMsgTime) {
             long time = SystemClock.uptimeMillis() + delay;
-            handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
-            if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
-                    msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
-                    msg == MSG_SET_A2DP_SINK_CONNECTION_STATE ||
-                    msg == MSG_SET_HEARING_AID_CONNECTION_STATE) {
+
+            if (msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
+                msg == MSG_SET_A2DP_SINK_CONNECTION_STATE ||
+                msg == MSG_SET_HEARING_AID_CONNECTION_STATE ||
+                msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
+                msg == MSG_A2DP_DEVICE_CONFIG_CHANGE ||
+                msg == MSG_BTA2DP_DOCK_TIMEOUT) {
+                if (mLastDeviceConnectMsgTime >= time) {
+                  // add a little delay to make sure messages are ordered as expected
+                  time = mLastDeviceConnectMsgTime + 30;
+                }
                 mLastDeviceConnectMsgTime = time;
             }
+
+            handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
         }
     }
 
@@ -4666,7 +4678,14 @@
     public int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(BluetoothDevice device,
                 int state, int profile, boolean suppressNoisyIntent, int a2dpVolume)
     {
+        mDeviceLogger.log(new AudioEventLogger.StringEvent(
+                "setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent state=" + state
+                // only querying address as this is the only readily available field on the device
+                + " addr=" + device.getAddress()
+                + " prof=" + profile + " supprNoisy=" + suppressNoisyIntent
+                + " vol=" + a2dpVolume));
         if (mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE, device)) {
+            mDeviceLogger.log(new AudioEventLogger.StringEvent("A2DP connection state ignored"));
             return 0;
         }
         return setBluetoothA2dpDeviceConnectionStateInt(
@@ -4689,6 +4708,13 @@
             } else {
                 delay = 0;
             }
+
+            if (DEBUG_DEVICES) {
+                Log.d(TAG, "setBluetoothA2dpDeviceConnectionStateInt device: " + device
+                      + " state: " + state + " delay(ms): " + delay
+                      + " suppressNoisyIntent: " + suppressNoisyIntent);
+            }
+
             queueMsgUnderWakeLock(mAudioHandler,
                     (profile == BluetoothProfile.A2DP ?
                         MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
@@ -5597,6 +5623,7 @@
                     synchronized (mConnectedDevices) {
                         makeA2dpDeviceUnavailableNow( (String) msg.obj );
                     }
+                    mAudioEventWakeLock.release();
                     break;
 
                 case MSG_SET_FORCE_USE:
@@ -5611,7 +5638,7 @@
                 case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
                     {   WiredDeviceConnectionState connectState =
                             (WiredDeviceConnectionState)msg.obj;
-                        mWiredDevLogger.log(new WiredDevConnectEvent(connectState));
+                        mDeviceLogger.log(new WiredDevConnectEvent(connectState));
                         onSetWiredDeviceConnectionState(connectState.mType, connectState.mState,
                                 connectState.mAddress, connectState.mName, connectState.mCaller);
                         mAudioEventWakeLock.release();
@@ -5827,6 +5854,9 @@
 
     // must be called synchronized on mConnectedDevices
     private void makeA2dpDeviceUnavailableNow(String address) {
+        if (address == null) {
+            return;
+        }
         synchronized (mA2dpAvrcpLock) {
             mAvrcpAbsVolSupported = false;
         }
@@ -5836,6 +5866,9 @@
                 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
         // Remove A2DP routes as well
         setCurrentAudioRouteName(null);
+        if (mDockAddress == address) {
+            mDockAddress = null;
+        }
     }
 
     // must be called synchronized on mConnectedDevices
@@ -5847,9 +5880,12 @@
         mConnectedDevices.remove(
                 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
         // send the delayed message to make the device unavailable later
-        Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
-        mAudioHandler.sendMessageDelayed(msg, delayMs);
-
+        queueMsgUnderWakeLock(mAudioHandler,
+            MSG_BTA2DP_DOCK_TIMEOUT,
+            0,
+            0,
+            address,
+            delayMs);
     }
 
     // must be called synchronized on mConnectedDevices
@@ -5921,7 +5957,8 @@
     private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state, int a2dpVolume)
     {
         if (DEBUG_DEVICES) {
-            Log.d(TAG, "onSetA2dpSinkConnectionState btDevice=" + btDevice+"state=" + state);
+            Log.d(TAG, "onSetA2dpSinkConnectionState btDevice= " + btDevice+" state= " + state
+                + " is dock: "+btDevice.isBluetoothDock());
         }
         if (btDevice == null) {
             return;
@@ -5958,7 +5995,7 @@
                 } else {
                     // this could be a connection of another A2DP device before the timeout of
                     // a dock: cancel the dock timeout, and make the dock unavailable now
-                    if(hasScheduledA2dpDockTimeout()) {
+                    if (hasScheduledA2dpDockTimeout() && mDockAddress != null) {
                         cancelA2dpDeviceTimeout();
                         makeA2dpDeviceUnavailableNow(mDockAddress);
                     }
@@ -6056,10 +6093,14 @@
         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
             address = "";
         }
+        mDeviceLogger.log(new AudioEventLogger.StringEvent(
+                "onBluetoothA2dpDeviceConfigChange addr=" + address));
 
         int device = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
         synchronized (mConnectedDevices) {
             if (mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE, btDevice)) {
+                mDeviceLogger.log(new AudioEventLogger.StringEvent(
+                        "A2dp config change ignored"));
                 return;
             }
             final String key = makeDeviceListKey(device, address);
@@ -6177,17 +6218,6 @@
             }
         }
 
-        if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
-                mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
-                mAudioHandler.hasMessages(MSG_SET_HEARING_AID_CONNECTION_STATE) ||
-                mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
-            synchronized (mLastDeviceConnectMsgTime) {
-                long time = SystemClock.uptimeMillis();
-                if (mLastDeviceConnectMsgTime > time) {
-                    delay = (int)(mLastDeviceConnectMsgTime - time) + 30;
-                }
-            }
-        }
         return delay;
     }
 
@@ -7166,19 +7196,20 @@
     //==========================================================================================
     // AudioService logging and dumpsys
     //==========================================================================================
-    final int LOG_NB_EVENTS_PHONE_STATE = 20;
-    final int LOG_NB_EVENTS_WIRED_DEV_CONNECTION = 30;
-    final int LOG_NB_EVENTS_FORCE_USE = 20;
-    final int LOG_NB_EVENTS_VOLUME = 40;
-    final int LOG_NB_EVENTS_DYN_POLICY = 10;
+    static final int LOG_NB_EVENTS_PHONE_STATE = 20;
+    static final int LOG_NB_EVENTS_DEVICE_CONNECTION = 30;
+    static final int LOG_NB_EVENTS_FORCE_USE = 20;
+    static final int LOG_NB_EVENTS_VOLUME = 40;
+    static final int LOG_NB_EVENTS_DYN_POLICY = 10;
 
     final private AudioEventLogger mModeLogger = new AudioEventLogger(LOG_NB_EVENTS_PHONE_STATE,
             "phone state (logged after successfull call to AudioSystem.setPhoneState(int))");
 
-    final private AudioEventLogger mWiredDevLogger = new AudioEventLogger(
-            LOG_NB_EVENTS_WIRED_DEV_CONNECTION,
-            "wired device connection (logged before onSetWiredDeviceConnectionState() is executed)"
-            );
+    // logs for wired + A2DP device connections:
+    // - wired: logged before onSetWiredDeviceConnectionState() is executed
+    // - A2DP: logged at reception of method call
+    final private AudioEventLogger mDeviceLogger = new AudioEventLogger(
+            LOG_NB_EVENTS_DEVICE_CONNECTION, "wired/A2DP device connection");
 
     final private AudioEventLogger mForceUseLogger = new AudioEventLogger(
             LOG_NB_EVENTS_FORCE_USE,
@@ -7267,7 +7298,7 @@
         pw.println("\nEvent logs:");
         mModeLogger.dump(pw);
         pw.println("\n");
-        mWiredDevLogger.dump(pw);
+        mDeviceLogger.dump(pw);
         pw.println("\n");
         mForceUseLogger.dump(pw);
         pw.println("\n");
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index 4f53ed4..33525fd 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -46,6 +46,7 @@
 import libcore.io.Streams;
 
 import com.android.server.LocalServices;
+import com.android.server.policy.WindowManagerPolicy;
 
 /**
  * <p>
@@ -63,7 +64,7 @@
 
     // The layer for the electron beam surface.
     // This is currently hardcoded to be one layer above the boot animation.
-    private static final int COLOR_FADE_LAYER = 0x40000001;
+    private static final int COLOR_FADE_LAYER = WindowManagerPolicy.COLOR_FADE_LAYER;
 
     // The number of frames to draw when preparing the animation so that it will
     // be ready to run smoothly.  We use 3 frames because we are triple-buffered.
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index b9a279a..21ae048 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -31,8 +31,6 @@
 import android.os.PowerManager;
 import android.os.SystemProperties;
 import android.os.Trace;
-import android.text.TextUtils;
-import android.util.PathParser;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
@@ -404,8 +402,8 @@
                             && SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false))) {
                         mInfo.flags |= DisplayDeviceInfo.FLAG_ROUND;
                     }
-                    mInfo.displayCutout = DisplayCutout.fromResources(res, mInfo.width,
-                            mInfo.height);
+                    mInfo.displayCutout = DisplayCutout.fromResourcesRectApproximation(res,
+                            mInfo.width, mInfo.height);
                     mInfo.type = Display.TYPE_BUILT_IN;
                     mInfo.densityDpi = (int)(phys.density * 160 + 0.5f);
                     mInfo.xDpi = phys.xDpi;
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 8d730b4..0ec1f9c 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -254,7 +254,7 @@
     // 1 second, or 1 Hz frequency.
     private static final long LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS = 1000;
     // Default update duration in milliseconds for REQUEST_LOCATION.
-    private static final long LOCATION_UPDATE_DURATION_MILLIS = 0;
+    private static final long LOCATION_UPDATE_DURATION_MILLIS = 10 * 1000;
 
     /** simpler wrapper for ProviderRequest + Worksource */
     private static class GpsRequest {
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 36b04fc..c6a8712 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -955,12 +955,18 @@
     @GuardedBy("mSeparateChallengeLock")
     private void setSeparateProfileChallengeEnabledLocked(@UserIdInt int userId, boolean enabled,
             String managedUserPassword) {
+        final boolean old = getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userId);
         setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, enabled, userId);
-        if (enabled) {
-            mStorage.removeChildProfileLock(userId);
-            removeKeystoreProfileKey(userId);
-        } else {
-            tieManagedProfileLockIfNecessary(userId, managedUserPassword);
+        try {
+            if (enabled) {
+                mStorage.removeChildProfileLock(userId);
+                removeKeystoreProfileKey(userId);
+            } else {
+                tieManagedProfileLockIfNecessary(userId, managedUserPassword);
+            }
+        } catch (IllegalStateException e) {
+            setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, old, userId);
+            throw e;
         }
     }
 
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 0897b8a..c1112f7 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -329,6 +329,8 @@
 
     private long[] mFallbackVibrationPattern;
     private boolean mUseAttentionLight;
+    boolean mHasLight = true;
+    boolean mLightEnabled;
     boolean mSystemReady;
 
     private boolean mDisableNotificationEffects;
@@ -343,9 +345,9 @@
     private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
 
     // for enabling and disabling notification pulse behavior
-    private boolean mScreenOn = true;
+    boolean mScreenOn = true;
     protected boolean mInCall = false;
-    private boolean mNotificationPulseEnabled;
+    boolean mNotificationPulseEnabled;
 
     private Uri mInCallNotificationUri;
     private AudioAttributes mInCallNotificationAudioAttributes;
@@ -1195,7 +1197,8 @@
             ContentResolver resolver = getContext().getContentResolver();
             if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
                 boolean pulseEnabled = Settings.System.getIntForUser(resolver,
-                            Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT) != 0;
+                            Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT)
+                        != 0;
                 if (mNotificationPulseEnabled != pulseEnabled) {
                     mNotificationPulseEnabled = pulseEnabled;
                     updateNotificationPulse();
@@ -1457,6 +1460,8 @@
         mInCallNotificationVolume = resources.getFloat(R.dimen.config_inCallNotificationVolume);
 
         mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
+        mHasLight =
+                resources.getBoolean(com.android.internal.R.bool.config_intrusiveNotificationLed);
 
         // Don't start allowing notifications until the setup wizard has run once.
         // After that, including subsequent boots, init with notifications turned on.
@@ -3828,6 +3833,7 @@
                         pw.println("  ");
                     }
                     pw.println("  mUseAttentionLight=" + mUseAttentionLight);
+                    pw.println("  mHasLight=" + mHasLight);
                     pw.println("  mNotificationPulseEnabled=" + mNotificationPulseEnabled);
                     pw.println("  mSoundNotificationKey=" + mSoundNotificationKey);
                     pw.println("  mVibrateNotificationKey=" + mVibrateNotificationKey);
@@ -4525,6 +4531,15 @@
     @GuardedBy("mNotificationLock")
     @VisibleForTesting
     protected boolean isVisuallyInterruptive(NotificationRecord old, NotificationRecord r) {
+        // Ignore summary updates because we don't display most of the information.
+        if (r.sbn.isGroup() && r.sbn.getNotification().isGroupSummary()) {
+            if (DEBUG_INTERRUPTIVENESS) {
+                Log.v(TAG, "INTERRUPTIVENESS: "
+                        +  r.getKey() + " is not interruptive: summary");
+            }
+            return false;
+        }
+
         if (old == null) {
             if (DEBUG_INTERRUPTIVENESS) {
                 Log.v(TAG, "INTERRUPTIVENESS: "
@@ -4562,15 +4577,6 @@
             return false;
         }
 
-        // Ignore summary updates because we don't display most of the information.
-        if (r.sbn.isGroup() && r.sbn.getNotification().isGroupSummary()) {
-            if (DEBUG_INTERRUPTIVENESS) {
-                Log.v(TAG, "INTERRUPTIVENESS: "
-                        +  r.getKey() + " is not interruptive: summary");
-            }
-            return false;
-        }
-
         final String oldTitle = String.valueOf(oldN.extras.get(Notification.EXTRA_TITLE));
         final String newTitle = String.valueOf(newN.extras.get(Notification.EXTRA_TITLE));
         if (!Objects.equals(oldTitle, newTitle)) {
@@ -4825,8 +4831,7 @@
         // light
         // release the light
         boolean wasShowLights = mLights.remove(key);
-        if (record.getLight() != null && aboveThreshold
-                && ((record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_LIGHTS) == 0)) {
+        if (canShowLightsLocked(record, aboveThreshold)) {
             mLights.add(key);
             updateLightsLocked();
             if (mUseAttentionLight) {
@@ -4837,7 +4842,19 @@
             updateLightsLocked();
         }
         if (buzz || beep || blink) {
-            record.setInterruptive(true);
+            // Ignore summary updates because we don't display most of the information.
+            if (record.sbn.isGroup() && record.sbn.getNotification().isGroupSummary()) {
+                if (DEBUG_INTERRUPTIVENESS) {
+                    Log.v(TAG, "INTERRUPTIVENESS: "
+                            + record.getKey() + " is not interruptive: summary");
+                }
+            } else {
+                if (DEBUG_INTERRUPTIVENESS) {
+                    Log.v(TAG, "INTERRUPTIVENESS: "
+                            + record.getKey() + " is interruptive: alerted");
+                }
+                record.setInterruptive(true);
+            }
             MetricsLogger.action(record.getLogMaker()
                     .setCategory(MetricsEvent.NOTIFICATION_ALERT)
                     .setType(MetricsEvent.TYPE_OPEN)
@@ -4847,11 +4864,49 @@
     }
 
     @GuardedBy("mNotificationLock")
+    boolean canShowLightsLocked(final NotificationRecord record, boolean aboveThreshold) {
+        // device lacks light
+        if (!mHasLight) {
+            return false;
+        }
+        // user turned lights off globally
+        if (!mNotificationPulseEnabled) {
+            return false;
+        }
+        // the notification/channel has no light
+        if (record.getLight() == null) {
+            return false;
+        }
+        // unimportant notification
+        if (!aboveThreshold) {
+            return false;
+        }
+        // suppressed due to DND
+        if ((record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_LIGHTS) != 0) {
+            return false;
+        }
+        // Suppressed because it's a silent update
+        final Notification notification = record.getNotification();
+        if (record.isUpdate && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
+            return false;
+        }
+        // Suppressed because another notification in its group handles alerting
+        if (record.sbn.isGroup() && record.getNotification().suppressAlertingDueToGrouping()) {
+            return false;
+        }
+        // not if in call or the screen's on
+        if (mInCall || mScreenOn) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @GuardedBy("mNotificationLock")
     boolean shouldMuteNotificationLocked(final NotificationRecord record) {
         // Suppressed because it's a silent update
         final Notification notification = record.getNotification();
-        if(record.isUpdate
-                && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
+        if (record.isUpdate && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
             return true;
         }
 
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 0f3f44e..75b9f13 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -95,6 +95,7 @@
     static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
     private static final int MAX_LOGTAG_LENGTH = 35;
     final StatusBarNotification sbn;
+    IActivityManager mAm;
     final int mTargetSdkVersion;
     final int mOriginalFlags;
     private final Context mContext;
@@ -127,6 +128,11 @@
     // The most recent update time, or the creation time if no updates.
     private long mUpdateTimeMs;
 
+    // The most recent interruption time, or the creation time if no updates. Differs from the
+    // above value because updates are filtered based on whether they actually interrupted the
+    // user
+    private long mInterruptionTimeMs;
+
     // Is this record an update of an old record?
     public boolean isUpdate;
     private int mPackagePriority;
@@ -174,10 +180,12 @@
         this.sbn = sbn;
         mTargetSdkVersion = LocalServices.getService(PackageManagerInternal.class)
                 .getPackageTargetSdkVersion(sbn.getPackageName());
+        mAm = ActivityManager.getService();
         mOriginalFlags = sbn.getNotification().flags;
         mRankingTimeMs = calculateRankingTimeMs(0L);
         mCreationTimeMs = sbn.getPostTime();
         mUpdateTimeMs = mCreationTimeMs;
+        mInterruptionTimeMs = mCreationTimeMs;
         mContext = context;
         stats = new NotificationUsageStats.SingleNotificationStats();
         mChannel = channel;
@@ -523,6 +531,7 @@
         pw.println(prefix + "mCreationTimeMs=" + mCreationTimeMs);
         pw.println(prefix + "mVisibleSinceMs=" + mVisibleSinceMs);
         pw.println(prefix + "mUpdateTimeMs=" + mUpdateTimeMs);
+        pw.println(prefix + "mInterruptionTimeMs=" + mInterruptionTimeMs);
         pw.println(prefix + "mSuppressedVisualEffects= " + mSuppressedVisualEffects);
         if (mPreChannelsNotification) {
             pw.println(prefix + String.format("defaults=0x%08x flags=0x%08x",
@@ -784,6 +793,10 @@
         return mVisibleSinceMs == 0 ? 0 : (int) (now - mVisibleSinceMs);
     }
 
+    public int getInterruptionMs(long now) {
+        return (int) (now - mInterruptionTimeMs);
+    }
+
     /**
      * Set the visibility of the notification.
      */
@@ -842,7 +855,7 @@
     public void setSeen() {
         mStats.setSeen();
         if (mTextChanged) {
-            mIsInterruptive = true;
+            setInterruptive(true);
         }
     }
 
@@ -938,6 +951,17 @@
 
     public void setInterruptive(boolean interruptive) {
         mIsInterruptive = interruptive;
+        final long now = System.currentTimeMillis();
+        mInterruptionTimeMs = interruptive ? now : mInterruptionTimeMs;
+
+        if (interruptive) {
+            MetricsLogger.action(getLogMaker()
+                    .setCategory(MetricsEvent.NOTIFICATION_INTERRUPTION)
+                    .setType(MetricsEvent.TYPE_OPEN)
+                    .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_INTERRUPTION_MILLIS,
+                            getInterruptionMs(now)));
+            MetricsLogger.histogram(mContext, "note_interruptive", getInterruptionMs(now));
+        }
     }
 
     public void setTextChanged(boolean textChanged) {
@@ -1036,16 +1060,17 @@
      * Collect all {@link Uri} that should have permission granted to whoever
      * will be rendering it.
      */
-    private void calculateGrantableUris() {
+    protected void calculateGrantableUris() {
         final Notification notification = getNotification();
         notification.visitUris((uri) -> {
-            visitGrantableUri(uri);
+            visitGrantableUri(uri, false);
         });
 
         if (notification.getChannelId() != null) {
             NotificationChannel channel = getChannel();
             if (channel != null) {
-                visitGrantableUri(channel.getSound());
+                visitGrantableUri(channel.getSound(), (channel.getUserLockedFields()
+                        & NotificationChannel.USER_LOCKED_SOUND) != 0);
             }
         }
     }
@@ -1058,18 +1083,17 @@
      * {@link #mGrantableUris}. Otherwise, this will either log or throw
      * {@link SecurityException} depending on target SDK of enqueuing app.
      */
-    private void visitGrantableUri(Uri uri) {
+    private void visitGrantableUri(Uri uri, boolean userOverriddenUri) {
         if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
 
         // We can't grant Uri permissions from system
         final int sourceUid = sbn.getUid();
         if (sourceUid == android.os.Process.SYSTEM_UID) return;
 
-        final IActivityManager am = ActivityManager.getService();
         final long ident = Binder.clearCallingIdentity();
         try {
             // This will throw SecurityException if caller can't grant
-            am.checkGrantUriPermission(sourceUid, null,
+            mAm.checkGrantUriPermission(sourceUid, null,
                     ContentProvider.getUriWithoutUserId(uri),
                     Intent.FLAG_GRANT_READ_URI_PERMISSION,
                     ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)));
@@ -1081,10 +1105,12 @@
         } catch (RemoteException ignored) {
             // Ignored because we're in same process
         } catch (SecurityException e) {
-            if (mTargetSdkVersion >= Build.VERSION_CODES.P) {
-                throw e;
-            } else {
-                Log.w(TAG, "Ignoring " + uri + " from " + sourceUid + ": " + e.getMessage());
+            if (!userOverriddenUri) {
+                if (mTargetSdkVersion >= Build.VERSION_CODES.P) {
+                    throw e;
+                } else {
+                    Log.w(TAG, "Ignoring " + uri + " from " + sourceUid + ": " + e.getMessage());
+                }
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -1112,7 +1138,9 @@
                         sbn.getNotification().isGroupSummary() ? 1 : 0)
                 .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS, getLifespanMs(now))
                 .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_UPDATE_MILLIS, getFreshnessMs(now))
-                .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS, getExposureMs(now));
+                .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS, getExposureMs(now))
+                .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_INTERRUPTION_MILLIS,
+                        getInterruptionMs(now));
     }
 
     public LogMaker getLogMaker() {
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 0774672..d6ab5f7 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -489,7 +489,7 @@
         PinnerService pinnerService = LocalServices.getService(PinnerService.class);
         if (pinnerService != null) {
             Log.i(TAG, "Pinning optimized code " + updatedPackages);
-            pinnerService.update(updatedPackages);
+            pinnerService.update(updatedPackages, false /* force */);
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 1b8c2cc..f30372b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -13967,6 +13967,68 @@
         return false;
     }
 
+    @Override
+    public void setSystemAppHiddenUntilInstalled(String packageName, boolean hidden) {
+        enforceSystemOrPhoneCaller("setSystemAppHiddenUntilInstalled");
+        synchronized (mPackages) {
+            final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
+            if (pkgSetting == null || !pkgSetting.isSystem()) {
+                return;
+            }
+            PackageParser.Package pkg = pkgSetting.pkg;
+            if (pkg != null && pkg.applicationInfo != null) {
+                pkg.applicationInfo.hiddenUntilInstalled = hidden;
+            }
+            final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(packageName);
+            if (disabledPs == null) {
+                return;
+            }
+            pkg = disabledPs.pkg;
+            if (pkg != null && pkg.applicationInfo != null) {
+                pkg.applicationInfo.hiddenUntilInstalled = hidden;
+            }
+        }
+    }
+
+    @Override
+    public boolean setSystemAppInstallState(String packageName, boolean installed, int userId) {
+        enforceSystemOrPhoneCaller("setSystemAppInstallState");
+        synchronized (mPackages) {
+            final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
+            // The target app should always be in system
+            if (pkgSetting == null || !pkgSetting.isSystem()) {
+                return false;
+            }
+            // Check if the install state is the same
+            if (pkgSetting.getInstalled(userId) == installed) {
+                return false;
+            }
+        }
+
+        final long callingId = Binder.clearCallingIdentity();
+        try {
+            if (installed) {
+                // install the app from uninstalled state
+                installExistingPackageAsUser(
+                        packageName,
+                        userId,
+                        0 /*installFlags*/,
+                        PackageManager.INSTALL_REASON_DEVICE_SETUP);
+                return true;
+            }
+
+            // uninstall the app from installed state
+            deletePackageVersioned(
+                    new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST),
+                    new LegacyPackageDeleteObserver(null).getBinder(),
+                    userId,
+                    PackageManager.DELETE_SYSTEM_APP);
+            return true;
+        } finally {
+            Binder.restoreCallingIdentity(callingId);
+        }
+    }
+
     private void sendApplicationHiddenForUser(String packageName, PackageSetting pkgSetting,
             int userId) {
         final PackageRemovedInfo info = new PackageRemovedInfo(this);
@@ -14031,10 +14093,16 @@
     @Override
     public int installExistingPackageAsUser(String packageName, int userId, int installFlags,
             int installReason) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES,
-                null);
-        PackageSetting pkgSetting;
         final int callingUid = Binder.getCallingUid();
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES)
+                != PackageManager.PERMISSION_GRANTED
+                && mContext.checkCallingOrSelfPermission(
+                        android.Manifest.permission.INSTALL_EXISTING_PACKAGES)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Neither user " + callingUid + " nor current process has "
+                    + android.Manifest.permission.INSTALL_PACKAGES + ".");
+        }
+        PackageSetting pkgSetting;
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 true /* requireFullPermission */, true /* checkShell */,
                 "installExistingPackage for user " + userId);
@@ -14178,7 +14246,7 @@
                         unactionedPackages.add(packageName);
                         continue;
                     }
-                    if (!canSuspendPackageForUserLocked(packageName, userId)) {
+                    if (suspended && !canSuspendPackageForUserLocked(packageName, userId)) {
                         unactionedPackages.add(packageName);
                         continue;
                     }
@@ -14333,44 +14401,44 @@
     @GuardedBy("mPackages")
     private boolean canSuspendPackageForUserLocked(String packageName, int userId) {
         if (isPackageDeviceAdmin(packageName, userId)) {
-            Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName
+            Slog.w(TAG, "Cannot suspend package \"" + packageName
                     + "\": has an active device admin");
             return false;
         }
 
         String activeLauncherPackageName = getActiveLauncherPackageName(userId);
         if (packageName.equals(activeLauncherPackageName)) {
-            Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName
+            Slog.w(TAG, "Cannot suspend package \"" + packageName
                     + "\": contains the active launcher");
             return false;
         }
 
         if (packageName.equals(mRequiredInstallerPackage)) {
-            Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName
+            Slog.w(TAG, "Cannot suspend package \"" + packageName
                     + "\": required for package installation");
             return false;
         }
 
         if (packageName.equals(mRequiredUninstallerPackage)) {
-            Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName
+            Slog.w(TAG, "Cannot suspend package \"" + packageName
                     + "\": required for package uninstallation");
             return false;
         }
 
         if (packageName.equals(mRequiredVerifierPackage)) {
-            Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName
+            Slog.w(TAG, "Cannot suspend package \"" + packageName
                     + "\": required for package verification");
             return false;
         }
 
         if (packageName.equals(getDefaultDialerPackageName(userId))) {
-            Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName
+            Slog.w(TAG, "Cannot suspend package \"" + packageName
                     + "\": is the default dialer");
             return false;
         }
 
         if (mProtectedPackages.isPackageStateProtected(userId, packageName)) {
-            Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName
+            Slog.w(TAG, "Cannot suspend package \"" + packageName
                     + "\": protected package");
             return false;
         }
@@ -21093,6 +21161,8 @@
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(), this,
                 mContext.getContentResolver(), UserHandle.USER_SYSTEM);
 
+        disableSkuSpecificApps();
+
         // Read the compatibilty setting when the system is ready.
         boolean compatibilityModeEnabled = android.provider.Settings.Global.getInt(
                 mContext.getContentResolver(),
@@ -21880,6 +21950,28 @@
         }
     }
 
+    //TODO: b/111402650
+    private void disableSkuSpecificApps() {
+        if (!mIsUpgrade && !mFirstBoot) {
+            return;
+        }
+        String apkList[] = mContext.getResources().getStringArray(
+                R.array.config_disableApksUnlessMatchedSku_apk_list);
+        String skuArray[] = mContext.getResources().getStringArray(
+                R.array.config_disableApkUnlessMatchedSku_skus_list);
+        if (ArrayUtils.isEmpty(apkList)) {
+           return;
+        }
+        String sku = SystemProperties.get("ro.boot.hardware.sku");
+        if (!TextUtils.isEmpty(sku) && ArrayUtils.contains(skuArray, sku)) {
+            return;
+        }
+        for (String packageName : apkList) {
+            setSystemAppHiddenUntilInstalled(packageName, true);
+            setSystemAppInstallState(packageName, false, ActivityManager.getCurrentUser());
+        }
+    }
+
     private void dumpProto(FileDescriptor fd) {
         final ProtoOutputStream proto = new ProtoOutputStream(fd);
 
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 5177995..a7e3830 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -4120,7 +4120,8 @@
                     continue;
                 }
                 final boolean shouldInstall = ps.isSystem() &&
-                        !ArrayUtils.contains(disallowedPackages, ps.name);
+                        !ArrayUtils.contains(disallowedPackages, ps.name) &&
+                        !ps.pkg.applicationInfo.hiddenUntilInstalled;
                 // Only system apps are initially installed.
                 ps.setInstalled(shouldInstall, userHandle);
                 if (!shouldInstall) {
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 599e5a5..b9c3048 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -132,6 +132,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
@@ -1573,6 +1574,24 @@
                 "Ephemeral apps can't use ShortcutManager");
     }
 
+    private void verifyShortcutInfoPackage(String callerPackage, ShortcutInfo si) {
+        if (si == null) {
+            return;
+        }
+        if (!Objects.equals(callerPackage, si.getPackage())) {
+            android.util.EventLog.writeEvent(0x534e4554, "109824443", -1, "");
+            throw new SecurityException("Shortcut package name mismatch");
+        }
+    }
+
+    private void verifyShortcutInfoPackages(
+            String callerPackage, List<ShortcutInfo> list) {
+        final int size = list.size();
+        for (int i = 0; i < size; i++) {
+            verifyShortcutInfoPackage(callerPackage, list.get(i));
+        }
+    }
+
     // Overridden in unit tests to execute r synchronously.
     void injectPostToHandler(Runnable r) {
         mHandler.post(r);
@@ -1720,6 +1739,7 @@
         verifyCaller(packageName, userId);
 
         final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
+        verifyShortcutInfoPackages(packageName, newShortcuts);
         final int size = newShortcuts.size();
 
         final boolean unlimited = injectHasUnlimitedShortcutsApiCallsPermission(
@@ -1774,6 +1794,7 @@
         verifyCaller(packageName, userId);
 
         final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
+        verifyShortcutInfoPackages(packageName, newShortcuts);
         final int size = newShortcuts.size();
 
         final boolean unlimited = injectHasUnlimitedShortcutsApiCallsPermission(
@@ -1859,6 +1880,7 @@
         verifyCaller(packageName, userId);
 
         final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
+        verifyShortcutInfoPackages(packageName, newShortcuts);
         final int size = newShortcuts.size();
 
         final boolean unlimited = injectHasUnlimitedShortcutsApiCallsPermission(
@@ -1921,6 +1943,7 @@
         Preconditions.checkNotNull(shortcut);
         Preconditions.checkArgument(shortcut.isEnabled(), "Shortcut must be enabled");
         verifyCaller(packageName, userId);
+        verifyShortcutInfoPackage(packageName, shortcut);
 
         final Intent ret;
         synchronized (mLock) {
@@ -1942,6 +1965,7 @@
     private boolean requestPinItem(String packageName, int userId, ShortcutInfo shortcut,
             AppWidgetProviderInfo appWidget, Bundle extras, IntentSender resultIntent) {
         verifyCaller(packageName, userId);
+        verifyShortcutInfoPackage(packageName, shortcut);
 
         final boolean ret;
         synchronized (mLock) {
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index c9aa1ef..1ae59cb 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -833,11 +833,11 @@
                     getSystemPackage(textClassifierPackageName);
             if (textClassifierPackage != null
                     && doesPackageSupportRuntimePermissions(textClassifierPackage)) {
-                grantRuntimePermissions(textClassifierPackage, PHONE_PERMISSIONS, true, userId);
-                grantRuntimePermissions(textClassifierPackage, SMS_PERMISSIONS, true, userId);
-                grantRuntimePermissions(textClassifierPackage, CALENDAR_PERMISSIONS, true, userId);
-                grantRuntimePermissions(textClassifierPackage, LOCATION_PERMISSIONS, true, userId);
-                grantRuntimePermissions(textClassifierPackage, CONTACTS_PERMISSIONS, true, userId);
+                grantRuntimePermissions(textClassifierPackage, PHONE_PERMISSIONS, false, userId);
+                grantRuntimePermissions(textClassifierPackage, SMS_PERMISSIONS, false, userId);
+                grantRuntimePermissions(textClassifierPackage, CALENDAR_PERMISSIONS, false, userId);
+                grantRuntimePermissions(textClassifierPackage, LOCATION_PERMISSIONS, false, userId);
+                grantRuntimePermissions(textClassifierPackage, CONTACTS_PERMISSIONS, false, userId);
             }
         }
 
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index a02ee22..e11b642 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -157,6 +157,8 @@
     int FINISH_LAYOUT_REDO_WALLPAPER = 0x0004;
     /** Need to recompute animations */
     int FINISH_LAYOUT_REDO_ANIM = 0x0008;
+    /** Layer for the screen off animation */
+    int COLOR_FADE_LAYER = 0x40000001;
 
     /**
      * Register shortcuts for window manager to dispatch.
diff --git a/services/core/java/com/android/server/slice/PinnedSliceState.java b/services/core/java/com/android/server/slice/PinnedSliceState.java
index 4e7fb96..e139ab8 100644
--- a/services/core/java/com/android/server/slice/PinnedSliceState.java
+++ b/services/core/java/com/android/server/slice/PinnedSliceState.java
@@ -154,8 +154,8 @@
     }
 
     ContentProviderClient getClient() {
-        ContentProviderClient client =
-                mService.getContext().getContentResolver().acquireContentProviderClient(mUri);
+        ContentProviderClient client = mService.getContext().getContentResolver()
+                .acquireUnstableContentProviderClient(mUri);
         if (client == null) return null;
         client.setDetectNotResponding(SLICE_TIMEOUT);
         return client;
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 08d0ae9..fa6079c 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -19,6 +19,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.pm.ActivityInfo.COLOR_MODE_DEFAULT;
 import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
@@ -1377,7 +1378,7 @@
             setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM, "checkAppWindowsReadyToShow");
 
             // We can now show all of the drawn windows!
-            if (!mService.mOpeningApps.contains(this)) {
+            if (!mService.mOpeningApps.contains(this) && canShowWindows()) {
                 showAllWindowsLocked();
             }
         }
@@ -2270,4 +2271,21 @@
     boolean isClosingOrEnteringPip() {
         return (isAnimating() && hiddenRequested) || mWillCloseOrEnterPip;
     }
+
+    /**
+     * @return Whether we are allowed to show non-starting windows at the moment. We disallow
+     *         showing windows during transitions in case we have windows that have wide-color-gamut
+     *         color mode set to avoid jank in the middle of the transition.
+     */
+    boolean canShowWindows() {
+        return allDrawn && !(isReallyAnimating() && hasNonDefaultColorWindow());
+    }
+
+    /**
+     * @return true if we have a window that has a non-default color mode set; false otherwise.
+     */
+    private boolean hasNonDefaultColorWindow() {
+        return forAllWindows(ws -> ws.mAttrs.getColorMode() != COLOR_MODE_DEFAULT,
+                true /* topToBottom */);
+    }
 }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index b0e6208..2887e5ef 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -404,7 +404,7 @@
         WindowStateAnimator winAnimator = w.mWinAnimator;
         final AppWindowToken atoken = w.mAppToken;
         if (winAnimator.mDrawState == READY_TO_SHOW) {
-            if (atoken == null || atoken.allDrawn) {
+            if (atoken == null || atoken.canShowWindows()) {
                 if (w.performShowLocked()) {
                     pendingLayoutChanges |= FINISH_LAYOUT_REDO_ANIM;
                     if (DEBUG_LAYOUT_REPEATS) {
@@ -1106,11 +1106,12 @@
             }
         }
 
+        forAllWindows(w -> {
+            w.forceSeamlesslyRotateIfAllowed(oldRotation, rotation);
+        }, true /* traverseTopToBottom */);
+
         if (rotateSeamlessly) {
-            forAllWindows(w -> {
-                    w.mWinAnimator.seamlesslyRotateWindow(getPendingTransaction(),
-                            oldRotation, rotation);
-            }, true /* traverseTopToBottom */);
+            seamlesslyRotate(getPendingTransaction(), oldRotation, rotation);
         }
 
         mService.mDisplayManagerInternal.performTraversal(getPendingTransaction());
@@ -1252,11 +1253,21 @@
                     cutout, mInitialDisplayWidth, mInitialDisplayHeight);
         }
         final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
-        final Path bounds = cutout.getBounds().getBoundaryPath();
+        final List<Rect> bounds = WmDisplayCutout.computeSafeInsets(
+                        cutout, mInitialDisplayWidth, mInitialDisplayHeight)
+                .getDisplayCutout().getBoundingRects();
         transformPhysicalToLogicalCoordinates(rotation, mInitialDisplayWidth, mInitialDisplayHeight,
                 mTmpMatrix);
-        bounds.transform(mTmpMatrix);
-        return WmDisplayCutout.computeSafeInsets(DisplayCutout.fromBounds(bounds),
+        final Region region = Region.obtain();
+        for (int i = 0; i < bounds.size(); i++) {
+            final Rect rect = bounds.get(i);
+            final RectF rectF = new RectF(bounds.get(i));
+            mTmpMatrix.mapRect(rectF);
+            rectF.round(rect);
+            region.op(rect, Op.UNION);
+        }
+
+        return WmDisplayCutout.computeSafeInsets(DisplayCutout.fromBounds(region),
                 rotated ? mInitialDisplayHeight : mInitialDisplayWidth,
                 rotated ? mInitialDisplayWidth : mInitialDisplayHeight);
     }
@@ -3538,7 +3549,14 @@
                 // docked or freeform stack is visible...except for the home stack/task if the
                 // docked stack is minimized and it actually set something.
                 if (mHomeStack != null && mHomeStack.isVisible()
-                        && mDividerControllerLocked.isMinimizedDock()) {
+                        && mDividerControllerLocked.isMinimizedDock()
+                        // TODO(b/110159357): Work around to unblock the release for failing test
+                        // ActivityManagerAppConfigurationTests#testSplitscreenPortraitAppOrientationRequests
+                        // which shouldn't be failing since home stack shouldn't be visible. We need
+                        // to dig deeper to see why it is failing. NOTE: Not failing on current
+                        // master...
+                        && !(mDividerControllerLocked.isHomeStackResizable()
+                            && mHomeStack.matchParentBounds())) {
                     final int orientation = mHomeStack.getOrientation();
                     if (orientation != SCREEN_ORIENTATION_UNSET) {
                         return orientation;
@@ -3694,6 +3712,19 @@
         }
 
         @Override
+        SurfaceControl.Builder makeChildSurface(WindowContainer child) {
+            final SurfaceControl.Builder builder = super.makeChildSurface(child);
+            if (child instanceof WindowToken && ((WindowToken) child).mRoundedCornerOverlay) {
+                // To draw above the ColorFade layer during the screen off transition, the
+                // rounded corner overlays need to be at the root of the surface hierarchy.
+                // TODO: move the ColorLayer into the display overlay layer such that this is not
+                // necessary anymore.
+                builder.setParent(null);
+            }
+            return builder;
+        }
+
+        @Override
         void assignChildLayers(SurfaceControl.Transaction t) {
             assignChildLayers(t, null /* imeContainer */);
         }
@@ -3709,6 +3740,10 @@
                     wt.assignRelativeLayer(t, mTaskStackContainers.getSplitScreenDividerAnchor(), 1);
                     continue;
                 }
+                if (wt.mRoundedCornerOverlay) {
+                    wt.assignLayer(t, WindowManagerPolicy.COLOR_FADE_LAYER + 1);
+                    continue;
+                }
                 wt.assignLayer(t, j);
                 wt.assignChildLayers(t);
 
diff --git a/services/core/java/com/android/server/wm/ForcedSeamlessRotator.java b/services/core/java/com/android/server/wm/ForcedSeamlessRotator.java
new file mode 100644
index 0000000..f25ec5c
--- /dev/null
+++ b/services/core/java/com/android/server/wm/ForcedSeamlessRotator.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+
+import android.graphics.Matrix;
+import android.view.DisplayInfo;
+
+import com.android.server.wm.utils.CoordinateTransforms;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * Helper class for forced seamless rotation.
+ *
+ * Works by transforming the window token back into the old display rotation.
+ *
+ * Uses deferTransactionUntil instead of latching on the buffer size to allow for seamless 180
+ * degree rotations.
+ */
+public class ForcedSeamlessRotator {
+
+    private final Matrix mTransform = new Matrix();
+    private final float[] mFloat9 = new float[9];
+    private final int mOldRotation;
+    private final int mNewRotation;
+
+    public ForcedSeamlessRotator(int oldRotation, int newRotation, DisplayInfo info) {
+        mOldRotation = oldRotation;
+        mNewRotation = newRotation;
+
+        final boolean flipped = info.rotation == ROTATION_90 || info.rotation == ROTATION_270;
+        final int h = flipped ? info.logicalWidth : info.logicalHeight;
+        final int w = flipped ? info.logicalHeight : info.logicalWidth;
+
+        final Matrix tmp = new Matrix();
+        CoordinateTransforms.transformLogicalToPhysicalCoordinates(oldRotation, w, h, mTransform);
+        CoordinateTransforms.transformPhysicalToLogicalCoordinates(newRotation, w, h, tmp);
+        mTransform.postConcat(tmp);
+    }
+
+    /**
+     * Applies a transform to the window token's surface that undoes the effect of the global
+     * display rotation.
+     */
+    public void unrotate(WindowToken token) {
+        token.getPendingTransaction().setMatrix(token.getSurfaceControl(), mTransform, mFloat9);
+    }
+
+    /**
+     * Removes the transform to the window token's surface that undoes the effect of the global
+     * display rotation.
+     *
+     * Removing the transform and the result of the WindowState's layout are both tied to the
+     * WindowState's next frame, such that they apply at the same time the client draws the
+     * window in the new orientation.
+     */
+    public void finish(WindowToken token, WindowState win) {
+        mTransform.reset();
+        token.getPendingTransaction().setMatrix(token.mSurfaceControl, mTransform, mFloat9);
+        token.getPendingTransaction().deferTransactionUntil(token.mSurfaceControl,
+                win.mWinAnimator.mSurfaceController.mSurfaceControl.getHandle(),
+                win.getFrameNumber());
+        win.getPendingTransaction().deferTransactionUntil(win.mSurfaceControl,
+                win.mWinAnimator.mSurfaceController.mSurfaceControl.getHandle(),
+                win.getFrameNumber());
+    }
+
+    public void dump(PrintWriter pw) {
+        pw.print("{old="); pw.print(mOldRotation); pw.print(", new="); pw.print(mNewRotation);
+        pw.print("}");
+    }
+
+    @Override
+    public String toString() {
+        StringWriter sw = new StringWriter();
+        dump(new PrintWriter(sw));
+        return "ForcedSeamlessRotator" + sw.toString();
+    }
+}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 281e0a844..a626663 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -40,6 +40,7 @@
 import android.os.Looper;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.Trace;
 import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -620,6 +621,8 @@
 
         private void updateInputWindows(boolean inDrag) {
 
+            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "updateInputWindows");
+
             // TODO: multi-display
             navInputConsumer = getInputConsumer(INPUT_CONSUMER_NAVIGATION, DEFAULT_DISPLAY);
             pipInputConsumer = getInputConsumer(INPUT_CONSUMER_PIP, DEFAULT_DISPLAY);
@@ -645,6 +648,8 @@
             mService.mInputManager.setInputWindows(mInputWindowHandles, mFocusedInputWindowHandle);
 
             clearInputWindowHandlesLw();
+
+            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
index 2bfff26..cb50460 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
@@ -26,6 +26,8 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
 import android.annotation.Nullable;
+import android.hardware.power.V1_0.PowerHint;
+import android.os.PowerManagerInternal;
 import android.util.ArrayMap;
 import android.view.Choreographer;
 import android.view.SurfaceControl;
@@ -57,6 +59,7 @@
     private final AnimationHandler mAnimationHandler;
     private final Transaction mFrameTransaction;
     private final AnimatorFactory mAnimatorFactory;
+    private final PowerManagerInternal mPowerManagerInternal;
     private boolean mApplyScheduled;
 
     @GuardedBy("mLock")
@@ -70,13 +73,15 @@
     @GuardedBy("mLock")
     private boolean mAnimationStartDeferred;
 
-    SurfaceAnimationRunner() {
-        this(null /* callbackProvider */, null /* animatorFactory */, new Transaction());
+    SurfaceAnimationRunner(PowerManagerInternal powerManagerInternal) {
+        this(null /* callbackProvider */, null /* animatorFactory */, new Transaction(),
+                powerManagerInternal);
     }
 
     @VisibleForTesting
     SurfaceAnimationRunner(@Nullable AnimationFrameCallbackProvider callbackProvider,
-            AnimatorFactory animatorFactory, Transaction frameTransaction) {
+            AnimatorFactory animatorFactory, Transaction frameTransaction,
+            PowerManagerInternal powerManagerInternal) {
         SurfaceAnimationThread.getHandler().runWithScissors(() -> mChoreographer = getSfInstance(),
                 0 /* timeout */);
         mFrameTransaction = frameTransaction;
@@ -87,6 +92,7 @@
         mAnimatorFactory = animatorFactory != null
                 ? animatorFactory
                 : SfValueAnimator::new;
+        mPowerManagerInternal = powerManagerInternal;
     }
 
     /**
@@ -231,6 +237,7 @@
         synchronized (mLock) {
             startPendingAnimationsLocked();
         }
+        mPowerManagerInternal.powerHint(PowerHint.INTERACTION, 0);
     }
 
     private void scheduleApplyTransaction() {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 19c5a3d..8fe7063 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -736,6 +736,20 @@
     }
 
     /**
+     * Seamlessly rotates the container, by recomputing the location in the new
+     * rotation, and rotating buffers until they are updated for the new rotation.
+     *
+     * @param t the transaction to perform the seamless rotation in
+     * @param oldRotation the rotation we are rotating from
+     * @param newRotation the rotation we are rotating to
+     */
+    void seamlesslyRotate(Transaction t, int oldRotation, int newRotation) {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            mChildren.get(i).seamlesslyRotate(t, oldRotation, newRotation);
+        }
+    }
+
+    /**
      * Returns true if this container is opaque and fills all the space made available by its parent
      * container.
      *
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 7a2c28b..8bc2246 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1061,7 +1061,7 @@
                 PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, TAG_WM);
         mHoldingScreenWakeLock.setReferenceCounted(false);
 
-        mSurfaceAnimationRunner = new SurfaceAnimationRunner();
+        mSurfaceAnimationRunner = new SurfaceAnimationRunner(mPowerManagerInternal);
 
         mAllowTheaterModeWakeFromLayout = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_allowTheaterModeWakeFromWindowLayout);
@@ -1883,6 +1883,13 @@
             }
 
             win.setFrameNumber(frameNumber);
+
+            if (win.mPendingForcedSeamlessRotate != null && !mWaitingForConfig) {
+                win.mPendingForcedSeamlessRotate.finish(win.mToken, win);
+                win.mFinishForcedSeamlessRotateFrameNumber = win.getFrameNumber();
+                win.mPendingForcedSeamlessRotate = null;
+            }
+
             int attrChanges = 0;
             int flagChanges = 0;
             if (attrs != null) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index bee70a0..009f393 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -125,6 +125,7 @@
 import static com.android.server.wm.WindowStateProto.DESTROYING;
 import static com.android.server.wm.WindowStateProto.DISPLAY_FRAME;
 import static com.android.server.wm.WindowStateProto.DISPLAY_ID;
+import static com.android.server.wm.WindowStateProto.FINISHED_FORCED_SEAMLESS_ROTATION_FRAME;
 import static com.android.server.wm.WindowStateProto.FRAME;
 import static com.android.server.wm.WindowStateProto.GIVEN_CONTENT_INSETS;
 import static com.android.server.wm.WindowStateProto.HAS_SURFACE;
@@ -137,6 +138,7 @@
 import static com.android.server.wm.WindowStateProto.OVERSCAN_FRAME;
 import static com.android.server.wm.WindowStateProto.OVERSCAN_INSETS;
 import static com.android.server.wm.WindowStateProto.PARENT_FRAME;
+import static com.android.server.wm.WindowStateProto.PENDING_FORCED_SEAMLESS_ROTATION;
 import static com.android.server.wm.WindowStateProto.REMOVED;
 import static com.android.server.wm.WindowStateProto.REMOVE_ON_EXIT;
 import static com.android.server.wm.WindowStateProto.REQUESTED_HEIGHT;
@@ -150,6 +152,8 @@
 import static com.android.server.wm.WindowStateProto.VISIBLE_FRAME;
 import static com.android.server.wm.WindowStateProto.VISIBLE_INSETS;
 import static com.android.server.wm.WindowStateProto.WINDOW_CONTAINER;
+import static com.android.server.wm.utils.CoordinateTransforms.transformRect;
+import static com.android.server.wm.utils.CoordinateTransforms.transformToRotation;
 
 import android.annotation.CallSuper;
 import android.app.AppOpsManager;
@@ -278,6 +282,14 @@
     private boolean mDragResizing;
     private boolean mDragResizingChangeReported = true;
     private int mResizeMode;
+    /**
+     * Special mode that is intended only for the rounded corner overlay: during rotation
+     * transition, we un-rotate the window token such that the window appears as it did before the
+     * rotation.
+     */
+    final boolean mForceSeamlesslyRotate;
+    ForcedSeamlessRotator mPendingForcedSeamlessRotate;
+    long mFinishForcedSeamlessRotateFrameNumber;
 
     private RemoteCallbackList<IWindowFocusObserver> mFocusCallbacks;
 
@@ -667,6 +679,14 @@
 
     private static final float DEFAULT_DIM_AMOUNT_DEAD_WINDOW = 0.5f;
 
+    void forceSeamlesslyRotateIfAllowed(int oldRotation, int rotation) {
+        if (mForceSeamlesslyRotate) {
+            mPendingForcedSeamlessRotate = new ForcedSeamlessRotator(
+                    oldRotation, rotation, getDisplayInfo());
+            mPendingForcedSeamlessRotate.unrotate(this.mToken);
+        }
+    }
+
     interface PowerManagerWrapper {
         void wakeUp(long time, String reason);
 
@@ -713,6 +733,7 @@
         mSeq = seq;
         mEnforceSizeCompat = (mAttrs.privateFlags & PRIVATE_FLAG_COMPATIBLE_WINDOW) != 0;
         mPowerManagerWrapper = powerManagerWrapper;
+        mForceSeamlesslyRotate = token.mRoundedCornerOverlay;
         if (localLOGV) Slog.v(
             TAG, "Window " + this + " client=" + c.asBinder()
             + " token=" + token + " (" + mAttrs.token + ")" + " params=" + a);
@@ -1811,7 +1832,8 @@
                 && (mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
                 && !isDragResizing() && !adjustedForMinimizedDockOrIme
                 && getWindowConfiguration().hasMovementAnimations()
-                && !mWinAnimator.mLastHidden) {
+                && !mWinAnimator.mLastHidden
+                && !mSeamlesslyRotated) {
             startMoveAnimation(left, top);
         }
 
@@ -3286,6 +3308,11 @@
         proto.write(REMOVED, mRemoved);
         proto.write(IS_ON_SCREEN, isOnScreen());
         proto.write(IS_VISIBLE, isVisible());
+        if (mForceSeamlesslyRotate) {
+            proto.write(PENDING_FORCED_SEAMLESS_ROTATION, mPendingForcedSeamlessRotate != null);
+            proto.write(FINISHED_FORCED_SEAMLESS_ROTATION_FRAME,
+                    mFinishForcedSeamlessRotateFrameNumber);
+        }
         proto.end(token);
     }
 
@@ -3462,6 +3489,16 @@
             pw.print(prefix); pw.print("mLastFreezeDuration=");
                     TimeUtils.formatDuration(mLastFreezeDuration, pw); pw.println();
         }
+        if (mForceSeamlesslyRotate) {
+            pw.print(prefix); pw.print("forceSeamlesslyRotate: pending=");
+            if (mPendingForcedSeamlessRotate != null) {
+                mPendingForcedSeamlessRotate.dump(pw);
+            } else {
+                pw.print("null");
+            }
+            pw.print(" finishedFrameNumber="); pw.print(mFinishForcedSeamlessRotateFrameNumber);
+            pw.println();
+        }
         if (mHScale != 1 || mVScale != 1) {
             pw.print(prefix); pw.print("mHScale="); pw.print(mHScale);
                     pw.print(" mVScale="); pw.println(mVScale);
@@ -4697,7 +4734,10 @@
 
         transformFrameToSurfacePosition(mFrame.left, mFrame.top, mSurfacePosition);
 
-        if (!mSurfaceAnimator.hasLeash() && !mLastSurfacePosition.equals(mSurfacePosition)) {
+        // Freeze position while we're unrotated, so the surface remains at the position it was
+        // prior to the rotation.
+        if (!mSurfaceAnimator.hasLeash() && mPendingForcedSeamlessRotate == null &&
+                !mLastSurfacePosition.equals(mSurfacePosition)) {
             t.setPosition(mSurfaceControl, mSurfacePosition.x, mSurfacePosition.y);
             mLastSurfacePosition.set(mSurfacePosition.x, mSurfacePosition.y);
             if (surfaceInsetsChanging() && mWinAnimator.hasSurface()) {
@@ -4850,6 +4890,31 @@
         mFrameNumber = frameNumber;
     }
 
+    @Override
+    void seamlesslyRotate(Transaction t, int oldRotation, int newRotation) {
+        // Invisible windows, the wallpaper, and force seamlessly rotated windows do not participate
+        // in the regular seamless rotation animation.
+        if (!isVisibleNow() || mIsWallpaper || mForceSeamlesslyRotate) {
+            return;
+        }
+        final Matrix transform = mTmpMatrix;
+
+        mService.markForSeamlessRotation(this, true);
+
+        // We rotated the screen, but have not performed a new layout pass yet. In the mean time,
+        // we recompute the coordinates of mFrame in the new orientation, so the surface can be
+        // properly placed.
+        transformToRotation(oldRotation, newRotation, getDisplayInfo(), transform);
+        transformRect(transform, mFrame, null /* tmpRectF */);
+
+        updateSurfacePosition(t);
+        mWinAnimator.seamlesslyRotate(t, oldRotation, newRotation);
+
+        // Dispatch to children only after mFrame has been updated, as it's needed in the
+        // child's updateSurfacePosition.
+        super.seamlesslyRotate(t, oldRotation, newRotation);
+    }
+
     private final class MoveAnimationSpec implements AnimationSpec {
 
         private final long mDuration;
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 3eef125..a05e04d 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -41,18 +41,18 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
 import static com.android.server.wm.WindowManagerService.logWithStack;
-import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
 import static com.android.server.wm.WindowStateAnimatorProto.DRAW_STATE;
 import static com.android.server.wm.WindowStateAnimatorProto.LAST_CLIP_RECT;
 import static com.android.server.wm.WindowStateAnimatorProto.SURFACE;
 import static com.android.server.wm.WindowStateAnimatorProto.SYSTEM_DECOR_RECT;
+import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
+import static com.android.server.wm.utils.CoordinateTransforms.transformToRotation;
 
 import android.content.Context;
 import android.graphics.Matrix;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.Rect;
-import android.graphics.RectF;
 import android.graphics.Region;
 import android.os.Debug;
 import android.os.Trace;
@@ -366,7 +366,8 @@
         mDrawState = READY_TO_SHOW;
         boolean result = false;
         final AppWindowToken atoken = mWin.mAppToken;
-        if (atoken == null || atoken.allDrawn || mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
+        if (atoken == null || atoken.canShowWindows()
+                || mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
             result = mWin.performShowLocked();
         }
         return result;
@@ -685,8 +686,11 @@
         final int displayId = mWin.getDisplayId();
         final ScreenRotationAnimation screenRotationAnimation =
                 mAnimator.getScreenRotationAnimationLocked(displayId);
-        final boolean screenAnimation =
-                screenRotationAnimation != null && screenRotationAnimation.isAnimating();
+        final boolean windowParticipatesInScreenRotationAnimation =
+                !mWin.mForceSeamlesslyRotate;
+        final boolean screenAnimation = screenRotationAnimation != null
+                && screenRotationAnimation.isAnimating()
+                && windowParticipatesInScreenRotationAnimation;
 
         if (screenAnimation) {
             // cache often used attributes locally
@@ -798,6 +802,13 @@
             return false;
         }
 
+        // During forced seamless rotation, the surface bounds get updated with the crop in the
+        // new rotation, which is not compatible with showing the surface in the old rotation.
+        // To work around that we disable cropping for such windows, as it is not necessary anyways.
+        if (w.mForceSeamlesslyRotate) {
+            return false;
+        }
+
         // If we're animating, the wallpaper should only
         // be updated at the end of the animation.
         if (w.mAttrs.type == TYPE_WALLPAPER) {
@@ -1492,40 +1503,14 @@
         }
     }
 
-    void seamlesslyRotateWindow(SurfaceControl.Transaction t,
-            int oldRotation, int newRotation) {
+    void seamlesslyRotate(SurfaceControl.Transaction t, int oldRotation, int newRotation) {
         final WindowState w = mWin;
-        if (!w.isVisibleNow() || w.mIsWallpaper) {
-            return;
-        }
 
-        final Rect cropRect = mService.mTmpRect;
-        final Rect displayRect = mService.mTmpRect2;
-        final RectF frameRect = mService.mTmpRectF;
+        // We rotated the screen, but have not received a new buffer with the correct size yet. In
+        // the mean time, we rotate the buffer we have to the new orientation.
         final Matrix transform = mService.mTmpTransform;
-
-        final float x = w.mFrame.left;
-        final float y = w.mFrame.top;
-        final float width = w.mFrame.width();
-        final float height = w.mFrame.height();
-
-        mService.getDefaultDisplayContentLocked().getBounds(displayRect);
-        final float displayWidth = displayRect.width();
-        final float displayHeight = displayRect.height();
-
-        // Compute a transform matrix to undo the coordinate space transformation,
-        // and present the window at the same physical position it previously occupied.
-        final int deltaRotation = DisplayContent.deltaRotation(newRotation, oldRotation);
-        DisplayContent.createRotationMatrix(deltaRotation, x, y, displayWidth, displayHeight,
+        transformToRotation(oldRotation, newRotation, w.mFrame.width(), w.mFrame.height(),
                 transform);
-
-        // We just need to apply a rotation matrix to the window. For example
-        // if we have a portrait window and rotate to landscape, the window is still portrait
-        // and now extends off the bottom of the screen (and only halfway across). Essentially we
-        // apply a transform to display the current buffer at it's old position
-        // (in the new coordinate space). We then freeze layer updates until the resize
-        // occurs, at which point we undo, them.
-        mService.markForSeamlessRotation(w, true);
         transform.getValues(mService.mTmpFloats);
 
         float DsDx = mService.mTmpFloats[Matrix.MSCALE_X];
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index b97460a..e411c0a 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -270,12 +270,6 @@
         dc.reParentWindowToken(this);
         mDisplayContent = dc;
 
-        // The rounded corner overlay should not be rotated. We ensure that by moving it outside
-        // the windowing layer.
-        if (mRoundedCornerOverlay) {
-            mDisplayContent.reparentToOverlay(mPendingTransaction, mSurfaceControl);
-        }
-
         // TODO(b/36740756): One day this should perhaps be hooked
         // up with goodToGo, so we don't move a window
         // to another display before the window behind
diff --git a/services/core/java/com/android/server/wm/utils/CoordinateTransforms.java b/services/core/java/com/android/server/wm/utils/CoordinateTransforms.java
index 09d7b5d..a2f37a5 100644
--- a/services/core/java/com/android/server/wm/utils/CoordinateTransforms.java
+++ b/services/core/java/com/android/server/wm/utils/CoordinateTransforms.java
@@ -22,7 +22,11 @@
 import static android.view.Surface.ROTATION_90;
 
 import android.annotation.Dimension;
+import android.annotation.Nullable;
 import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.view.DisplayInfo;
 import android.view.Surface.Rotation;
 
 public class CoordinateTransforms {
@@ -59,4 +63,93 @@
                 throw new IllegalArgumentException("Unknown rotation: " + rotation);
         }
     }
+
+    /**
+     * Sets a matrix such that given a rotation, it transforms that rotation's logical coordinates
+     * to physical coordinates.
+     *
+     * @param rotation the rotation to which the matrix should transform
+     * @param out      the matrix to be set
+     */
+    public static void transformLogicalToPhysicalCoordinates(@Rotation int rotation,
+            @Dimension int physicalWidth, @Dimension int physicalHeight, Matrix out) {
+        switch (rotation) {
+            case ROTATION_0:
+                out.reset();
+                break;
+            case ROTATION_90:
+                out.setRotate(90);
+                out.preTranslate(0, -physicalWidth);
+                break;
+            case ROTATION_180:
+                out.setRotate(180);
+                out.preTranslate(-physicalWidth, -physicalHeight);
+                break;
+            case ROTATION_270:
+                out.setRotate(270);
+                out.preTranslate(-physicalHeight, 0);
+                break;
+            default:
+                throw new IllegalArgumentException("Unknown rotation: " + rotation);
+        }
+    }
+
+    /**
+     * Sets a matrix such that given a two rotations, that it transforms coordinates given in the
+     * old rotation to coordinates that refer to the same physical location in the new rotation.
+     *
+     * @param oldRotation the rotation to transform from
+     * @param newRotation the rotation to transform to
+     * @param info the display info
+     * @param out a matrix that will be set to the transform
+     */
+    public static void transformToRotation(@Rotation int oldRotation,
+            @Rotation int newRotation, DisplayInfo info, Matrix out) {
+        final boolean flipped = info.rotation == ROTATION_90 || info.rotation == ROTATION_270;
+        final int h = flipped ? info.logicalWidth : info.logicalHeight;
+        final int w = flipped ? info.logicalHeight : info.logicalWidth;
+
+        final Matrix tmp = new Matrix();
+        transformLogicalToPhysicalCoordinates(oldRotation, w, h, out);
+        transformPhysicalToLogicalCoordinates(newRotation, w, h, tmp);
+        out.postConcat(tmp);
+    }
+
+    /**
+     * Sets a matrix such that given a two rotations, that it transforms coordinates given in the
+     * old rotation to coordinates that refer to the same physical location in the new rotation.
+     *
+     * @param oldRotation the rotation to transform from
+     * @param newRotation the rotation to transform to
+     * @param newWidth the width of the area to transform, in the new rotation
+     * @param newHeight the height of the area to transform, in the new rotation
+     * @param out a matrix that will be set to the transform
+     */
+    public static void transformToRotation(@Rotation int oldRotation,
+            @Rotation int newRotation, int newWidth, int newHeight, Matrix out) {
+        final boolean flipped = newRotation == ROTATION_90 || newRotation == ROTATION_270;
+        final int h = flipped ? newWidth : newHeight;
+        final int w = flipped ? newHeight : newWidth;
+
+        final Matrix tmp = new Matrix();
+        transformLogicalToPhysicalCoordinates(oldRotation, w, h, out);
+        transformPhysicalToLogicalCoordinates(newRotation, w, h, tmp);
+        out.postConcat(tmp);
+    }
+
+    /**
+     * Transforms a rect using a transformation matrix
+     *
+     * @param transform the transformation to apply to the rect
+     * @param inOutRect the rect to transform
+     * @param tmp a temporary value, if null the function will allocate its own.
+     */
+    public static void transformRect(Matrix transform, Rect inOutRect, @Nullable RectF tmp) {
+        if (tmp == null) {
+            tmp = new RectF();
+        }
+        tmp.set(inOutRect);
+        transform.mapRect(tmp);
+        inOutRect.set((int) tmp.left, (int) tmp.top, (int) tmp.right, (int) tmp.bottom);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java
index 2c47a94..1d37802 100644
--- a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java
@@ -37,6 +37,7 @@
 import android.graphics.Path;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
+import android.graphics.RectF;
 import android.os.IBinder;
 import android.os.UserHandle;
 import android.support.test.InstrumentationRegistry;
@@ -172,15 +173,14 @@
     }
 
     private static DisplayCutout displayCutoutForRotation(int rotation) {
-        Path p = new Path();
-        p.addRect(DISPLAY_WIDTH / 4, 0, DISPLAY_WIDTH * 3 / 4, DISPLAY_CUTOUT_HEIGHT,
-                Path.Direction.CCW);
+        RectF rectF = new RectF(DISPLAY_WIDTH / 4, 0, DISPLAY_WIDTH * 3 / 4, DISPLAY_CUTOUT_HEIGHT);
 
         Matrix m = new Matrix();
         transformPhysicalToLogicalCoordinates(rotation, DISPLAY_WIDTH, DISPLAY_HEIGHT, m);
-        p.transform(m);
+        m.mapRect(rectF);
 
-        return DisplayCutout.fromBounds(p);
+        return DisplayCutout.fromBoundingRect((int) rectF.left, (int) rectF.top,
+                (int) rectF.right, (int) rectF.bottom);
     }
 
     static class TestContextWrapper extends ContextWrapper {
diff --git a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
index edac8a5..79e9bb4 100644
--- a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
@@ -20,24 +20,23 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.animation.AnimationHandler;
 import android.animation.AnimationHandler.AnimationFrameCallbackProvider;
 import android.animation.ValueAnimator;
 import android.graphics.Matrix;
 import android.graphics.Point;
+import android.os.PowerManagerInternal;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.FlakyTest;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
-import android.util.Log;
 import android.view.Choreographer;
 import android.view.Choreographer.FrameCallback;
 import android.view.SurfaceControl;
@@ -46,7 +45,6 @@
 import android.view.animation.TranslateAnimation;
 
 import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
-import com.android.server.wm.SurfaceAnimationRunner.AnimatorFactory;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -71,6 +69,7 @@
     @Mock SurfaceControl mMockSurface;
     @Mock Transaction mMockTransaction;
     @Mock AnimationSpec mMockAnimationSpec;
+    @Mock PowerManagerInternal mMockPowerManager;
     @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
 
     private SurfaceAnimationRunner mSurfaceAnimationRunner;
@@ -81,7 +80,7 @@
         super.setUp();
         mFinishCallbackLatch = new CountDownLatch(1);
         mSurfaceAnimationRunner = new SurfaceAnimationRunner(null /* callbackProvider */, null,
-                mMockTransaction);
+                mMockTransaction, mMockPowerManager);
     }
 
     private void finishedCallback() {
@@ -113,7 +112,7 @@
     @Test
     public void testCancel_notStarted() throws Exception {
         mSurfaceAnimationRunner = new SurfaceAnimationRunner(new NoOpFrameCallbackProvider(), null,
-                mMockTransaction);
+                mMockTransaction, mMockPowerManager);
         mSurfaceAnimationRunner
                 .startAnimation(createTranslateAnimation(), mMockSurface, mMockTransaction,
                 this::finishedCallback);
@@ -126,7 +125,7 @@
     @Test
     public void testCancel_running() throws Exception {
         mSurfaceAnimationRunner = new SurfaceAnimationRunner(new NoOpFrameCallbackProvider(), null,
-                mMockTransaction);
+                mMockTransaction, mMockPowerManager);
         mSurfaceAnimationRunner.startAnimation(createTranslateAnimation(), mMockSurface,
                 mMockTransaction, this::finishedCallback);
         waitUntilNextFrame();
@@ -156,7 +155,7 @@
                     listener.onAnimationUpdate(animation);
                 });
             }
-        }, mMockTransaction);
+        }, mMockTransaction, mMockPowerManager);
         when(mMockAnimationSpec.getDuration()).thenReturn(200L);
         mSurfaceAnimationRunner.startAnimation(mMockAnimationSpec, mMockSurface, mMockTransaction,
                 this::finishedCallback);
@@ -184,6 +183,19 @@
         assertFinishCallbackCalled();
     }
 
+    @Test
+    public void testPowerHint() throws Exception {
+        mSurfaceAnimationRunner = new SurfaceAnimationRunner(new NoOpFrameCallbackProvider(), null,
+                mMockTransaction, mMockPowerManager);
+        mSurfaceAnimationRunner.startAnimation(createTranslateAnimation(), mMockSurface,
+                mMockTransaction, this::finishedCallback);
+        waitUntilNextFrame();
+
+        // TODO: For some reason we don't have access to PowerHint definition from the tests. For
+        // now let's just verify that we got some kind of hint.
+        verify(mMockPowerManager).powerHint(anyInt(), anyInt());
+    }
+
     private void waitUntilNextFrame() throws Exception {
         final CountDownLatch latch = new CountDownLatch(1);
         mSurfaceAnimationRunner.mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT,
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
index 85e846d..9f113ad 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
@@ -16,6 +16,8 @@
 
 package com.android.server.wm;
 
+import android.graphics.Rect;
+import android.view.SurfaceControl;
 import android.view.WindowManager;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -29,6 +31,8 @@
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.hardware.camera2.params.OutputConfiguration.ROTATION_90;
+import static android.view.Surface.ROTATION_0;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
@@ -48,8 +52,10 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.spy;
@@ -349,6 +355,32 @@
         assertThat(app.getDisplayId(), is(mDisplayContent.getDisplayId()));
     }
 
+    @Test
+    public void testSeamlesslyRotateWindow() {
+        final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+        final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
+
+        app.mHasSurface = true;
+        app.mSurfaceControl = mock(SurfaceControl.class);
+        app.mWinAnimator.mSurfaceController = mock(WindowSurfaceController.class);
+        try {
+            app.mFrame.set(10, 20, 60, 80);
+
+            app.seamlesslyRotate(t, ROTATION_0, ROTATION_90);
+
+            assertTrue(app.mSeamlesslyRotated);
+            assertEquals(new Rect(20, mDisplayInfo.logicalWidth - 60,
+                    80, mDisplayInfo.logicalWidth - 10), app.mFrame);
+
+            verify(t).setPosition(app.mSurfaceControl, app.mFrame.left, app.mFrame.top);
+            verify(app.mWinAnimator.mSurfaceController).setPosition(t, 0, 50, false);
+            verify(app.mWinAnimator.mSurfaceController).setMatrix(t, 0, -1, 1, 0, false);
+        } finally {
+            app.mSurfaceControl = null;
+            app.mHasSurface = false;
+        }
+    }
+
     private void testPrepareWindowToDisplayDuringRelayout(boolean wasVisible) {
         reset(mPowerManagerWrapper);
         final WindowState root = createWindow(null, TYPE_APPLICATION, "root");
diff --git a/services/tests/servicestests/src/com/android/server/wm/utils/CoordinateTransformsTest.java b/services/tests/servicestests/src/com/android/server/wm/utils/CoordinateTransformsTest.java
index 40a10e0..f82b012 100644
--- a/services/tests/servicestests/src/com/android/server/wm/utils/CoordinateTransformsTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/utils/CoordinateTransformsTest.java
@@ -21,14 +21,19 @@
 import static android.view.Surface.ROTATION_270;
 import static android.view.Surface.ROTATION_90;
 
+import static com.android.server.wm.utils.CoordinateTransforms.transformLogicalToPhysicalCoordinates;
 import static com.android.server.wm.utils.CoordinateTransforms.transformPhysicalToLogicalCoordinates;
 
+
+import static com.android.server.wm.utils.CoordinateTransforms.transformToRotation;
+
 import static org.hamcrest.Matchers.is;
 import static org.junit.Assert.*;
 
 import android.graphics.Matrix;
 import android.graphics.Point;
 import android.graphics.PointF;
+import android.view.DisplayInfo;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -41,6 +46,7 @@
     private static final int H = 400;
 
     private final Matrix mMatrix = new Matrix();
+    private final Matrix mMatrix2 = new Matrix();
 
     @Rule
     public final ErrorCollector mErrorCollector = new ErrorCollector();
@@ -48,39 +54,140 @@
     @Before
     public void setUp() throws Exception {
         mMatrix.setTranslate(0xdeadbeef, 0xdeadbeef);
+        mMatrix2.setTranslate(0xbeefdead, 0xbeefdead);
     }
 
     @Test
-    public void transformPhysicalToLogicalCoordinates_rot0() throws Exception {
+    public void transformPhysicalToLogicalCoordinates_rot0() {
         transformPhysicalToLogicalCoordinates(ROTATION_0, W, H, mMatrix);
         assertThat(mMatrix, is(Matrix.IDENTITY_MATRIX));
     }
 
     @Test
-    public void transformPhysicalToLogicalCoordinates_rot90() throws Exception {
+    public void transformPhysicalToLogicalCoordinates_rot90() {
         transformPhysicalToLogicalCoordinates(ROTATION_90, W, H, mMatrix);
 
-        checkDevicePoint(0, 0).mapsToLogicalPoint(0, W);
-        checkDevicePoint(W, H).mapsToLogicalPoint(H, 0);
+        checkPoint(0, 0).transformsTo(0, W);
+        checkPoint(W, H).transformsTo(H, 0);
     }
 
     @Test
-    public void transformPhysicalToLogicalCoordinates_rot180() throws Exception {
+    public void transformPhysicalToLogicalCoordinates_rot180() {
         transformPhysicalToLogicalCoordinates(ROTATION_180, W, H, mMatrix);
 
-        checkDevicePoint(0, 0).mapsToLogicalPoint(W, H);
-        checkDevicePoint(W, H).mapsToLogicalPoint(0, 0);
+        checkPoint(0, 0).transformsTo(W, H);
+        checkPoint(W, H).transformsTo(0, 0);
     }
 
     @Test
-    public void transformPhysicalToLogicalCoordinates_rot270() throws Exception {
+    public void transformPhysicalToLogicalCoordinates_rot270() {
         transformPhysicalToLogicalCoordinates(ROTATION_270, W, H, mMatrix);
 
-        checkDevicePoint(0, 0).mapsToLogicalPoint(H, 0);
-        checkDevicePoint(W, H).mapsToLogicalPoint(0, W);
+        checkPoint(0, 0).transformsTo(H, 0);
+        checkPoint(W, H).transformsTo(0, W);
     }
 
-    private DevicePointAssertable checkDevicePoint(int x, int y) {
+    @Test
+    public void transformLogicalToPhysicalCoordinates_rot0() {
+        transformLogicalToPhysicalCoordinates(ROTATION_0, W, H, mMatrix);
+        assertThat(mMatrix, is(Matrix.IDENTITY_MATRIX));
+    }
+
+    @Test
+    public void transformLogicalToPhysicalCoordinates_rot90() {
+        transformLogicalToPhysicalCoordinates(ROTATION_90, W, H, mMatrix);
+
+        checkPoint(0, W).transformsTo(0, 0);
+        checkPoint(H, 0).transformsTo(W, H);
+    }
+
+    @Test
+    public void transformLogicalToPhysicalCoordinates_rot180() {
+        transformLogicalToPhysicalCoordinates(ROTATION_180, W, H, mMatrix);
+
+        checkPoint(W, H).transformsTo(0, 0);
+        checkPoint(0, 0).transformsTo(W, H);
+    }
+
+    @Test
+    public void transformLogicalToPhysicalCoordinates_rot270() {
+        transformLogicalToPhysicalCoordinates(ROTATION_270, W, H, mMatrix);
+
+        checkPoint(H, 0).transformsTo(0, 0);
+        checkPoint(0, W).transformsTo(W, H);
+    }
+
+    @Test
+    public void transformLogicalToPhysicalCoordinatesIsInverse_rot0() {
+        transformLogicalToPhysicalCoordinates(ROTATION_0, W, H, mMatrix);
+        transformPhysicalToLogicalCoordinates(ROTATION_0, W, H, mMatrix2);
+
+        assertMatricesAreInverses(mMatrix, mMatrix2);
+    }
+
+    @Test
+    public void transformLogicalToPhysicalCoordinatesIsInverse_rot90() {
+        transformLogicalToPhysicalCoordinates(ROTATION_90, W, H, mMatrix);
+        transformPhysicalToLogicalCoordinates(ROTATION_90, W, H, mMatrix2);
+
+        assertMatricesAreInverses(mMatrix, mMatrix2);
+    }
+
+    @Test
+    public void transformLogicalToPhysicalCoordinatesIsInverse_rot180() {
+        transformLogicalToPhysicalCoordinates(ROTATION_180, W, H, mMatrix);
+        transformPhysicalToLogicalCoordinates(ROTATION_180, W, H, mMatrix2);
+
+        assertMatricesAreInverses(mMatrix, mMatrix2);
+    }
+
+    @Test
+    public void transformLogicalToPhysicalCoordinatesIsInverse_rot270() {
+        transformLogicalToPhysicalCoordinates(ROTATION_270, W, H, mMatrix);
+        transformPhysicalToLogicalCoordinates(ROTATION_270, W, H, mMatrix2);
+
+        assertMatricesAreInverses(mMatrix, mMatrix2);
+    }
+
+    @Test
+    public void transformBetweenRotations_rot180_rot270() {
+        // W,H are flipped, because they need to be given in the new orientation, i.e. ROT_270.
+        transformToRotation(ROTATION_180, ROTATION_270, H, W, mMatrix);
+
+        checkPoint(0, 0).transformsTo(0, W);
+        checkPoint(W, H).transformsTo(H, 0);
+    }
+
+    @Test
+    public void transformBetweenRotations_rot90_rot0() {
+        transformToRotation(ROTATION_180, ROTATION_270, W, H, mMatrix);
+
+        checkPoint(0, 0).transformsTo(0, H);
+        // H,W is bottom right in ROT_90
+        checkPoint(H, W).transformsTo(W, 0);
+    }
+
+    @Test
+    public void transformBetweenRotations_displayInfo() {
+        final DisplayInfo di = new DisplayInfo();
+        di.rotation = ROTATION_90;
+        di.logicalWidth = H;  // dimensions are flipped in ROT_90
+        di.logicalHeight = W;
+        transformToRotation(ROTATION_180, ROTATION_270, di, mMatrix);
+
+        // W,H are flipped, because they need to be given in the new orientation, i.e. ROT_270.
+        transformToRotation(ROTATION_180, ROTATION_270, H, W, mMatrix2);
+
+        assertEquals(mMatrix2, mMatrix);
+    }
+
+    private void assertMatricesAreInverses(Matrix matrix, Matrix matrix2) {
+        final Matrix concat = new Matrix();
+        concat.setConcat(matrix, matrix2);
+        assertTrue("expected identity, but was: " + concat, concat.isIdentity());
+    }
+
+    private TransformPointAssertable checkPoint(int x, int y) {
         final Point devicePoint = new Point(x, y);
         final float[] fs = new float[] {x, y};
         mMatrix.mapPoints(fs);
@@ -92,7 +199,7 @@
         };
     }
 
-    public interface DevicePointAssertable {
-        void mapsToLogicalPoint(int x, int y);
+    public interface TransformPointAssertable {
+        void transformsTo(int x, int y);
     }
 }
\ No newline at end of file
diff --git a/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java b/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java
index 345c1d7..eec852b 100644
--- a/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java
+++ b/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java
@@ -31,6 +31,7 @@
 
     protected static final String PKG_N_MR1 = "com.example.n_mr1";
     protected static final String PKG_O = "com.example.o";
+    protected static final String PKG_P = "com.example.p";
 
     @Rule
     public final TestableContext mContext =
@@ -57,6 +58,8 @@
                             return Build.VERSION_CODES.N_MR1;
                         case PKG_O:
                             return Build.VERSION_CODES.O;
+                        case PKG_P:
+                            return Build.VERSION_CODES.P;
                         default:
                             return Build.VERSION_CODES.CUR_DEVELOPMENT;
                     }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 7809999..bdba3d5 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -19,7 +19,9 @@
 import static android.app.Notification.GROUP_ALERT_CHILDREN;
 import static android.app.Notification.GROUP_ALERT_SUMMARY;
 import static android.app.NotificationManager.IMPORTANCE_HIGH;
+import static android.app.NotificationManager.IMPORTANCE_LOW;
 import static android.app.NotificationManager.IMPORTANCE_MIN;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
 
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNull;
@@ -149,6 +151,9 @@
         mService.setFallbackVibrationPattern(FALLBACK_VIBRATION_PATTERN);
         mService.setUsageStats(mUsageStats);
         mService.setAccessibilityManager(accessibilityManager);
+        mService.mScreenOn = false;
+        mService.mInCall = false;
+        mService.mNotificationPulseEnabled = true;
     }
 
     //
@@ -216,8 +221,13 @@
     }
 
     private NotificationRecord getLightsNotification() {
+        return getNotificationRecord(mId, false /* insistent */, false /* once */,
+                false /* noisy */, false /* buzzy*/, true /* lights */);
+    }
+
+    private NotificationRecord getLightsOnceNotification() {
         return getNotificationRecord(mId, false /* insistent */, true /* once */,
-                false /* noisy */, true /* buzzy*/, true /* lights */);
+                false /* noisy */, false /* buzzy*/, true /* lights */);
     }
 
     private NotificationRecord getCustomLightsNotification() {
@@ -244,6 +254,12 @@
                 groupKey, groupAlertBehavior, false);
     }
 
+    private NotificationRecord getLightsNotificationRecord(String groupKey,
+            int groupAlertBehavior) {
+        return getNotificationRecord(mId, false, false, false, false, true /*lights*/, true, true,
+                true, groupKey, groupAlertBehavior, false);
+    }
+
     private NotificationRecord getNotificationRecord(int id, boolean insistent, boolean once,
             boolean noisy, boolean buzzy, boolean lights, boolean defaultVibration,
             boolean defaultSound, boolean defaultLights, String groupKey, int groupAlertBehavior,
@@ -369,6 +385,10 @@
         verify(mVibrator, never()).cancel();
     }
 
+    private void verifyNeverLights() {
+        verify(mLight, never()).setFlashing(anyInt(), anyInt(), anyInt(), anyInt());
+    }
+
     private void verifyLights() {
         verify(mLight, times(1)).setFlashing(anyInt(), anyInt(), anyInt(), anyInt());
     }
@@ -712,7 +732,8 @@
         mService.buzzBeepBlinkLocked(summary);
 
         verifyBeepLooped();
-        assertTrue(summary.isInterruptive());
+        // summaries are never interruptive for notification counts
+        assertFalse(summary.isInterruptive());
     }
 
     @Test
@@ -990,6 +1011,156 @@
         verify(mAccessibilityService, times(1)).sendAccessibilityEvent(any(), anyInt());
     }
 
+    @Test
+    public void testLightsScreenOn() {
+        mService.mScreenOn = true;
+        NotificationRecord r = getLightsNotification();
+        mService.buzzBeepBlinkLocked(r);
+        verifyNeverLights();
+        assertFalse(r.isInterruptive());
+    }
+
+    @Test
+    public void testLightsInCall() {
+        mService.mInCall = true;
+        NotificationRecord r = getLightsNotification();
+        mService.buzzBeepBlinkLocked(r);
+        verifyNeverLights();
+        assertFalse(r.isInterruptive());
+    }
+
+    @Test
+    public void testLightsSilentUpdate() {
+        NotificationRecord r = getLightsOnceNotification();
+        mService.buzzBeepBlinkLocked(r);
+        verifyLights();
+        assertTrue(r.isInterruptive());
+
+        r = getLightsOnceNotification();
+        r.isUpdate = true;
+        mService.buzzBeepBlinkLocked(r);
+        // checks that lights happened once, i.e. this new call didn't trigger them again
+        verifyLights();
+        assertFalse(r.isInterruptive());
+    }
+
+    @Test
+    public void testLightsUnimportant() {
+        NotificationRecord r = getLightsNotification();
+        r.setImportance(IMPORTANCE_LOW, "testing");
+        mService.buzzBeepBlinkLocked(r);
+        verifyNeverLights();
+        assertFalse(r.isInterruptive());
+    }
+
+    @Test
+    public void testLightsNoLights() {
+        NotificationRecord r = getQuietNotification();
+        mService.buzzBeepBlinkLocked(r);
+        verifyNeverLights();
+        assertFalse(r.isInterruptive());
+    }
+
+    @Test
+    public void testLightsNoLightOnDevice() {
+        mService.mHasLight = false;
+        NotificationRecord r = getLightsNotification();
+        mService.buzzBeepBlinkLocked(r);
+        verifyNeverLights();
+        assertFalse(r.isInterruptive());
+    }
+
+    @Test
+    public void testLightsLightsOffGlobally() {
+        mService.mNotificationPulseEnabled = false;
+        NotificationRecord r = getLightsNotification();
+        mService.buzzBeepBlinkLocked(r);
+        verifyNeverLights();
+        assertFalse(r.isInterruptive());
+    }
+
+    @Test
+    public void testLightsDndIntercepted() {
+        NotificationRecord r = getLightsNotification();
+        r.setSuppressedVisualEffects(SUPPRESSED_EFFECT_LIGHTS);
+        mService.buzzBeepBlinkLocked(r);
+        verifyNeverLights();
+        assertFalse(r.isInterruptive());
+    }
+
+    @Test
+    public void testGroupAlertSummaryNoLightsChild() {
+        NotificationRecord child = getLightsNotificationRecord("a", GROUP_ALERT_SUMMARY);
+
+        mService.buzzBeepBlinkLocked(child);
+
+        verifyNeverLights();
+        assertFalse(child.isInterruptive());
+    }
+
+    @Test
+    public void testGroupAlertSummaryLightsSummary() {
+        NotificationRecord summary = getLightsNotificationRecord("a", GROUP_ALERT_SUMMARY);
+        summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY;
+
+        mService.buzzBeepBlinkLocked(summary);
+
+        verifyLights();
+        // summaries should never count for interruptiveness counts
+        assertFalse(summary.isInterruptive());
+    }
+
+    @Test
+    public void testGroupAlertSummaryLightsNonGroupChild() {
+        NotificationRecord nonGroup = getLightsNotificationRecord(null, GROUP_ALERT_SUMMARY);
+
+        mService.buzzBeepBlinkLocked(nonGroup);
+
+        verifyLights();
+        assertTrue(nonGroup.isInterruptive());
+    }
+
+    @Test
+    public void testGroupAlertChildNoLightsSummary() {
+        NotificationRecord summary = getLightsNotificationRecord("a", GROUP_ALERT_CHILDREN);
+        summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY;
+
+        mService.buzzBeepBlinkLocked(summary);
+
+        verifyNeverLights();
+        assertFalse(summary.isInterruptive());
+    }
+
+    @Test
+    public void testGroupAlertChildLightsChild() {
+        NotificationRecord child = getLightsNotificationRecord("a", GROUP_ALERT_CHILDREN);
+
+        mService.buzzBeepBlinkLocked(child);
+
+        verifyLights();
+        assertTrue(child.isInterruptive());
+    }
+
+    @Test
+    public void testGroupAlertChildLightsNonGroupSummary() {
+        NotificationRecord nonGroup = getLightsNotificationRecord(null, GROUP_ALERT_CHILDREN);
+
+        mService.buzzBeepBlinkLocked(nonGroup);
+
+        verifyLights();
+        assertTrue(nonGroup.isInterruptive());
+    }
+
+    @Test
+    public void testGroupAlertAllLightsGroup() {
+        NotificationRecord group = getLightsNotificationRecord("a", GROUP_ALERT_ALL);
+
+        mService.buzzBeepBlinkLocked(group);
+
+        verifyLights();
+        assertTrue(group.isInterruptive());
+    }
+
     static class VibrateRepeatMatcher implements ArgumentMatcher<VibrationEffect> {
         private final int mRepeatIndex;
 
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index a408438..cdbf3c6 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -2942,6 +2942,20 @@
     }
 
     @Test
+    public void testVisualDifference_summaryNewNotification() {
+        Notification.Builder nb2 = new Notification.Builder(mContext, "")
+                .setGroup("bananas")
+                .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
+                .setContentText("bar");
+        StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
+                nb2.build(), new UserHandle(mUid), null, 0);
+        NotificationRecord r2 =
+                new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
+
+        assertFalse(mService.isVisuallyInterruptive(null, r2));
+    }
+
+    @Test
     public void testHideAndUnhideNotificationsOnSuspendedPackageBroadcast() {
         // post 2 notification from this package
         final NotificationRecord notif1 = generateNotificationRecord(
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
index c1868e7..e286991 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
@@ -29,9 +29,17 @@
 import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
 
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.app.ActivityManager;
+import android.app.IActivityManager;
 import android.app.Notification;
 import android.app.Notification.Builder;
 import android.app.NotificationChannel;
@@ -44,12 +52,14 @@
 import android.metrics.LogMaker;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.notification.Adjustment;
 import android.service.notification.StatusBarNotification;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Slog;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.server.UiServiceTestCase;
@@ -58,7 +68,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
 import java.util.Objects;
@@ -67,7 +76,7 @@
 @RunWith(AndroidJUnit4.class)
 public class NotificationRecordTest extends UiServiceTestCase {
 
-    private final Context mMockContext = Mockito.mock(Context.class);
+    private final Context mMockContext = mock(Context.class);
     @Mock PackageManager mPm;
 
     private final String pkg = PKG_N_MR1;
@@ -93,8 +102,6 @@
             new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "test",
                     NotificationManager.IMPORTANCE_UNSPECIFIED);
     private android.os.UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser());
-    final ApplicationInfo legacy = new ApplicationInfo();
-    final ApplicationInfo upgrade = new ApplicationInfo();
 
     private static final long[] CUSTOM_VIBRATION = new long[] {
             300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400,
@@ -115,12 +122,12 @@
 
         when(mMockContext.getResources()).thenReturn(getContext().getResources());
         when(mMockContext.getPackageManager()).thenReturn(mPm);
+        when(mMockContext.getApplicationInfo()).thenReturn(new ApplicationInfo());
     }
 
-    private StatusBarNotification getNotification(boolean preO, boolean noisy, boolean defaultSound,
+    private StatusBarNotification getNotification(String pkg, boolean noisy, boolean defaultSound,
             boolean buzzy, boolean defaultVibration, boolean lights, boolean defaultLights,
             String group) {
-        when(mMockContext.getApplicationInfo()).thenReturn(preO ? legacy : upgrade);
         final Builder builder = new Builder(mMockContext)
                 .setContentTitle("foo")
                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
@@ -159,22 +166,14 @@
         }
 
         builder.setDefaults(defaults);
-        if (!preO) {
-            builder.setChannelId(channelId);
-        }
+        builder.setChannelId(channelId);
 
         if(group != null) {
             builder.setGroup(group);
         }
 
         Notification n = builder.build();
-        if (preO) {
-            return new StatusBarNotification(pkg, pkg, id1, tag1, uid, uid, n,
-                    mUser, null, uid);
-        } else {
-            return new StatusBarNotification(pkg2, pkg2, id2, tag2, uid2, uid2, n,
-                    mUser, null, uid2);
-        }
+        return new StatusBarNotification(pkg, pkg, id1, tag1, uid, uid, n, mUser, null, uid);
     }
 
     //
@@ -185,7 +184,7 @@
     public void testSound_default_preUpgradeUsesNotification() throws Exception {
         defaultChannel.setSound(null, null);
         // pre upgrade, default sound.
-        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, null /* group */);
 
@@ -198,7 +197,7 @@
     public void testSound_custom_preUpgradeUsesNotification() throws Exception {
         defaultChannel.setSound(null, null);
         // pre upgrade, custom sound.
-        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */,
                 false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, null /* group */);
 
@@ -212,7 +211,7 @@
         defaultChannel.setSound(CUSTOM_SOUND, CUSTOM_ATTRIBUTES);
         defaultChannel.lockFields(NotificationChannel.USER_LOCKED_SOUND);
         // pre upgrade, default sound.
-        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, null /* group */);
 
@@ -224,7 +223,7 @@
     @Test
     public void testSound_noSound_preUpgrade() throws Exception {
         // pre upgrade, default sound.
-        StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_N_MR1, false /* noisy */,
                 false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, null /* group */);
 
@@ -237,7 +236,7 @@
     public void testSound_default_upgradeUsesChannel() throws Exception {
         channel.setSound(CUSTOM_SOUND, CUSTOM_ATTRIBUTES);
         // post upgrade, default sound.
-        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, null /* group */);
 
@@ -250,7 +249,7 @@
     public void testVibration_default_preUpgradeUsesNotification() throws Exception {
         defaultChannel.enableVibration(false);
         // pre upgrade, default vibration.
-        StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_N_MR1, false /* noisy */,
                 false /* defaultSound */, true /* buzzy */, true /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, null /* group */);
 
@@ -262,7 +261,7 @@
     public void testVibration_custom_preUpgradeUsesNotification() throws Exception {
         defaultChannel.enableVibration(false);
         // pre upgrade, custom vibration.
-        StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_N_MR1, false /* noisy */,
                 false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, null /* group */);
 
@@ -275,7 +274,7 @@
         defaultChannel.enableVibration(true);
         defaultChannel.lockFields(NotificationChannel.USER_LOCKED_VIBRATION);
         // pre upgrade, custom vibration.
-        StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_N_MR1, false /* noisy */,
                 false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, null /* group */);
 
@@ -287,7 +286,7 @@
     public void testVibration_custom_upgradeUsesChannel() throws Exception {
         channel.enableVibration(true);
         // post upgrade, custom vibration.
-        StatusBarNotification sbn = getNotification(false /*preO */, false /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_O, false /* noisy */,
                 false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, null /* group */);
 
@@ -297,7 +296,7 @@
 
     @Test
     public void testImportance_preUpgrade() throws Exception {
-        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, null /* group */);
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
@@ -308,7 +307,7 @@
     public void testImportance_locked_preUpgrade() throws Exception {
         defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
         defaultChannel.lockFields(USER_LOCKED_IMPORTANCE);
-        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, null /* group */);
 
@@ -320,7 +319,7 @@
     public void testImportance_locked_unspecified_preUpgrade() throws Exception {
         defaultChannel.setImportance(NotificationManager.IMPORTANCE_UNSPECIFIED);
         defaultChannel.lockFields(USER_LOCKED_IMPORTANCE);
-        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, null /* group */);
 
@@ -330,7 +329,7 @@
 
     @Test
     public void testImportance_upgrade() throws Exception {
-        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, null /* group */);
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
@@ -339,7 +338,7 @@
 
     @Test
     public void testLights_preUpgrade_noLight() throws Exception {
-        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, null /* group */);
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
@@ -349,7 +348,7 @@
 
     @Test
     public void testLights_preUpgrade() throws Exception {
-        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 true /* lights */, false /* defaultLights */, null /* group */);
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
@@ -360,7 +359,7 @@
     public void testLights_locked_preUpgrade() throws Exception {
         defaultChannel.enableLights(true);
         defaultChannel.lockFields(NotificationChannel.USER_LOCKED_LIGHTS);
-        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 true /* lights */, false /* defaultLights */, null /* group */);
 
@@ -379,7 +378,7 @@
 
         NotificationRecord.Light expected = new NotificationRecord.Light(
                 defaultLightColor, defaultLightOn, defaultLightOff);
-        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 true /* lights */, true /* defaultLights */, null /* group */);
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
@@ -395,7 +394,7 @@
 
         NotificationRecord.Light expected = new NotificationRecord.Light(
                 Color.BLUE, defaultLightOn, defaultLightOff);
-        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 true /* lights */, false /* defaultLights */, null /* group */);
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
@@ -404,7 +403,7 @@
 
     @Test
     public void testLights_upgrade_noLight() throws Exception {
-        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, null /* group */);
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
@@ -413,7 +412,7 @@
 
     @Test
     public void testLogmakerShortChannel() throws Exception {
-        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, null /* group */);
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
@@ -426,7 +425,7 @@
 
     @Test
     public void testLogmakerLongChannel() throws Exception {
-        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
         true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
         false /* lights */, false /*defaultLights */, null /* group */);
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, channelLongId);
@@ -437,7 +436,7 @@
 
     @Test
     public void testLogmakerNoGroup() throws Exception {
-        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */, null /* group */);
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
@@ -446,7 +445,7 @@
 
     @Test
     public void testLogmakerShortGroup() throws Exception {
-        StatusBarNotification sbn = getNotification(false /*reO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, groupId /* group */);
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
@@ -456,7 +455,7 @@
 
     @Test
     public void testLogmakerLongGroup() throws Exception {
-        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, groupIdLong /* group */);
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
@@ -467,7 +466,7 @@
 
     @Test
     public void testLogmakerOverrideGroup() throws Exception {
-        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, groupId /* group */);
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
@@ -483,7 +482,7 @@
 
     @Test
     public void testNotificationStats() throws Exception {
-        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, groupId /* group */);
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
@@ -526,7 +525,7 @@
 
     @Test
     public void testUserSentiment() throws Exception {
-        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, groupId /* group */);
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
@@ -544,7 +543,7 @@
 
     @Test
     public void testUserSentiment_appImportanceUpdatesSentiment() throws Exception {
-        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, groupId /* group */);
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
@@ -556,7 +555,7 @@
 
     @Test
     public void testUserSentiment_appImportanceBlocksNegativeSentimentUpdate() throws Exception {
-        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, groupId /* group */);
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
@@ -573,7 +572,7 @@
     @Test
     public void testUserSentiment_userLocked() throws Exception {
         channel.lockFields(USER_LOCKED_IMPORTANCE);
-        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, groupId /* group */);
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
@@ -591,7 +590,7 @@
 
     @Test
     public void testAppImportance_returnsCorrectly() throws Exception {
-        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, groupId /* group */);
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
@@ -605,7 +604,7 @@
 
     @Test
     public void testIsInterruptive_textChanged_notSeen() {
-        StatusBarNotification sbn = getNotification(false /*preO */, false /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_O, false /* noisy */,
                 false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, null /* group */);
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
@@ -618,7 +617,7 @@
 
     @Test
     public void testIsInterruptive_textChanged_seen() {
-        StatusBarNotification sbn = getNotification(false /*preO */, false /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_O, false /* noisy */,
                 false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, null /* group */);
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
@@ -632,7 +631,7 @@
 
     @Test
     public void testIsInterruptive_textNotChanged_seen() {
-        StatusBarNotification sbn = getNotification(false /*preO */, false /* noisy */,
+        StatusBarNotification sbn = getNotification(PKG_O, false /* noisy */,
                 false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, null /* group */);
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
@@ -643,4 +642,59 @@
         record.setSeen();
         assertEquals(false, record.isInterruptive());
     }
+
+    @Test
+    public void testCalculateGrantableUris_PappProvided() throws RemoteException {
+        IActivityManager am = mock(IActivityManager.class);
+        when(am.checkGrantUriPermission(anyInt(), eq(null), any(),
+                anyInt(), anyInt())).thenThrow(new SecurityException());
+
+        Notification n = mock(Notification.class);
+        when(n.getChannelId()).thenReturn(channel.getId());
+        StatusBarNotification sbn =
+                new StatusBarNotification(PKG_P, PKG_P, id1, tag1, uid, uid, n, mUser, null, uid);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+        record.mAm = am;
+
+        try {
+            record.calculateGrantableUris();
+            fail("App provided uri for p targeting app should throw exception");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testCalculateGrantableUris_PuserOverridden() throws RemoteException {
+        IActivityManager am = mock(IActivityManager.class);
+        when(am.checkGrantUriPermission(anyInt(), eq(null), any(),
+                anyInt(), anyInt())).thenThrow(SecurityException.class);
+
+        channel.lockFields(NotificationChannel.USER_LOCKED_SOUND);
+        Notification n = mock(Notification.class);
+        when(n.getChannelId()).thenReturn(channel.getId());
+        StatusBarNotification sbn =
+                new StatusBarNotification(PKG_P, PKG_P, id1, tag1, uid, uid, n, mUser, null, uid);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+        record.mAm = am;
+
+        record.calculateGrantableUris();
+    }
+
+    @Test
+    public void testCalculateGrantableUris_prePappProvided() throws RemoteException {
+        IActivityManager am = mock(IActivityManager.class);
+        when(am.checkGrantUriPermission(anyInt(), eq(null), any(),
+                anyInt(), anyInt())).thenThrow(SecurityException.class);
+
+        Notification n = mock(Notification.class);
+        when(n.getChannelId()).thenReturn(channel.getId());
+        StatusBarNotification sbn =
+                new StatusBarNotification(PKG_O, PKG_O, id1, tag1, uid, uid, n, mUser, null, uid);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+        record.mAm = am;
+
+        record.calculateGrantableUris();
+        // should not throw
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
index 3c4e333..82e0fbe 100644
--- a/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
@@ -1,16 +1,16 @@
 package com.android.server.slice;
 
+import static android.testing.TestableContentResolver.UNSTABLE;
+
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -71,11 +71,12 @@
         mSliceService = mock(SliceManagerService.class);
         when(mSliceService.getContext()).thenReturn(mContext);
         when(mSliceService.getLock()).thenReturn(new Object());
-        when(mSliceService.getHandler()).thenReturn(new Handler(TestableLooper.get(this).getLooper()));
+        when(mSliceService.getHandler()).thenReturn(
+                new Handler(TestableLooper.get(this).getLooper()));
         mContentProvider = mock(ContentProvider.class);
         mIContentProvider = mock(IContentProvider.class);
         when(mContentProvider.getIContentProvider()).thenReturn(mIContentProvider);
-        mContext.getContentResolver().addProvider(AUTH, mContentProvider);
+        mContext.getContentResolver().addProvider(AUTH, mContentProvider, UNSTABLE);
         mPinnedSliceManager = new PinnedSliceState(mSliceService, TEST_URI, "pkg");
     }
 
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index e6584c5..2547f16 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -924,8 +924,7 @@
             } catch (RemoteException re) {
                 throw re.rethrowFromSystemServer();
             }
-            final int packageUid = mPackageManagerInternal.getPackageUid(packageName,
-                    PackageManager.MATCH_ANY_USER, userId);
+            final int packageUid = mPackageManagerInternal.getPackageUid(packageName, 0, userId);
             // If the calling app is asking about itself, continue, else check for permission.
             if (packageUid != callingUid) {
                 if (!hasPermission(callingPackage)) {
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index c96463c..22958d4 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -45,6 +45,7 @@
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.OutputStreamWriter;
+import java.nio.channels.Channels;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -853,6 +854,8 @@
         private final OutputStreamWriter mPipeToInCall;
         private final ParcelFileDescriptor mFdFromInCall;
         private final ParcelFileDescriptor mFdToInCall;
+
+        private final FileInputStream mFromInCallFileInputStream;
         private char[] mReadBuffer = new char[READ_BUFFER_SIZE];
 
         /**
@@ -861,8 +864,11 @@
         public RttTextStream(ParcelFileDescriptor toInCall, ParcelFileDescriptor fromInCall) {
             mFdFromInCall = fromInCall;
             mFdToInCall = toInCall;
+            mFromInCallFileInputStream = new FileInputStream(fromInCall.getFileDescriptor());
+
+            // Wrap the FileInputStream in a Channel so that it's interruptible.
             mPipeFromInCall = new InputStreamReader(
-                    new FileInputStream(fromInCall.getFileDescriptor()));
+                    Channels.newInputStream(Channels.newChannel(mFromInCallFileInputStream)));
             mPipeToInCall = new OutputStreamWriter(
                     new FileOutputStream(toInCall.getFileDescriptor()));
         }
@@ -910,7 +916,7 @@
          * not entered any new text yet.
          */
         public String readImmediately() throws IOException {
-            if (mPipeFromInCall.ready()) {
+            if (mFromInCallFileInputStream.available() > 0) {
                 return read();
             } else {
                 return null;
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index a1f814b..88cb6c9 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -77,6 +77,30 @@
     public static final String
             KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool";
 
+    /**
+     * Boolean indicating if the "Call forwarding" item is visible in the Call Settings menu.
+     * true means visible. false means gone.
+     * @hide
+     */
+    public static final String KEY_CALL_FORWARDING_VISIBILITY_BOOL =
+            "call_forwarding_visibility_bool";
+
+    /**
+     * Boolean indicating if the "Caller ID" item is visible in the Additional Settings menu.
+     * true means visible. false means gone.
+     * @hide
+     */
+    public static final String KEY_ADDITIONAL_SETTINGS_CALLER_ID_VISIBILITY_BOOL =
+            "additional_settings_caller_id_visibility_bool";
+
+    /**
+     * Boolean indicating if the "Call Waiting" item is visible in the Additional Settings menu.
+     * true means visible. false means gone.
+     * @hide
+     */
+    public static final String KEY_ADDITIONAL_SETTINGS_CALL_WAITING_VISIBILITY_BOOL =
+            "additional_settings_call_waiting_visibility_bool";
+
    /**
     * Boolean indicating if the "Call barring" item is visible in the Call Settings menu.
     * true means visible. false means gone.
@@ -2043,6 +2067,9 @@
 
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONED_BOOL, false);
         sDefaults.putBoolean(KEY_CALL_BARRING_VISIBILITY_BOOL, false);
+        sDefaults.putBoolean(KEY_CALL_FORWARDING_VISIBILITY_BOOL, true);
+        sDefaults.putBoolean(KEY_ADDITIONAL_SETTINGS_CALLER_ID_VISIBILITY_BOOL, true);
+        sDefaults.putBoolean(KEY_ADDITIONAL_SETTINGS_CALL_WAITING_VISIBILITY_BOOL, true);
         sDefaults.putBoolean(KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL, false);
         sDefaults.putBoolean(KEY_MDN_IS_ADDITIONAL_VOICEMAIL_NUMBER_BOOL, false);
         sDefaults.putBoolean(KEY_OPERATOR_SELECTION_EXPAND_BOOL, true);
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 5961e9a..5bd4d22 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -335,11 +335,18 @@
      * <p>
      * The {@link #EXTRA_STATE} extra indicates the new call state.
      * If a receiving app has {@link android.Manifest.permission#READ_CALL_LOG} permission, a second
-     * extra {@link #EXTRA_INCOMING_NUMBER} provides the phone number for incoming and outoing calls
-     * as a String.  Note: If the receiving app has
+     * extra {@link #EXTRA_INCOMING_NUMBER} provides the phone number for incoming and outgoing
+     * calls as a String.
+     * <p>
+     * If the receiving app has
      * {@link android.Manifest.permission#READ_CALL_LOG} and
      * {@link android.Manifest.permission#READ_PHONE_STATE} permission, it will receive the
-     * broadcast twice; one with the phone number and another without it.
+     * broadcast twice; one with the {@link #EXTRA_INCOMING_NUMBER} populated with the phone number,
+     * and another with it blank.  Due to the nature of broadcasts, you cannot assume the order
+     * in which these broadcasts will arrive, however you are guaranteed to receive two in this
+     * case.  Apps which are interested in the {@link #EXTRA_INCOMING_NUMBER} can ignore the
+     * broadcasts where {@link #EXTRA_INCOMING_NUMBER} is not present in the extras (e.g. where
+     * {@link Intent#hasExtra(String)} returns {@code false}).
      * <p class="note">
      * This was a {@link android.content.Context#sendStickyBroadcast sticky}
      * broadcast in version 1.0, but it is no longer sticky.
@@ -488,10 +495,19 @@
     public static final String EXTRA_STATE_OFFHOOK = PhoneConstants.State.OFFHOOK.toString();
 
     /**
-     * The lookup key used with the {@link #ACTION_PHONE_STATE_CHANGED} broadcast
-     * for a String containing the incoming phone number.
-     * Only valid when the new call state is RINGING.
-     *
+     * Extra key used with the {@link #ACTION_PHONE_STATE_CHANGED} broadcast
+     * for a String containing the incoming or outgoing phone number.
+     * <p>
+     * This extra is only populated for receivers of the {@link #ACTION_PHONE_STATE_CHANGED}
+     * broadcast which have been granted the {@link android.Manifest.permission#READ_CALL_LOG} and
+     * {@link android.Manifest.permission#READ_PHONE_STATE} permissions.
+     * <p>
+     * For incoming calls, the phone number is only guaranteed to be populated when the
+     * {@link #EXTRA_STATE} changes from {@link #EXTRA_STATE_IDLE} to {@link #EXTRA_STATE_RINGING}.
+     * If the incoming caller is from an unknown number, the extra will be populated with an empty
+     * string.
+     * For outgoing calls, the phone number is only guaranteed to be populated when the
+     * {@link #EXTRA_STATE} changes from {@link #EXTRA_STATE_IDLE} to {@link #EXTRA_STATE_OFFHOOK}.
      * <p class="note">
      * Retrieve with
      * {@link android.content.Intent#getStringExtra(String)}.
@@ -5518,23 +5534,6 @@
     }
 
     /**
-     * @return true if the IMS resolver is busy resolving a binding and should not be considered
-     * available, false if the IMS resolver is idle.
-     * @hide
-     */
-    public boolean isResolvingImsBinding() {
-        try {
-            ITelephony telephony = getITelephony();
-            if (telephony != null) {
-                return telephony.isResolvingImsBinding();
-            }
-        } catch (RemoteException e) {
-            Rlog.e(TAG, "isResolvingImsBinding, RemoteException: " + e.getMessage());
-        }
-        return false;
-    }
-
-    /**
      * Set IMS registration state
      *
      * @param Registration state
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 9388ed1..5dc0cff 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -31,6 +31,7 @@
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.net.InetAddress;
@@ -633,33 +634,33 @@
             int maxConns, int waitTime, int maxConnsTime, int mtu, int mvnoType,
             String mvnoMatchData, int apnSetId) {
         return new Builder()
-            .setId(id)
-            .setOperatorNumeric(operatorNumeric)
-            .setEntryName(entryName)
-            .setApnName(apnName)
-            .setProxyAddress(proxyAddress)
-            .setProxyPort(proxyPort)
-            .setMmsc(mmsc)
-            .setMmsProxyAddress(mmsProxyAddress)
-            .setMmsProxyPort(mmsProxyPort)
-            .setUser(user)
-            .setPassword(password)
-            .setAuthType(authType)
-            .setApnTypeBitmask(mApnTypeBitmask)
-            .setProtocol(protocol)
-            .setRoamingProtocol(roamingProtocol)
-            .setCarrierEnabled(carrierEnabled)
-            .setNetworkTypeBitmask(networkTypeBitmask)
-            .setProfileId(profileId)
-            .setModemCognitive(modemCognitive)
-            .setMaxConns(maxConns)
-            .setWaitTime(waitTime)
-            .setMaxConnsTime(maxConnsTime)
-            .setMtu(mtu)
-            .setMvnoType(mvnoType)
-            .setMvnoMatchData(mvnoMatchData)
-            .setApnSetId(apnSetId)
-            .buildWithoutCheck();
+                .setId(id)
+                .setOperatorNumeric(operatorNumeric)
+                .setEntryName(entryName)
+                .setApnName(apnName)
+                .setProxyAddress(proxyAddress)
+                .setProxyPort(proxyPort)
+                .setMmsc(mmsc)
+                .setMmsProxyAddress(mmsProxyAddress)
+                .setMmsProxyPort(mmsProxyPort)
+                .setUser(user)
+                .setPassword(password)
+                .setAuthType(authType)
+                .setApnTypeBitmask(mApnTypeBitmask)
+                .setProtocol(protocol)
+                .setRoamingProtocol(roamingProtocol)
+                .setCarrierEnabled(carrierEnabled)
+                .setNetworkTypeBitmask(networkTypeBitmask)
+                .setProfileId(profileId)
+                .setModemCognitive(modemCognitive)
+                .setMaxConns(maxConns)
+                .setWaitTime(waitTime)
+                .setMaxConnsTime(maxConnsTime)
+                .setMtu(mtu)
+                .setMvnoType(mvnoType)
+                .setMvnoMatchData(mvnoMatchData)
+                .setApnSetId(apnSetId)
+                .buildWithoutCheck();
     }
 
     /** @hide */
@@ -691,56 +692,56 @@
         }
 
         return makeApnSetting(
-            cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)),
-            cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)),
-            cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)),
-            cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)),
-            cursor.getString(
-                cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY)),
-            portFromString(cursor.getString(
-                cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT))),
-            UriFromString(cursor.getString(
-                cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))),
-            cursor.getString(
-                cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY)),
-            portFromString(cursor.getString(
-                cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT))),
-            cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)),
-            cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)),
-            cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE)),
-            apnTypesBitmask,
-            getProtocolIntFromString(
-                cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL))),
-            getProtocolIntFromString(
+                cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)),
+                cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)),
+                cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)),
+                cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)),
+                cursor.getString(
+                        cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY)),
+                portFromString(cursor.getString(
+                        cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT))),
+                UriFromString(cursor.getString(
+                        cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))),
+                cursor.getString(
+                        cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY)),
+                portFromString(cursor.getString(
+                        cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT))),
+                cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)),
+                cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)),
+                cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE)),
+                apnTypesBitmask,
+                getProtocolIntFromString(
+                    cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL))),
+                getProtocolIntFromString(
+                    cursor.getString(cursor.getColumnIndexOrThrow(
+                        Telephony.Carriers.ROAMING_PROTOCOL))),
+                cursor.getInt(cursor.getColumnIndexOrThrow(
+                        Telephony.Carriers.CARRIER_ENABLED)) == 1,
+                networkTypeBitmask,
+                cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROFILE_ID)),
+                cursor.getInt(cursor.getColumnIndexOrThrow(
+                        Telephony.Carriers.MODEM_COGNITIVE)) == 1,
+                cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNS)),
+                cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.WAIT_TIME)),
+                cursor.getInt(cursor.getColumnIndexOrThrow(
+                        Telephony.Carriers.MAX_CONNS_TIME)),
+                cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU)),
+                getMvnoTypeIntFromString(
+                    cursor.getString(cursor.getColumnIndexOrThrow(
+                        Telephony.Carriers.MVNO_TYPE))),
                 cursor.getString(cursor.getColumnIndexOrThrow(
-                    Telephony.Carriers.ROAMING_PROTOCOL))),
-            cursor.getInt(cursor.getColumnIndexOrThrow(
-                Telephony.Carriers.CARRIER_ENABLED)) == 1,
-            networkTypeBitmask,
-            cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROFILE_ID)),
-            cursor.getInt(cursor.getColumnIndexOrThrow(
-                Telephony.Carriers.MODEM_COGNITIVE)) == 1,
-            cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNS)),
-            cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.WAIT_TIME)),
-            cursor.getInt(cursor.getColumnIndexOrThrow(
-                Telephony.Carriers.MAX_CONNS_TIME)),
-            cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU)),
-            getMvnoTypeIntFromString(
-                cursor.getString(cursor.getColumnIndexOrThrow(
-                    Telephony.Carriers.MVNO_TYPE))),
-            cursor.getString(cursor.getColumnIndexOrThrow(
-                Telephony.Carriers.MVNO_MATCH_DATA)),
-            cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN_SET_ID)));
+                        Telephony.Carriers.MVNO_MATCH_DATA)),
+                cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN_SET_ID)));
     }
 
     /** @hide */
     public static ApnSetting makeApnSetting(ApnSetting apn) {
         return makeApnSetting(apn.mId, apn.mOperatorNumeric, apn.mEntryName, apn.mApnName,
-            apn.mProxyAddress, apn.mProxyPort, apn.mMmsc, apn.mMmsProxyAddress,
-            apn.mMmsProxyPort, apn.mUser, apn.mPassword, apn.mAuthType, apn.mApnTypeBitmask,
-            apn.mProtocol, apn.mRoamingProtocol, apn.mCarrierEnabled, apn.mNetworkTypeBitmask,
-            apn.mProfileId, apn.mModemCognitive, apn.mMaxConns, apn.mWaitTime,
-            apn.mMaxConnsTime, apn.mMtu, apn.mMvnoType, apn.mMvnoMatchData, apn.mApnSetId);
+                apn.mProxyAddress, apn.mProxyPort, apn.mMmsc, apn.mMmsProxyAddress,
+                apn.mMmsProxyPort, apn.mUser, apn.mPassword, apn.mAuthType, apn.mApnTypeBitmask,
+                apn.mProtocol, apn.mRoamingProtocol, apn.mCarrierEnabled, apn.mNetworkTypeBitmask,
+                apn.mProfileId, apn.mModemCognitive, apn.mMaxConns, apn.mWaitTime,
+                apn.mMaxConnsTime, apn.mMtu, apn.mMvnoType, apn.mMvnoMatchData, apn.mApnSetId);
     }
 
     /**
@@ -930,16 +931,16 @@
     public String toString() {
         StringBuilder sb = new StringBuilder();
         sb.append("[ApnSettingV5] ")
-            .append(mEntryName)
-            .append(", ").append(mId)
-            .append(", ").append(mOperatorNumeric)
-            .append(", ").append(mApnName)
-            .append(", ").append(mProxyAddress)
-            .append(", ").append(UriToString(mMmsc))
-            .append(", ").append(mMmsProxyAddress)
-            .append(", ").append(portToString(mMmsProxyPort))
-            .append(", ").append(portToString(mProxyPort))
-            .append(", ").append(mAuthType).append(", ");
+                .append(mEntryName)
+                .append(", ").append(mId)
+                .append(", ").append(mOperatorNumeric)
+                .append(", ").append(mApnName)
+                .append(", ").append(mProxyAddress)
+                .append(", ").append(UriToString(mMmsc))
+                .append(", ").append(mMmsProxyAddress)
+                .append(", ").append(portToString(mMmsProxyPort))
+                .append(", ").append(portToString(mProxyPort))
+                .append(", ").append(mAuthType).append(", ");
         final String[] types = getApnTypesStringFromBitmask(mApnTypeBitmask).split(",");
         sb.append(TextUtils.join(" | ", types));
         sb.append(", ").append(PROTOCOL_INT_MAP.get(mProtocol));
@@ -1021,31 +1022,31 @@
         ApnSetting other = (ApnSetting) o;
 
         return mEntryName.equals(other.mEntryName)
-            && Objects.equals(mId, other.mId)
-            && Objects.equals(mOperatorNumeric, other.mOperatorNumeric)
-            && Objects.equals(mApnName, other.mApnName)
-            && Objects.equals(mProxyAddress, other.mProxyAddress)
-            && Objects.equals(mMmsc, other.mMmsc)
-            && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress)
-            && Objects.equals(mMmsProxyPort, other.mMmsProxyPort)
-            && Objects.equals(mProxyPort, other.mProxyPort)
-            && Objects.equals(mUser, other.mUser)
-            && Objects.equals(mPassword, other.mPassword)
-            && Objects.equals(mAuthType, other.mAuthType)
-            && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask)
-            && Objects.equals(mProtocol, other.mProtocol)
-            && Objects.equals(mRoamingProtocol, other.mRoamingProtocol)
-            && Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
-            && Objects.equals(mProfileId, other.mProfileId)
-            && Objects.equals(mModemCognitive, other.mModemCognitive)
-            && Objects.equals(mMaxConns, other.mMaxConns)
-            && Objects.equals(mWaitTime, other.mWaitTime)
-            && Objects.equals(mMaxConnsTime, other.mMaxConnsTime)
-            && Objects.equals(mMtu, other.mMtu)
-            && Objects.equals(mMvnoType, other.mMvnoType)
-            && Objects.equals(mMvnoMatchData, other.mMvnoMatchData)
-            && Objects.equals(mNetworkTypeBitmask, other.mNetworkTypeBitmask)
-            && Objects.equals(mApnSetId, other.mApnSetId);
+                && Objects.equals(mId, other.mId)
+                && Objects.equals(mOperatorNumeric, other.mOperatorNumeric)
+                && Objects.equals(mApnName, other.mApnName)
+                && Objects.equals(mProxyAddress, other.mProxyAddress)
+                && Objects.equals(mMmsc, other.mMmsc)
+                && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress)
+                && Objects.equals(mMmsProxyPort, other.mMmsProxyPort)
+                && Objects.equals(mProxyPort,other.mProxyPort)
+                && Objects.equals(mUser, other.mUser)
+                && Objects.equals(mPassword, other.mPassword)
+                && Objects.equals(mAuthType, other.mAuthType)
+                && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask)
+                && Objects.equals(mProtocol, other.mProtocol)
+                && Objects.equals(mRoamingProtocol, other.mRoamingProtocol)
+                && Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
+                && Objects.equals(mProfileId, other.mProfileId)
+                && Objects.equals(mModemCognitive, other.mModemCognitive)
+                && Objects.equals(mMaxConns, other.mMaxConns)
+                && Objects.equals(mWaitTime, other.mWaitTime)
+                && Objects.equals(mMaxConnsTime, other.mMaxConnsTime)
+                && Objects.equals(mMtu, other.mMtu)
+                && Objects.equals(mMvnoType, other.mMvnoType)
+                && Objects.equals(mMvnoMatchData, other.mMvnoMatchData)
+                && Objects.equals(mNetworkTypeBitmask, other.mNetworkTypeBitmask)
+                && Objects.equals(mApnSetId, other.mApnSetId);
     }
 
     /**
@@ -1068,29 +1069,29 @@
         ApnSetting other = (ApnSetting) o;
 
         return mEntryName.equals(other.mEntryName)
-            && Objects.equals(mOperatorNumeric, other.mOperatorNumeric)
-            && Objects.equals(mApnName, other.mApnName)
-            && Objects.equals(mProxyAddress, other.mProxyAddress)
-            && Objects.equals(mMmsc, other.mMmsc)
-            && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress)
-            && Objects.equals(mMmsProxyPort, other.mMmsProxyPort)
-            && Objects.equals(mProxyPort, other.mProxyPort)
-            && Objects.equals(mUser, other.mUser)
-            && Objects.equals(mPassword, other.mPassword)
-            && Objects.equals(mAuthType, other.mAuthType)
-            && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask)
-            && (isDataRoaming || Objects.equals(mProtocol, other.mProtocol))
-            && (!isDataRoaming || Objects.equals(mRoamingProtocol, other.mRoamingProtocol))
-            && Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
-            && Objects.equals(mProfileId, other.mProfileId)
-            && Objects.equals(mModemCognitive, other.mModemCognitive)
-            && Objects.equals(mMaxConns, other.mMaxConns)
-            && Objects.equals(mWaitTime, other.mWaitTime)
-            && Objects.equals(mMaxConnsTime, other.mMaxConnsTime)
-            && Objects.equals(mMtu, other.mMtu)
-            && Objects.equals(mMvnoType, other.mMvnoType)
-            && Objects.equals(mMvnoMatchData, other.mMvnoMatchData)
-            && Objects.equals(mApnSetId, other.mApnSetId);
+                && Objects.equals(mOperatorNumeric, other.mOperatorNumeric)
+                && Objects.equals(mApnName, other.mApnName)
+                && Objects.equals(mProxyAddress, other.mProxyAddress)
+                && Objects.equals(mMmsc, other.mMmsc)
+                && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress)
+                && Objects.equals(mMmsProxyPort, other.mMmsProxyPort)
+                && Objects.equals(mProxyPort, other.mProxyPort)
+                && Objects.equals(mUser, other.mUser)
+                && Objects.equals(mPassword, other.mPassword)
+                && Objects.equals(mAuthType, other.mAuthType)
+                && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask)
+                && (isDataRoaming || Objects.equals(mProtocol,other.mProtocol))
+                && (!isDataRoaming || Objects.equals(mRoamingProtocol, other.mRoamingProtocol))
+                && Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
+                && Objects.equals(mProfileId, other.mProfileId)
+                && Objects.equals(mModemCognitive, other.mModemCognitive)
+                && Objects.equals(mMaxConns, other.mMaxConns)
+                && Objects.equals(mWaitTime, other.mWaitTime)
+                && Objects.equals(mMaxConnsTime, other.mMaxConnsTime)
+                && Objects.equals(mMtu, other.mMtu)
+                && Objects.equals(mMvnoType, other.mMvnoType)
+                && Objects.equals(mMvnoMatchData, other.mMvnoMatchData)
+                && Objects.equals(mApnSetId, other.mApnSetId);
     }
 
     /**
@@ -1102,22 +1103,22 @@
      */
     public boolean similar(ApnSetting other) {
         return (!this.canHandleType(TYPE_DUN)
-            && !other.canHandleType(TYPE_DUN)
-            && Objects.equals(this.mApnName, other.mApnName)
-            && !typeSameAny(this, other)
-            && xorEquals(this.mProxyAddress, other.mProxyAddress)
-            && xorEqualsInt(this.mProxyPort, other.mProxyPort)
-            && xorEquals(this.mProtocol, other.mProtocol)
-            && xorEquals(this.mRoamingProtocol, other.mRoamingProtocol)
-            && Objects.equals(this.mCarrierEnabled, other.mCarrierEnabled)
-            && Objects.equals(this.mProfileId, other.mProfileId)
-            && Objects.equals(this.mMvnoType, other.mMvnoType)
-            && Objects.equals(this.mMvnoMatchData, other.mMvnoMatchData)
-            && xorEquals(this.mMmsc, other.mMmsc)
-            && xorEquals(this.mMmsProxyAddress, other.mMmsProxyAddress)
-            && xorEqualsInt(this.mMmsProxyPort, other.mMmsProxyPort))
-            && Objects.equals(this.mNetworkTypeBitmask, other.mNetworkTypeBitmask)
-            && Objects.equals(mApnSetId, other.mApnSetId);
+                && !other.canHandleType(TYPE_DUN)
+                && Objects.equals(this.mApnName, other.mApnName)
+                && !typeSameAny(this, other)
+                && xorEquals(this.mProxyAddress, other.mProxyAddress)
+                && xorEqualsInt(this.mProxyPort, other.mProxyPort)
+                && xorEquals(this.mProtocol, other.mProtocol)
+                && xorEquals(this.mRoamingProtocol, other.mRoamingProtocol)
+                && Objects.equals(this.mCarrierEnabled, other.mCarrierEnabled)
+                && Objects.equals(this.mProfileId, other.mProfileId)
+                && Objects.equals(this.mMvnoType, other.mMvnoType)
+                && Objects.equals(this.mMvnoMatchData, other.mMvnoMatchData)
+                && xorEquals(this.mMmsc, other.mMmsc)
+                && xorEquals(this.mMmsProxyAddress, other.mMmsProxyAddress)
+                && xorEqualsInt(this.mMmsProxyPort, other.mMmsProxyPort))
+                && Objects.equals(this.mNetworkTypeBitmask, other.mNetworkTypeBitmask)
+                && Objects.equals(mApnSetId, other.mApnSetId);
     }
 
     // Equal or one is null.
@@ -1341,13 +1342,13 @@
             new Parcelable.Creator<ApnSetting>() {
                 @Override
                 public ApnSetting createFromParcel(Parcel in) {
-                return readFromParcel(in);
-            }
+                    return readFromParcel(in);
+                }
 
                 @Override
                 public ApnSetting[] newArray(int size) {
-                return new ApnSetting[size];
-            }
+                    return new ApnSetting[size];
+                }
             };
 
     /**
diff --git a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
index bcad554..a1bea4d 100644
--- a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
+++ b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
@@ -21,7 +21,6 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
-import android.content.res.Resources;
 import android.os.RemoteException;
 import android.provider.Settings;
 import android.telephony.TelephonyManager;
@@ -145,6 +144,18 @@
                         telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName) ==
                                 TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
 
+                // add hiddenUntilInstalled flag for carrier apps and associated apps
+                packageManager.setSystemAppHiddenUntilInstalled(packageName, true);
+                List<ApplicationInfo> associatedAppList = associatedApps.get(packageName);
+                if (associatedAppList != null) {
+                    for (ApplicationInfo associatedApp : associatedAppList) {
+                        packageManager.setSystemAppHiddenUntilInstalled(
+                                associatedApp.packageName,
+                                true
+                        );
+                    }
+                }
+
                 if (hasPrivileges) {
                     // Only update enabled state for the app on /system. Once it has been
                     // updated we shouldn't touch it.
@@ -152,9 +163,14 @@
                             && (ai.enabledSetting ==
                             PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
                             || ai.enabledSetting ==
-                            PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) {
+                            PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED
+                            || (ai.flags & ApplicationInfo.FLAG_INSTALLED) == 0)) {
                         Slog.i(TAG, "Update state(" + packageName + "): ENABLED for user "
                                 + userId);
+                        packageManager.setSystemAppInstallState(
+                                packageName,
+                                true /*installed*/,
+                                userId);
                         packageManager.setApplicationEnabledSetting(
                                 packageName,
                                 PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
@@ -164,15 +180,20 @@
                     }
 
                     // Also enable any associated apps for this carrier app.
-                    List<ApplicationInfo> associatedAppList = associatedApps.get(packageName);
                     if (associatedAppList != null) {
                         for (ApplicationInfo associatedApp : associatedAppList) {
                             if (associatedApp.enabledSetting ==
                                     PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
                                     || associatedApp.enabledSetting ==
-                                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
+                                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED
+                                    || (associatedApp.flags
+                                    & ApplicationInfo.FLAG_INSTALLED) == 0) {
                                 Slog.i(TAG, "Update associated state(" + associatedApp.packageName
                                         + "): ENABLED for user " + userId);
+                                packageManager.setSystemAppInstallState(
+                                        associatedApp.packageName,
+                                        true /*installed*/,
+                                        userId);
                                 packageManager.setApplicationEnabledSetting(
                                         associatedApp.packageName,
                                         PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
@@ -190,36 +211,33 @@
                     // updated we shouldn't touch it.
                     if (!ai.isUpdatedSystemApp()
                             && ai.enabledSetting ==
-                            PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
+                            PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
+                            && (ai.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
                         Slog.i(TAG, "Update state(" + packageName
                                 + "): DISABLED_UNTIL_USED for user " + userId);
-                        packageManager.setApplicationEnabledSetting(
+                        packageManager.setSystemAppInstallState(
                                 packageName,
-                                PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED,
-                                0,
-                                userId,
-                                callingPackage);
+                                false /*installed*/,
+                                userId);
                     }
 
                     // Also disable any associated apps for this carrier app if this is the first
                     // run. We avoid doing this a second time because it is brittle to rely on the
                     // distinction between "default" and "enabled".
                     if (!hasRunOnce) {
-                        List<ApplicationInfo> associatedAppList = associatedApps.get(packageName);
                         if (associatedAppList != null) {
                             for (ApplicationInfo associatedApp : associatedAppList) {
                                 if (associatedApp.enabledSetting
-                                        == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
+                                        == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
+                                        && (associatedApp.flags
+                                        & ApplicationInfo.FLAG_INSTALLED) != 0) {
                                     Slog.i(TAG,
                                             "Update associated state(" + associatedApp.packageName
                                                     + "): DISABLED_UNTIL_USED for user " + userId);
-                                    packageManager.setApplicationEnabledSetting(
+                                    packageManager.setSystemAppInstallState(
                                             associatedApp.packageName,
-                                            PackageManager
-                                                    .COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED,
-                                            0,
-                                            userId,
-                                            callingPackage);
+                                            false /*installed*/,
+                                            userId);
                                 }
                             }
                         }
@@ -357,7 +375,8 @@
             String packageName) {
         try {
             ApplicationInfo ai = packageManager.getApplicationInfo(packageName,
-                    PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, userId);
+                    PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
+                    | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS, userId);
             if (ai != null && ai.isSystemApp()) {
                 return ai;
             }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index b519ebc..5ecdfc9 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -817,12 +817,6 @@
     IImsConfig getImsConfig(int slotId, int feature);
 
     /**
-     * @return true if the IMS resolver is busy resolving a binding and should not be considered
-     * available, false if the IMS resolver is idle.
-     */
-    boolean isResolvingImsBinding();
-
-    /**
     *  @return true if the ImsService to bind to for the slot id specified was set, false otherwise.
     */
     boolean setImsService(int slotId, boolean isCarrierImsService, String packageName);
diff --git a/tests/testables/src/android/testing/TestableContentResolver.java b/tests/testables/src/android/testing/TestableContentResolver.java
index 0850916..a0afef8 100644
--- a/tests/testables/src/android/testing/TestableContentResolver.java
+++ b/tests/testables/src/android/testing/TestableContentResolver.java
@@ -20,6 +20,7 @@
 import android.content.IContentProvider;
 import android.database.ContentObserver;
 import android.net.Uri;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 
 import com.google.android.collect.Maps;
@@ -35,7 +36,11 @@
  */
 public class TestableContentResolver extends ContentResolver {
 
-    private final Map<String, ContentProvider> mProviders = Maps.newHashMap();
+    public static final int STABLE = 1;
+    public static final int UNSTABLE = 2;
+
+    private final Map<String, ContentProvider> mProviders = new ArrayMap<>();
+    private final Map<String, ContentProvider> mUnstableProviders = new ArrayMap<>();
     private final ContentResolver mParent;
     private final ArraySet<ContentProvider> mInUse = new ArraySet<>();
     private boolean mFallbackToExisting;
@@ -62,7 +67,23 @@
      * subclasses, or null.
      */
     public void addProvider(String name, ContentProvider provider) {
-        mProviders.put(name, provider);
+        addProvider(name, provider, STABLE | UNSTABLE);
+    }
+
+    /**
+     * Adds access to a provider based on its authority
+     *
+     * @param name The authority name associated with the provider.
+     * @param provider An instance of {@link android.content.ContentProvider} or one of its
+     * subclasses, or null.
+     */
+    public void addProvider(String name, ContentProvider provider, int flags) {
+        if ((flags & STABLE) != 0) {
+            mProviders.put(name, provider);
+        }
+        if ((flags & UNSTABLE) != 0) {
+            mUnstableProviders.put(name, provider);
+        }
     }
 
     @Override
@@ -98,7 +119,7 @@
 
     @Override
     protected IContentProvider acquireUnstableProvider(Context c, String name) {
-        final ContentProvider provider = mProviders.get(name);
+        final ContentProvider provider = mUnstableProviders.get(name);
         if (provider != null) {
             return provider.getIContentProvider();
         } else {
@@ -128,7 +149,8 @@
     @Override
     public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
         if (!mFallbackToExisting) return;
-        if (!mProviders.containsKey(uri.getAuthority())) {
+        if (!mProviders.containsKey(uri.getAuthority())
+                && !mUnstableProviders.containsKey(uri.getAuthority())) {
             super.notifyChange(uri, observer, syncToNetwork);
         }
     }
diff --git a/tests/testables/tests/src/android/testing/TestableContentResolverTest.java b/tests/testables/tests/src/android/testing/TestableContentResolverTest.java
new file mode 100644
index 0000000..71afda0
--- /dev/null
+++ b/tests/testables/tests/src/android/testing/TestableContentResolverTest.java
@@ -0,0 +1,61 @@
+package android.testing;
+
+import android.content.ContentProvider;
+import android.content.IContentProvider;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class TestableContentResolverTest {
+
+    @Rule
+    public TestableContext mContext = new TestableContext(InstrumentationRegistry.getContext());
+    private TestableContentResolver mContentResolver;
+
+    @Before
+    public void setup() {
+        mContentResolver = new TestableContentResolver(mContext);
+        mContentResolver.setFallbackToExisting(false);
+    }
+
+    @Test
+    public void testDefaultContentProvider() {
+        ContentProvider provider = Mockito.mock(ContentProvider.class);
+        IContentProvider iprovider = Mockito.mock(IContentProvider.class);
+        Mockito.when(provider.getIContentProvider()).thenReturn(iprovider);
+        mContentResolver.addProvider("test", provider);
+
+        Assert.assertEquals(iprovider, mContentResolver.acquireProvider(mContext, "test"));
+        Assert.assertEquals(iprovider, mContentResolver.acquireUnstableProvider(mContext, "test"));
+    }
+
+    @Test
+    public void testStableContentProvider() {
+        ContentProvider provider = Mockito.mock(ContentProvider.class);
+        IContentProvider iprovider = Mockito.mock(IContentProvider.class);
+        Mockito.when(provider.getIContentProvider()).thenReturn(iprovider);
+        mContentResolver.addProvider("test", provider, TestableContentResolver.STABLE);
+
+        Assert.assertEquals(iprovider, mContentResolver.acquireProvider(mContext, "test"));
+        Assert.assertNull(mContentResolver.acquireUnstableProvider(mContext, "test"));
+    }
+
+    @Test
+    public void testUnstableContentProvider() {
+        ContentProvider provider = Mockito.mock(ContentProvider.class);
+        IContentProvider iprovider = Mockito.mock(IContentProvider.class);
+        Mockito.when(provider.getIContentProvider()).thenReturn(iprovider);
+        mContentResolver.addProvider("test", provider, TestableContentResolver.UNSTABLE);
+
+        Assert.assertEquals(iprovider, mContentResolver.acquireUnstableProvider(mContext, "test"));
+        Assert.assertNull(mContentResolver.acquireProvider(mContext, "test"));
+    }
+}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 66ccc6c..af44b7e 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -147,6 +147,8 @@
 
     boolean setWifiApConfiguration(in WifiConfiguration wifiConfig, String packageName);
 
+    void notifyUserOfApBandConversion(String packageName);
+
     Messenger getWifiServiceMessenger(String packageName);
 
     void enableTdls(String remoteIPAddress, boolean enable);
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 25f35d0..6963ed0 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -2170,6 +2170,21 @@
     }
 
     /**
+     * Method that triggers a notification to the user about a conversion to their saved AP config.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+    public void notifyUserOfApBandConversion() {
+        Log.d(TAG, "apBand was converted, notify the user");
+        try {
+            mService.notifyUserOfApBandConversion(mContext.getOpPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Enable/Disable TDLS on a specific local route.
      *
      * <p>