Merge "Register generic font families in Zygote"
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/RenderNodePerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/RenderNodePerfTest.java
index d18aa51..62dd124 100644
--- a/apct-tests/perftests/core/src/android/graphics/perftests/RenderNodePerfTest.java
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/RenderNodePerfTest.java
@@ -17,7 +17,6 @@
 package android.graphics.perftests;
 
 import android.graphics.Outline;
-import android.graphics.RecordingCanvas;
 import android.graphics.RenderNode;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
@@ -62,7 +61,7 @@
         final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         RenderNode node = RenderNode.create("LinearLayout", null);
         while (state.keepRunning()) {
-            node.isValid();
+            node.hasDisplayList();
         }
     }
 
@@ -71,8 +70,8 @@
         final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         RenderNode node = RenderNode.create("LinearLayout", null);
         while (state.keepRunning()) {
-            RecordingCanvas canvas = node.start(100, 100);
-            node.end(canvas);
+            node.startRecording(100, 100);
+            node.endRecording();
         }
     }
 
@@ -80,17 +79,16 @@
     public void testStartEndDeepHierarchy() {
         final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         RenderNode[] nodes = new RenderNode[30];
-        RecordingCanvas[] canvases = new RecordingCanvas[nodes.length];
         for (int i = 0; i < nodes.length; i++) {
             nodes[i] = RenderNode.create("LinearLayout", null);
         }
 
         while (state.keepRunning()) {
             for (int i = 0; i < nodes.length; i++) {
-                canvases[i] = nodes[i].start(100, 100);
+                nodes[i].startRecording(100, 100);
             }
             for (int i = nodes.length - 1; i >= 0; i--) {
-                nodes[i].end(canvases[i]);
+                nodes[i].endRecording();
             }
         }
     }
diff --git a/apct-tests/perftests/core/src/android/text/CanvasDrawTextTest.java b/apct-tests/perftests/core/src/android/text/CanvasDrawTextTest.java
new file mode 100644
index 0000000..ad9fb5f
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/text/CanvasDrawTextTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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 android.text;
+
+import android.graphics.RecordingCanvas;
+import android.graphics.RenderNode;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Random;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class CanvasDrawTextTest {
+    private static final int WORD_LENGTH = 9;  // Random word has 9 characters.
+
+    private static final TextPaint PAINT = new TextPaint();
+
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    private TextPerfUtils mTextUtil = new TextPerfUtils();
+
+    @Before
+    public void setUp() {
+        mTextUtil.resetRandom(0 /* seed */);
+    }
+
+    @Test
+    public void drawText_LongText_SmallWindow() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final String text = mTextUtil.nextRandomParagraph(
+                WORD_LENGTH, 4 * 1024 * 1024 /* 4mb text */).toString();
+        final RenderNode node = RenderNode.create("benchmark", null);
+        final RenderNode child = RenderNode.create("child", null);
+        child.setLeftTopRightBottom(50, 50, 100, 100);
+
+        RecordingCanvas canvas = node.start(100, 100);
+        node.end(canvas);
+        canvas = child.start(50, 50);
+        child.end(canvas);
+
+        final Random r = new Random(0);
+
+        while (state.keepRunning()) {
+            int start = r.nextInt(text.length() - 100);
+            canvas.drawText(text, start, start + 100, 0, 0, PAINT);
+        }
+    }
+}
diff --git a/apct-tests/perftests/core/src/android/text/TextPerfUtils.java b/apct-tests/perftests/core/src/android/text/TextPerfUtils.java
index 22e516a..2a98ebf 100644
--- a/apct-tests/perftests/core/src/android/text/TextPerfUtils.java
+++ b/apct-tests/perftests/core/src/android/text/TextPerfUtils.java
@@ -65,18 +65,23 @@
     }
 
     public CharSequence nextRandomParagraph(int wordLen, boolean applyRandomStyle, String setStr) {
-        return nextRandomParagraph(wordLen, applyRandomStyle, UnicodeSetToArray(setStr));
+        return nextRandomParagraph(wordLen, PARA_LENGTH, applyRandomStyle,
+                UnicodeSetToArray(setStr));
     }
 
     public CharSequence nextRandomParagraph(int wordLen, boolean applyRandomStyle) {
-        return nextRandomParagraph(wordLen, applyRandomStyle, ALPHABET);
+        return nextRandomParagraph(wordLen, PARA_LENGTH, applyRandomStyle, ALPHABET);
     }
 
-    public CharSequence nextRandomParagraph(int wordLen, boolean applyRandomStyle,
+    public CharSequence nextRandomParagraph(int wordLen, int paraLength) {
+        return nextRandomParagraph(wordLen, paraLength, false /* no style */, ALPHABET);
+    }
+
+    public CharSequence nextRandomParagraph(int wordLen, int paraLength, boolean applyRandomStyle,
             String[] charSet) {
         ArrayList<Character> chars = new ArrayList<>();
         ArrayList<Integer> wordOffsets = new ArrayList<>();
-        for (int i = 0; i < PARA_LENGTH; i++) {
+        for (int i = 0; i < paraLength; i++) {
             if (i % (wordLen + 1) == wordLen) {
                 chars.add(' ');
                 wordOffsets.add(chars.size());
diff --git a/apct-tests/perftests/core/src/android/view/ViewShowHidePerfTest.java b/apct-tests/perftests/core/src/android/view/ViewShowHidePerfTest.java
index 6159da4..dc4d4bd 100644
--- a/apct-tests/perftests/core/src/android/view/ViewShowHidePerfTest.java
+++ b/apct-tests/perftests/core/src/android/view/ViewShowHidePerfTest.java
@@ -155,7 +155,7 @@
     }
 
     private void updateAndValidateDisplayList(View view) {
-        boolean hasDisplayList = view.updateDisplayListIfDirty().isValid();
+        boolean hasDisplayList = view.updateDisplayListIfDirty().hasDisplayList();
         assertTrue(hasDisplayList);
     }
 
diff --git a/api/current.txt b/api/current.txt
index 15392b8..2d6c68c 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -5217,6 +5217,7 @@
     ctor public Notification(android.os.Parcel);
     method public android.app.Notification clone();
     method public int describeContents();
+    method public android.app.PendingIntent getAppOverlayIntent();
     method public int getBadgeIconType();
     method public java.lang.String getChannelId();
     method public java.lang.String getGroup();
@@ -5446,6 +5447,7 @@
     method public android.app.Notification.Style getStyle();
     method public static android.app.Notification.Builder recoverBuilder(android.content.Context, android.app.Notification);
     method public android.app.Notification.Builder setActions(android.app.Notification.Action...);
+    method public android.app.Notification.Builder setAppOverlayIntent(android.app.PendingIntent);
     method public android.app.Notification.Builder setAutoCancel(boolean);
     method public android.app.Notification.Builder setBadgeIconType(int);
     method public android.app.Notification.Builder setCategory(java.lang.String);
@@ -5663,6 +5665,7 @@
   public final class NotificationChannel implements android.os.Parcelable {
     ctor public NotificationChannel(java.lang.String, java.lang.CharSequence, int);
     method public boolean canBypassDnd();
+    method public boolean canOverlayApps();
     method public boolean canShowBadge();
     method public int describeContents();
     method public void enableLights(boolean);
@@ -5678,6 +5681,7 @@
     method public android.net.Uri getSound();
     method public long[] getVibrationPattern();
     method public boolean hasUserSetImportance();
+    method public void setAllowAppOverlay(boolean);
     method public void setBypassDnd(boolean);
     method public void setDescription(java.lang.String);
     method public void setGroup(java.lang.String);
@@ -5697,6 +5701,7 @@
 
   public final class NotificationChannelGroup implements android.os.Parcelable {
     ctor public NotificationChannelGroup(java.lang.String, java.lang.CharSequence);
+    method public boolean canOverlayApps();
     method public android.app.NotificationChannelGroup clone();
     method public int describeContents();
     method public java.util.List<android.app.NotificationChannel> getChannels();
@@ -5704,6 +5709,7 @@
     method public java.lang.String getId();
     method public java.lang.CharSequence getName();
     method public boolean isBlocked();
+    method public void setAllowAppOverlay(boolean);
     method public void setDescription(java.lang.String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.NotificationChannelGroup> CREATOR;
@@ -16068,10 +16074,10 @@
 
   public class BiometricManager {
     method public int canAuthenticate();
-    field public static final int ERROR_NONE = 0; // 0x0
-    field public static final int ERROR_NO_BIOMETRICS = 11; // 0xb
-    field public static final int ERROR_NO_HARDWARE = 12; // 0xc
-    field public static final int ERROR_UNAVAILABLE = 1; // 0x1
+    field public static final int BIOMETRIC_ERROR_NO_BIOMETRICS = 11; // 0xb
+    field public static final int BIOMETRIC_ERROR_NO_HARDWARE = 12; // 0xc
+    field public static final int BIOMETRIC_ERROR_UNAVAILABLE = 1; // 0x1
+    field public static final int BIOMETRIC_SUCCESS = 0; // 0x0
   }
 
   public class BiometricPrompt {
@@ -36803,10 +36809,12 @@
     method public static android.net.Uri getMediaScannerUri();
     method public static android.net.Uri getMediaUri(android.content.Context, android.net.Uri);
     method public static java.lang.String getVersion(android.content.Context);
+    method public static java.lang.String getVolumeName(android.net.Uri);
     field public static final java.lang.String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE";
     field public static final java.lang.String ACTION_IMAGE_CAPTURE_SECURE = "android.media.action.IMAGE_CAPTURE_SECURE";
     field public static final java.lang.String ACTION_VIDEO_CAPTURE = "android.media.action.VIDEO_CAPTURE";
     field public static final java.lang.String AUTHORITY = "media";
+    field public static final android.net.Uri AUTHORITY_URI;
     field public static final java.lang.String EXTRA_DURATION_LIMIT = "android.intent.extra.durationLimit";
     field public static final java.lang.String EXTRA_FINISH_ON_COMPLETION = "android.intent.extra.finishOnCompletion";
     field public static final java.lang.String EXTRA_FULL_SCREEN = "android.intent.extra.fullScreen";
@@ -37597,6 +37605,7 @@
     field public static final java.lang.String AUTH_TYPE = "authtype";
     field public static final deprecated java.lang.String BEARER = "bearer";
     field public static final java.lang.String CARRIER_ENABLED = "carrier_enabled";
+    field public static final java.lang.String CARRIER_ID = "carrier_id";
     field public static final android.net.Uri CONTENT_URI;
     field public static final java.lang.String CURRENT = "current";
     field public static final java.lang.String DEFAULT_SORT_ORDER = "name ASC";
@@ -43141,7 +43150,7 @@
     method public static int getDefaultSmsSubscriptionId();
     method public static int getDefaultSubscriptionId();
     method public static int getDefaultVoiceSubscriptionId();
-    method public java.util.List<android.telephony.SubscriptionInfo> getOpportunisticSubscriptions(int);
+    method public java.util.List<android.telephony.SubscriptionInfo> getOpportunisticSubscriptions();
     method public static int getSlotIndex(int);
     method public static int[] getSubscriptionIds(int);
     method public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int);
diff --git a/api/system-current.txt b/api/system-current.txt
index 4512fc3..43616cd 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -987,8 +987,8 @@
     field public static final java.lang.String ACTION_PRE_BOOT_COMPLETED = "android.intent.action.PRE_BOOT_COMPLETED";
     field public static final java.lang.String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART";
     field public static final java.lang.String ACTION_RESOLVE_INSTANT_APP_PACKAGE = "android.intent.action.RESOLVE_INSTANT_APP_PACKAGE";
-    field public static final java.lang.String ACTION_REVIEW_PERMISSION_USAGE = "android.intent.action.REVIEW_PERMISSION_USAGE";
     field public static final java.lang.String ACTION_REVIEW_PERMISSIONS = "android.intent.action.REVIEW_PERMISSIONS";
+    field public static final java.lang.String ACTION_REVIEW_PERMISSION_USAGE = "android.intent.action.REVIEW_PERMISSION_USAGE";
     field public static final java.lang.String ACTION_SHOW_SUSPENDED_APP_DETAILS = "android.intent.action.SHOW_SUSPENDED_APP_DETAILS";
     field public static final deprecated java.lang.String ACTION_SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
     field public static final java.lang.String ACTION_SPLIT_CONFIGURATION_CHANGED = "android.intent.action.SPLIT_CONFIGURATION_CHANGED";
@@ -4154,8 +4154,11 @@
     method public deprecated int getUserRestrictionSource(java.lang.String, android.os.UserHandle);
     method public java.util.List<android.os.UserManager.EnforcingUser> getUserRestrictionSources(java.lang.String, android.os.UserHandle);
     method public boolean hasRestrictedProfiles();
+    method public boolean isAdminUser();
+    method public boolean isGuestUser();
     method public boolean isManagedProfile();
     method public boolean isManagedProfile(int);
+    method public boolean isPrimaryUser();
     method public boolean isRestrictedProfile();
     field public static final java.lang.String ACTION_USER_RESTRICTIONS_CHANGED = "android.os.action.USER_RESTRICTIONS_CHANGED";
     field public static final deprecated java.lang.String DISALLOW_OEM_UNLOCK = "no_oem_unlock";
@@ -5493,6 +5496,7 @@
     method public int getRadioPowerState();
     method public int getSimApplicationState();
     method public int getSimCardState();
+    method public int getSupportedRadioAccessFamily();
     method public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms();
     method public android.telephony.UiccSlotInfo[] getUiccSlotsInfo();
     method public android.os.Bundle getVisualVoicemailSettings();
@@ -5558,6 +5562,24 @@
     field public static final int NETWORK_MODE_TDSCDMA_WCDMA = 14; // 0xe
     field public static final int NETWORK_MODE_WCDMA_ONLY = 2; // 0x2
     field public static final int NETWORK_MODE_WCDMA_PREF = 0; // 0x0
+    field public static final int NETWORK_TYPE_BITMASK_1xRTT = 128; // 0x80
+    field public static final int NETWORK_TYPE_BITMASK_CDMA = 16; // 0x10
+    field public static final int NETWORK_TYPE_BITMASK_EDGE = 4; // 0x4
+    field public static final int NETWORK_TYPE_BITMASK_EHRPD = 16384; // 0x4000
+    field public static final int NETWORK_TYPE_BITMASK_EVDO_0 = 32; // 0x20
+    field public static final int NETWORK_TYPE_BITMASK_EVDO_A = 64; // 0x40
+    field public static final int NETWORK_TYPE_BITMASK_EVDO_B = 4096; // 0x1000
+    field public static final int NETWORK_TYPE_BITMASK_GPRS = 2; // 0x2
+    field public static final int NETWORK_TYPE_BITMASK_GSM = 65536; // 0x10000
+    field public static final int NETWORK_TYPE_BITMASK_HSDPA = 256; // 0x100
+    field public static final int NETWORK_TYPE_BITMASK_HSPA = 1024; // 0x400
+    field public static final int NETWORK_TYPE_BITMASK_HSPAP = 32768; // 0x8000
+    field public static final int NETWORK_TYPE_BITMASK_HSUPA = 512; // 0x200
+    field public static final int NETWORK_TYPE_BITMASK_LTE = 8192; // 0x2000
+    field public static final int NETWORK_TYPE_BITMASK_LTE_CA = 524288; // 0x80000
+    field public static final int NETWORK_TYPE_BITMASK_TD_SCDMA = 131072; // 0x20000
+    field public static final int NETWORK_TYPE_BITMASK_UMTS = 8; // 0x8
+    field public static final int NETWORK_TYPE_BITMASK_UNKNOWN = 1; // 0x1
     field public static final int RADIO_POWER_OFF = 0; // 0x0
     field public static final int RADIO_POWER_ON = 1; // 0x1
     field public static final int RADIO_POWER_UNAVAILABLE = 2; // 0x2
diff --git a/api/test-current.txt b/api/test-current.txt
index 0e3d84e..8f08c71 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -140,7 +140,10 @@
   }
 
   public final class NotificationChannelGroup implements android.os.Parcelable {
+    method public int getUserLockedFields();
+    method public void lockFields(int);
     method public void setBlocked(boolean);
+    field public static final int USER_LOCKED_ALLOW_APP_OVERLAY = 2; // 0x2
   }
 
   public class NotificationManager {
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 2f69ac1..bce1820 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -2404,25 +2404,28 @@
  * Logs the memory stats for a native process (from procfs).
  */
 message NativeProcessMemoryState {
-  // The uid if available. -1 means not available.
-  optional int32 uid = 1 [(is_uid) = true];
+    // The uid if available. -1 means not available.
+    optional int32 uid = 1 [(is_uid) = true];
 
-  // The process name.
-  optional string process_name = 2;
+    // The process name.
+    optional string process_name = 2;
 
-  // # of page-faults
-  optional int64 page_fault = 3;
+    // # of page-faults
+    optional int64 page_fault = 3;
 
-  // # of major page-faults
-  optional int64 page_major_fault = 4;
+    // # of major page-faults
+    optional int64 page_major_fault = 4;
 
-  // RSS
-  optional int64 rss_in_bytes = 5;
+    // RSS
+    optional int64 rss_in_bytes = 5;
 
-  // RSS high watermark.
-  // Peak RSS usage of the process. Value is read from the VmHWM field in /proc/PID/status or
-  // from memory.max_usage_in_bytes under /dev/memcg if the device uses per-app memory cgroups.
-  optional int64 rss_high_watermark_in_bytes = 6;
+    // RSS high watermark.
+    // Peak RSS usage of the process. Value is read from the VmHWM field in /proc/PID/status.
+    optional int64 rss_high_watermark_in_bytes = 6;
+
+    // Elapsed real time when the process started.
+    // Value is read from /proc/PID/stat, field 22.
+    optional int64 start_time_nanos = 7;
 }
 
 /*
@@ -3117,4 +3120,4 @@
     optional int64 user_time_millis = 3;
     // Process cpu time in system space, cumulative from boot/process start
     optional int64 system_time_millis = 4;
-}
\ No newline at end of file
+}
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index ba626f8..73a88c1 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -172,7 +172,7 @@
           new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}},
         // native_process_memory_state
         {android::util::NATIVE_PROCESS_MEMORY_STATE,
-         {{3, 4, 5, 6},
+         {{3, 4, 5, 6, 7},
           {2},
           1 * NS_PER_SEC,
           new StatsCompanionServicePuller(android::util::NATIVE_PROCESS_MEMORY_STATE)}},
diff --git a/config/hiddenapi-vendor-list.txt b/config/hiddenapi-vendor-list.txt
index e5e64d3..4275bd4 100644
--- a/config/hiddenapi-vendor-list.txt
+++ b/config/hiddenapi-vendor-list.txt
@@ -120,7 +120,6 @@
 Landroid/os/SystemVibrator;-><init>()V
 Landroid/os/UserHandle;->isSameApp(II)Z
 Landroid/os/UserManager;->hasUserRestriction(Ljava/lang/String;Landroid/os/UserHandle;)Z
-Landroid/os/UserManager;->isAdminUser()Z
 Landroid/R$styleable;->CheckBoxPreference:[I
 Landroid/telephony/ims/compat/feature/MMTelFeature;-><init>()V
 Landroid/telephony/ims/compat/ImsService;-><init>()V
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 4756bf4..3b2a21e 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -23,6 +23,8 @@
 import static android.app.servertransaction.ActivityLifecycleItem.ON_START;
 import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP;
 import static android.app.servertransaction.ActivityLifecycleItem.PRE_ON_CREATE;
+import static android.content.ContentResolver.DEPRECATE_DATA_COLUMNS;
+import static android.content.ContentResolver.DEPRECATE_DATA_PREFIX;
 import static android.view.Display.INVALID_DISPLAY;
 
 import android.annotation.NonNull;
@@ -45,6 +47,7 @@
 import android.content.ComponentCallbacks2;
 import android.content.ComponentName;
 import android.content.ContentProvider;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.IContentProvider;
 import android.content.IIntentReceiver;
@@ -84,6 +87,7 @@
 import android.os.Debug;
 import android.os.DropBoxManager;
 import android.os.Environment;
+import android.os.FileUtils;
 import android.os.GraphicsEnvironment;
 import android.os.Handler;
 import android.os.HandlerExecutor;
@@ -114,6 +118,9 @@
 import android.renderscript.RenderScriptCacheDir;
 import android.security.NetworkSecurityPolicy;
 import android.security.net.config.NetworkSecurityConfigProvider;
+import android.system.ErrnoException;
+import android.system.OsConstants;
+import android.system.StructStat;
 import android.util.AndroidRuntimeException;
 import android.util.ArrayMap;
 import android.util.DisplayMetrics;
@@ -162,13 +169,16 @@
 
 import libcore.io.DropBox;
 import libcore.io.EventLogger;
+import libcore.io.ForwardingOs;
 import libcore.io.IoUtils;
+import libcore.io.Os;
 import libcore.net.event.NetworkEventDispatcher;
 
 import org.apache.harmony.dalvik.ddmc.DdmVmInternal;
 
 import java.io.File;
 import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
@@ -392,6 +402,9 @@
         = new ArrayMap<Activity, ArrayList<OnActivityPausedListener>>();
 
     final GcIdler mGcIdler = new GcIdler();
+    final PurgeIdler mPurgeIdler = new PurgeIdler();
+
+    boolean mPurgeIdlerScheduled = false;
     boolean mGcIdlerScheduled = false;
 
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
@@ -1681,6 +1694,7 @@
         public static final int RUN_ISOLATED_ENTRY_POINT = 158;
         public static final int EXECUTE_TRANSACTION = 159;
         public static final int RELAUNCH_ACTIVITY = 160;
+        public static final int PURGE_RESOURCES = 161;
 
         String codeToString(int code) {
             if (DEBUG_MESSAGES) {
@@ -1724,6 +1738,7 @@
                     case RUN_ISOLATED_ENTRY_POINT: return "RUN_ISOLATED_ENTRY_POINT";
                     case EXECUTE_TRANSACTION: return "EXECUTE_TRANSACTION";
                     case RELAUNCH_ACTIVITY: return "RELAUNCH_ACTIVITY";
+                    case PURGE_RESOURCES: return "PURGE_RESOURCES";
                 }
             }
             return Integer.toString(code);
@@ -1761,6 +1776,7 @@
                 case UNBIND_SERVICE:
                     Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceUnbind");
                     handleUnbindService((BindServiceData)msg.obj);
+                    schedulePurgeIdler();
                     Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                     break;
                 case SERVICE_ARGS:
@@ -1771,6 +1787,7 @@
                 case STOP_SERVICE:
                     Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceStop");
                     handleStopService((IBinder)msg.obj);
+                    schedulePurgeIdler();
                     Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                     break;
                 case CONFIGURATION_CHANGED:
@@ -1904,6 +1921,9 @@
                 case RELAUNCH_ACTIVITY:
                     handleRelaunchActivityLocally((IBinder) msg.obj);
                     break;
+                case PURGE_RESOURCES:
+                    schedulePurgeIdler();
+                    break;
             }
             Object obj = msg.obj;
             if (obj instanceof SomeArgs) {
@@ -1956,6 +1976,17 @@
         @Override
         public final boolean queueIdle() {
             doGcIfNeeded();
+            nPurgePendingResources();
+            return false;
+        }
+    }
+
+    final class PurgeIdler implements MessageQueue.IdleHandler {
+        @Override
+        public boolean queueIdle() {
+            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "purgePendingResources");
+            nPurgePendingResources();
+            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
             return false;
         }
     }
@@ -2285,6 +2316,22 @@
         mH.removeMessages(H.GC_WHEN_IDLE);
     }
 
+    void schedulePurgeIdler() {
+        if (!mPurgeIdlerScheduled) {
+            mPurgeIdlerScheduled = true;
+            Looper.myQueue().addIdleHandler(mPurgeIdler);
+        }
+        mH.removeMessages(H.PURGE_RESOURCES);
+    }
+
+    void unschedulePurgeIdler() {
+        if (mPurgeIdlerScheduled) {
+            mPurgeIdlerScheduled = false;
+            Looper.myQueue().removeIdleHandler(mPurgeIdler);
+        }
+        mH.removeMessages(H.PURGE_RESOURCES);
+    }
+
     void doGcIfNeeded() {
         mGcIdlerScheduled = false;
         final long now = SystemClock.uptimeMillis();
@@ -4586,6 +4633,7 @@
             }
             r.setState(ON_DESTROY);
         }
+        schedulePurgeIdler();
         mActivities.remove(token);
         StrictMode.decrementExpectedActivityCount(activityClass);
         return r;
@@ -6749,7 +6797,7 @@
         }
     }
 
-    private class DropBoxReporter implements DropBox.Reporter {
+    private static class DropBoxReporter implements DropBox.Reporter {
 
         private DropBoxManager dropBox;
 
@@ -6769,7 +6817,84 @@
 
         private synchronized void ensureInitialized() {
             if (dropBox == null) {
-                dropBox = (DropBoxManager) getSystemContext().getSystemService(Context.DROPBOX_SERVICE);
+                dropBox = currentActivityThread().getApplication()
+                        .getSystemService(DropBoxManager.class);
+            }
+        }
+    }
+
+    private static class AndroidOs extends ForwardingOs {
+        /**
+         * Install selective syscall interception. For example, this is used to
+         * implement special filesystem paths that will be redirected to
+         * {@link ContentResolver#openFileDescriptor(Uri, String)}.
+         */
+        public static void install() {
+            // If feature is disabled, we don't need to install
+            if (!DEPRECATE_DATA_COLUMNS) return;
+
+            // If app is modern enough, we don't need to install
+            if (VMRuntime.getRuntime().getTargetSdkVersion() >= Build.VERSION_CODES.Q) return;
+
+            // Install interception and make sure it sticks!
+            Os def = null;
+            do {
+                def = Os.getDefault();
+            } while (!Os.compareAndSetDefault(def, new AndroidOs(def)));
+        }
+
+        private AndroidOs(Os os) {
+            super(os);
+        }
+
+        private FileDescriptor openDeprecatedDataPath(String path, int mode) throws ErrnoException {
+            final Uri uri = ContentResolver.translateDeprecatedDataPath(path);
+            Log.v(TAG, "Redirecting " + path + " to " + uri);
+
+            final ContentResolver cr = currentActivityThread().getApplication()
+                    .getContentResolver();
+            try {
+                final FileDescriptor fd = new FileDescriptor();
+                fd.setInt$(cr.openFileDescriptor(uri,
+                        FileUtils.translateModePosixToString(mode)).detachFd());
+                return fd;
+            } catch (FileNotFoundException e) {
+                throw new ErrnoException(e.getMessage(), OsConstants.ENOENT);
+            }
+        }
+
+        @Override
+        public boolean access(String path, int mode) throws ErrnoException {
+            if (path != null && path.startsWith(DEPRECATE_DATA_PREFIX)) {
+                // If we opened it okay, then access check succeeded
+                IoUtils.closeQuietly(
+                        openDeprecatedDataPath(path, FileUtils.translateModeAccessToPosix(mode)));
+                return true;
+            } else {
+                return super.access(path, mode);
+            }
+        }
+
+        @Override
+        public FileDescriptor open(String path, int flags, int mode) throws ErrnoException {
+            if (path != null && path.startsWith(DEPRECATE_DATA_PREFIX)) {
+                return openDeprecatedDataPath(path, mode);
+            } else {
+                return super.open(path, flags, mode);
+            }
+        }
+
+        @Override
+        public StructStat stat(String path) throws ErrnoException {
+            if (path != null && path.startsWith(DEPRECATE_DATA_PREFIX)) {
+                final FileDescriptor fd = openDeprecatedDataPath(path, OsConstants.O_RDONLY);
+                try {
+                    return android.system.Os.fstat(fd);
+                } finally {
+                    IoUtils.closeQuietly(fd);
+                }
+            } else {
+                return super.stat(path);
             }
         }
     }
@@ -6777,6 +6902,9 @@
     public static void main(String[] args) {
         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
 
+        // Install selective syscall interception
+        AndroidOs.install();
+
         // CloseGuard defaults to true and can be quite spammy.  We
         // disable it here, but selectively enable it later (via
         // StrictMode) on debug builds, but using DropBox, not logs.
@@ -6826,6 +6954,6 @@
     }
 
     // ------------------ Regular JNI ------------------------
-
+    private native void nPurgePendingResources();
     private native void nDumpGraphicsInfo(FileDescriptor fd);
 }
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 3b05566..a30ae79 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1283,8 +1283,8 @@
             AppOpsManager.MODE_ALLOWED, // POST_NOTIFICATION
             AppOpsManager.MODE_ALLOWED, // NEIGHBORING_CELLS
             AppOpsManager.MODE_ALLOWED, // CALL_PHONE
-            AppOpsManager.MODE_ALLOWED, // READ_SMS
-            AppOpsManager.MODE_IGNORED, // WRITE_SMS
+            AppOpsManager.MODE_DEFAULT, // READ_SMS
+            AppOpsManager.MODE_DEFAULT, // WRITE_SMS
             AppOpsManager.MODE_DEFAULT, // RECEIVE_SMS
             AppOpsManager.MODE_ALLOWED, // RECEIVE_EMERGENCY_BROADCAST
             AppOpsManager.MODE_ALLOWED, // RECEIVE_MMS
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index b7b6352..fcfcc21 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -177,6 +177,7 @@
     void cancelRecentsAnimation(boolean restoreHomeStackPosition);
     void startLockTaskModeByToken(in IBinder token);
     void stopLockTaskModeByToken(in IBinder token);
+    void updateLockTaskPackages(int userId, in String[] packages);
     boolean isInLockTaskMode();
     int getLockTaskModeState();
     void setTaskDescription(in IBinder token, in ActivityManager.TaskDescription values);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 4f41da6..6d464fb 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1275,6 +1275,8 @@
     private String mShortcutId;
     private CharSequence mSettingsText;
 
+    private PendingIntent mAppOverlayIntent;
+
     /** @hide */
     @IntDef(prefix = { "GROUP_ALERT_" }, value = {
             GROUP_ALERT_ALL, GROUP_ALERT_CHILDREN, GROUP_ALERT_SUMMARY
@@ -2225,6 +2227,9 @@
         }
 
         mGroupAlertBehavior = parcel.readInt();
+        if (parcel.readInt() != 0) {
+            mAppOverlayIntent = PendingIntent.CREATOR.createFromParcel(parcel);
+        }
     }
 
     @Override
@@ -2339,6 +2344,7 @@
         that.mBadgeIcon = this.mBadgeIcon;
         that.mSettingsText = this.mSettingsText;
         that.mGroupAlertBehavior = this.mGroupAlertBehavior;
+        that.mAppOverlayIntent = this.mAppOverlayIntent;
 
         if (!heavy) {
             that.lightenPayload(); // will clean out extras
@@ -2660,6 +2666,13 @@
 
         parcel.writeInt(mGroupAlertBehavior);
 
+        if (mAppOverlayIntent != null) {
+            parcel.writeInt(1);
+            mAppOverlayIntent.writeToParcel(parcel, 0);
+        } else {
+            parcel.writeInt(0);
+        }
+
         // mUsesStandardHeader is not written because it should be recomputed in listeners
     }
 
@@ -3073,6 +3086,14 @@
     }
 
     /**
+     * Returns the intent that will be used to display app content in a floating window over the
+     * existing foreground activity.
+     */
+    public PendingIntent getAppOverlayIntent() {
+        return mAppOverlayIntent;
+    }
+
+    /**
      * The small icon representing this notification in the status bar and content view.
      *
      * @return the small icon representing this notification.
@@ -3406,6 +3427,23 @@
             return this;
         }
 
+        /**
+         * Sets the intent that will be used to display app content in a floating window
+         * over the existing foreground activity.
+         *
+         * <p>This intent will be ignored unless this notification is posted to a channel that
+         * allows {@link NotificationChannel#canOverlayApps() app overlays}.</p>
+         *
+         * <p>Notifications with a valid and allowed app overlay intent will be displayed as
+         * floating windows outside of the notification shade on unlocked devices. When a user
+         * interacts with one of these windows, this app overlay intent will be invoked and
+         * displayed.</p>
+         */
+        public Builder setAppOverlayIntent(PendingIntent intent) {
+            mN.mAppOverlayIntent = intent;
+            return this;
+        }
+
         /** @removed */
         @Deprecated
         public Builder setChannel(String channelId) {
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 9f93e17..41ceaaf 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -15,6 +15,8 @@
  */
 package android.app;
 
+import static android.app.NotificationManager.IMPORTANCE_HIGH;
+
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
@@ -41,6 +43,7 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.Arrays;
+import java.util.Objects;
 
 /**
  * A representation of settings that apply to a collection of similarly themed notifications.
@@ -81,6 +84,7 @@
     private static final String ATT_FG_SERVICE_SHOWN = "fgservice";
     private static final String ATT_GROUP = "group";
     private static final String ATT_BLOCKABLE_SYSTEM = "blockable_system";
+    private static final String ATT_ALLOW_APP_OVERLAY = "app_overlay";
     private static final String DELIMITER = ",";
 
     /**
@@ -116,6 +120,11 @@
     /**
      * @hide
      */
+    public static final int USER_LOCKED_ALLOW_APP_OVERLAY = 0x00000100;
+
+    /**
+     * @hide
+     */
     public static final int[] LOCKABLE_FIELDS = new int[] {
             USER_LOCKED_PRIORITY,
             USER_LOCKED_VISIBILITY,
@@ -124,6 +133,7 @@
             USER_LOCKED_VIBRATION,
             USER_LOCKED_SOUND,
             USER_LOCKED_SHOW_BADGE,
+            USER_LOCKED_ALLOW_APP_OVERLAY
     };
 
     private static final int DEFAULT_LIGHT_COLOR = 0;
@@ -133,6 +143,7 @@
             NotificationManager.IMPORTANCE_UNSPECIFIED;
     private static final boolean DEFAULT_DELETED = false;
     private static final boolean DEFAULT_SHOW_BADGE = true;
+    private static final boolean DEFAULT_ALLOW_APP_OVERLAY = true;
 
     @UnsupportedAppUsage
     private final String mId;
@@ -156,6 +167,7 @@
     private AudioAttributes mAudioAttributes = Notification.AUDIO_ATTRIBUTES_DEFAULT;
     // If this is a blockable system notification channel.
     private boolean mBlockableSystem = false;
+    private boolean mAllowAppOverlay = DEFAULT_ALLOW_APP_OVERLAY;
 
     /**
      * Creates a notification channel.
@@ -217,6 +229,7 @@
         mAudioAttributes = in.readInt() > 0 ? AudioAttributes.CREATOR.createFromParcel(in) : null;
         mLightColor = in.readInt();
         mBlockableSystem = in.readBoolean();
+        mAllowAppOverlay = in.readBoolean();
     }
 
     @Override
@@ -269,6 +282,7 @@
         }
         dest.writeInt(mLightColor);
         dest.writeBoolean(mBlockableSystem);
+        dest.writeBoolean(mAllowAppOverlay);
     }
 
     /**
@@ -461,6 +475,22 @@
     }
 
     /**
+     * Sets whether notifications posted to this channel can appear outside of the notification
+     * shade, floating over other apps' content.
+     *
+     * <p>This value will be ignored for channels that aren't allowed to pop on screen (that is,
+     * channels whose {@link #getImportance() importance} is <
+     * {@link NotificationManager#IMPORTANCE_HIGH}.</p>
+     *
+     * <p>Only modifiable before the channel is submitted to
+     *      * {@link NotificationManager#createNotificationChannel(NotificationChannel)}.</p>
+     * @see Notification#getAppOverlayIntent()
+     */
+    public void setAllowAppOverlay(boolean allowAppOverlay) {
+        mAllowAppOverlay = allowAppOverlay;
+    }
+
+    /**
      * Returns the id of this channel.
      */
     public String getId() {
@@ -573,6 +603,22 @@
     }
 
     /**
+     * Returns whether notifications posted to this channel can display outside of the notification
+     * shade, in a floating window on top of other apps.
+     */
+    public boolean canOverlayApps() {
+        return isAppOverlayAllowed() && getImportance() >= IMPORTANCE_HIGH;
+    }
+
+    /**
+     * Like {@link #canOverlayApps()}, but only checks the permission, not the importance.
+     * @hide
+     */
+    public boolean isAppOverlayAllowed() {
+        return mAllowAppOverlay;
+    }
+
+    /**
      * @hide
      */
     @SystemApi
@@ -605,6 +651,7 @@
     /**
      * Returns whether the user has chosen the importance of this channel, either to affirm the
      * initial selection from the app, or changed it to be higher or lower.
+     * @see #getImportance()
      */
     public boolean hasUserSetImportance() {
         return (mUserLockedFields & USER_LOCKED_IMPORTANCE) != 0;
@@ -652,6 +699,7 @@
         lockFields(safeInt(parser, ATT_USER_LOCKED, 0));
         setFgServiceShown(safeBool(parser, ATT_FG_SERVICE_SHOWN, false));
         setBlockableSystem(safeBool(parser, ATT_BLOCKABLE_SYSTEM, false));
+        setAllowAppOverlay(safeBool(parser, ATT_ALLOW_APP_OVERLAY, DEFAULT_ALLOW_APP_OVERLAY));
     }
 
     @Nullable
@@ -770,6 +818,9 @@
         if (isBlockableSystem()) {
             out.attribute(null, ATT_BLOCKABLE_SYSTEM, Boolean.toString(isBlockableSystem()));
         }
+        if (canOverlayApps() != DEFAULT_ALLOW_APP_OVERLAY) {
+            out.attribute(null, ATT_ALLOW_APP_OVERLAY, Boolean.toString(canOverlayApps()));
+        }
 
         out.endTag(null, TAG_CHANNEL);
     }
@@ -812,6 +863,7 @@
         record.put(ATT_DELETED, Boolean.toString(isDeleted()));
         record.put(ATT_GROUP, getGroup());
         record.put(ATT_BLOCKABLE_SYSTEM, isBlockableSystem());
+        record.put(ATT_ALLOW_APP_OVERLAY, canOverlayApps());
         return record;
     }
 
@@ -899,58 +951,36 @@
     public boolean equals(Object o) {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
-
         NotificationChannel that = (NotificationChannel) o;
-
-        if (getImportance() != that.getImportance()) return false;
-        if (mBypassDnd != that.mBypassDnd) return false;
-        if (getLockscreenVisibility() != that.getLockscreenVisibility()) return false;
-        if (mLights != that.mLights) return false;
-        if (getLightColor() != that.getLightColor()) return false;
-        if (getUserLockedFields() != that.getUserLockedFields()) return false;
-        if (mVibrationEnabled != that.mVibrationEnabled) return false;
-        if (mShowBadge != that.mShowBadge) return false;
-        if (isDeleted() != that.isDeleted()) return false;
-        if (isBlockableSystem() != that.isBlockableSystem()) return false;
-        if (getId() != null ? !getId().equals(that.getId()) : that.getId() != null) return false;
-        if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) {
-            return false;
-        }
-        if (getDescription() != null ? !getDescription().equals(that.getDescription())
-                : that.getDescription() != null) {
-            return false;
-        }
-        if (getSound() != null ? !getSound().equals(that.getSound()) : that.getSound() != null) {
-            return false;
-        }
-        if (!Arrays.equals(mVibration, that.mVibration)) return false;
-        if (getGroup() != null ? !getGroup().equals(that.getGroup()) : that.getGroup() != null) {
-            return false;
-        }
-        return getAudioAttributes() != null ? getAudioAttributes().equals(that.getAudioAttributes())
-                : that.getAudioAttributes() == null;
-
+        return getImportance() == that.getImportance() &&
+                mBypassDnd == that.mBypassDnd &&
+                getLockscreenVisibility() == that.getLockscreenVisibility() &&
+                mLights == that.mLights &&
+                getLightColor() == that.getLightColor() &&
+                getUserLockedFields() == that.getUserLockedFields() &&
+                isFgServiceShown() == that.isFgServiceShown() &&
+                mVibrationEnabled == that.mVibrationEnabled &&
+                mShowBadge == that.mShowBadge &&
+                isDeleted() == that.isDeleted() &&
+                isBlockableSystem() == that.isBlockableSystem() &&
+                mAllowAppOverlay == that.mAllowAppOverlay &&
+                Objects.equals(getId(), that.getId()) &&
+                Objects.equals(getName(), that.getName()) &&
+                Objects.equals(mDesc, that.mDesc) &&
+                Objects.equals(getSound(), that.getSound()) &&
+                Arrays.equals(mVibration, that.mVibration) &&
+                Objects.equals(getGroup(), that.getGroup()) &&
+                Objects.equals(getAudioAttributes(), that.getAudioAttributes());
     }
 
     @Override
     public int hashCode() {
-        int result = getId() != null ? getId().hashCode() : 0;
-        result = 31 * result + (getName() != null ? getName().hashCode() : 0);
-        result = 31 * result + (getDescription() != null ? getDescription().hashCode() : 0);
-        result = 31 * result + getImportance();
-        result = 31 * result + (mBypassDnd ? 1 : 0);
-        result = 31 * result + getLockscreenVisibility();
-        result = 31 * result + (getSound() != null ? getSound().hashCode() : 0);
-        result = 31 * result + (mLights ? 1 : 0);
-        result = 31 * result + getLightColor();
+        int result = Objects.hash(getId(), getName(), mDesc, getImportance(), mBypassDnd,
+                getLockscreenVisibility(), getSound(), mLights, getLightColor(),
+                getUserLockedFields(),
+                isFgServiceShown(), mVibrationEnabled, mShowBadge, isDeleted(), getGroup(),
+                getAudioAttributes(), isBlockableSystem(), mAllowAppOverlay);
         result = 31 * result + Arrays.hashCode(mVibration);
-        result = 31 * result + getUserLockedFields();
-        result = 31 * result + (mVibrationEnabled ? 1 : 0);
-        result = 31 * result + (mShowBadge ? 1 : 0);
-        result = 31 * result + (isDeleted() ? 1 : 0);
-        result = 31 * result + (getGroup() != null ? getGroup().hashCode() : 0);
-        result = 31 * result + (getAudioAttributes() != null ? getAudioAttributes().hashCode() : 0);
-        result = 31 * result + (isBlockableSystem() ? 1 : 0);
         return result;
     }
 
@@ -976,6 +1006,7 @@
                 + ", mGroup='" + mGroup + '\''
                 + ", mAudioAttributes=" + mAudioAttributes
                 + ", mBlockableSystem=" + mBlockableSystem
+                + ", mAllowAppOverlay=" + mAllowAppOverlay
                 + '}';
         pw.println(prefix + output);
     }
@@ -1001,6 +1032,7 @@
                 + ", mGroup='" + mGroup + '\''
                 + ", mAudioAttributes=" + mAudioAttributes
                 + ", mBlockableSystem=" + mBlockableSystem
+                + ", mAllowAppOverlay=" + mAllowAppOverlay
                 + '}';
     }
 
@@ -1034,6 +1066,7 @@
             mAudioAttributes.writeToProto(proto, NotificationChannelProto.AUDIO_ATTRIBUTES);
         }
         proto.write(NotificationChannelProto.IS_BLOCKABLE_SYSTEM, mBlockableSystem);
+        proto.write(NotificationChannelProto.ALLOW_APP_OVERLAY, mAllowAppOverlay);
 
         proto.end(token);
     }
diff --git a/core/java/android/app/NotificationChannelGroup.java b/core/java/android/app/NotificationChannelGroup.java
index 17c5cba..2322a42 100644
--- a/core/java/android/app/NotificationChannelGroup.java
+++ b/core/java/android/app/NotificationChannelGroup.java
@@ -32,6 +32,7 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * A grouping of related notification channels. e.g., channels that all belong to a single account.
@@ -49,13 +50,33 @@
     private static final String ATT_DESC = "desc";
     private static final String ATT_ID = "id";
     private static final String ATT_BLOCKED = "blocked";
+    private static final String ATT_ALLOW_APP_OVERLAY = "app_overlay";
+    private static final String ATT_USER_LOCKED = "locked";
 
+    private static final boolean DEFAULT_ALLOW_APP_OVERLAY = true;
+
+    /**
+     * @hide
+     */
+    public static final int USER_LOCKED_BLOCKED_STATE = 0x00000001;
+    /**
+     * @hide
+     */
+    @TestApi
+    public static final int USER_LOCKED_ALLOW_APP_OVERLAY = 0x00000002;
+
+    /**
+     * @see #getId()
+     */
     @UnsupportedAppUsage
     private final String mId;
     private CharSequence mName;
     private String mDescription;
     private boolean mBlocked;
     private List<NotificationChannel> mChannels = new ArrayList<>();
+    private boolean mAllowAppOverlay = DEFAULT_ALLOW_APP_OVERLAY;
+    // Bitwise representation of fields that have been changed by the user
+    private int mUserLockedFields;
 
     /**
      * Creates a notification channel group.
@@ -89,6 +110,8 @@
         }
         in.readParcelableList(mChannels, NotificationChannel.class.getClassLoader());
         mBlocked = in.readBoolean();
+        mAllowAppOverlay = in.readBoolean();
+        mUserLockedFields = in.readInt();
     }
 
     private String getTrimmedString(String input) {
@@ -115,6 +138,8 @@
         }
         dest.writeParcelableList(mChannels, flags);
         dest.writeBoolean(mBlocked);
+        dest.writeBoolean(mAllowAppOverlay);
+        dest.writeInt(mUserLockedFields);
     }
 
     /**
@@ -156,6 +181,15 @@
     }
 
     /**
+     * Returns whether notifications posted to this channel group can display outside of the
+     * notification shade, in a floating window on top of other apps. These may additionally be
+     * blocked at the notification channel level, see {@link NotificationChannel#canOverlayApps()}.
+     */
+    public boolean canOverlayApps() {
+        return mAllowAppOverlay;
+    }
+
+    /**
      * Sets the user visible description of this group.
      *
      * <p>The recommended maximum length is 300 characters; the value may be truncated if it is too
@@ -166,6 +200,21 @@
     }
 
     /**
+     * Sets whether notifications posted to this channel group can appear outside of the
+     * notification shade, floating over other apps' content.
+     *
+     * <p>This value will be ignored for notifications that are posted to channels that do not
+     * allow app overlays ({@link NotificationChannel#canOverlayApps()}.
+     *
+     * <p>Only modifiable before the channel is submitted to
+     * {@link NotificationManager#createNotificationChannelGroup(NotificationChannelGroup)}.</p>
+     * @see Notification#getAppOverlayIntent()
+     */
+    public void setAllowAppOverlay(boolean allowAppOverlay) {
+        mAllowAppOverlay = allowAppOverlay;
+    }
+
+    /**
      * @hide
      */
     @TestApi
@@ -190,10 +239,34 @@
     /**
      * @hide
      */
+    @TestApi
+    public void lockFields(int field) {
+        mUserLockedFields |= field;
+    }
+
+    /**
+     * @hide
+     */
+    public void unlockFields(int field) {
+        mUserLockedFields &= ~field;
+    }
+
+    /**
+     * @hide
+     */
+    @TestApi
+    public int getUserLockedFields() {
+        return mUserLockedFields;
+    }
+
+    /**
+     * @hide
+     */
     public void populateFromXml(XmlPullParser parser) {
         // Name, id, and importance are set in the constructor.
         setDescription(parser.getAttributeValue(null, ATT_DESC));
         setBlocked(safeBool(parser, ATT_BLOCKED, false));
+        setAllowAppOverlay(safeBool(parser, ATT_ALLOW_APP_OVERLAY, DEFAULT_ALLOW_APP_OVERLAY));
     }
 
     private static boolean safeBool(XmlPullParser parser, String att, boolean defValue) {
@@ -216,6 +289,10 @@
             out.attribute(null, ATT_DESC, getDescription().toString());
         }
         out.attribute(null, ATT_BLOCKED, Boolean.toString(isBlocked()));
+        if (canOverlayApps() != DEFAULT_ALLOW_APP_OVERLAY) {
+            out.attribute(null, ATT_ALLOW_APP_OVERLAY, Boolean.toString(canOverlayApps()));
+        }
+        out.attribute(null, ATT_USER_LOCKED, Integer.toString(mUserLockedFields));
 
         out.endTag(null, TAG_GROUP);
     }
@@ -230,6 +307,8 @@
         record.put(ATT_NAME, getName());
         record.put(ATT_DESC, getDescription());
         record.put(ATT_BLOCKED, isBlocked());
+        record.put(ATT_ALLOW_APP_OVERLAY, canOverlayApps());
+        record.put(ATT_USER_LOCKED, mUserLockedFields);
         return record;
     }
 
@@ -255,30 +334,20 @@
     public boolean equals(Object o) {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
-
         NotificationChannelGroup that = (NotificationChannelGroup) o;
-
-        if (isBlocked() != that.isBlocked()) return false;
-        if (getId() != null ? !getId().equals(that.getId()) : that.getId() != null) return false;
-        if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) {
-            return false;
-        }
-        if (getDescription() != null ? !getDescription().equals(that.getDescription())
-                : that.getDescription() != null) {
-            return false;
-        }
-        return getChannels() != null ? getChannels().equals(that.getChannels())
-                : that.getChannels() == null;
+        return isBlocked() == that.isBlocked() &&
+                mAllowAppOverlay == that.mAllowAppOverlay &&
+                mUserLockedFields == that.mUserLockedFields &&
+                Objects.equals(getId(), that.getId()) &&
+                Objects.equals(getName(), that.getName()) &&
+                Objects.equals(getDescription(), that.getDescription()) &&
+                Objects.equals(getChannels(), that.getChannels());
     }
 
     @Override
     public int hashCode() {
-        int result = getId() != null ? getId().hashCode() : 0;
-        result = 31 * result + (getName() != null ? getName().hashCode() : 0);
-        result = 31 * result + (getDescription() != null ? getDescription().hashCode() : 0);
-        result = 31 * result + (isBlocked() ? 1 : 0);
-        result = 31 * result + (getChannels() != null ? getChannels().hashCode() : 0);
-        return result;
+        return Objects.hash(getId(), getName(), getDescription(), isBlocked(), getChannels(),
+                mAllowAppOverlay, mUserLockedFields);
     }
 
     @Override
@@ -287,6 +356,8 @@
         cloned.setDescription(getDescription());
         cloned.setBlocked(isBlocked());
         cloned.setChannels(getChannels());
+        cloned.setAllowAppOverlay(canOverlayApps());
+        cloned.lockFields(mUserLockedFields);
         return cloned;
     }
 
@@ -298,6 +369,8 @@
                 + ", mDescription=" + (!TextUtils.isEmpty(mDescription) ? "hasDescription " : "")
                 + ", mBlocked=" + mBlocked
                 + ", mChannels=" + mChannels
+                + ", mAllowAppOverlay=" + mAllowAppOverlay
+                + ", mUserLockedFields=" + mUserLockedFields
                 + '}';
     }
 
@@ -312,7 +385,7 @@
         for (NotificationChannel channel : mChannels) {
             channel.writeToProto(proto, NotificationChannelGroupProto.CHANNELS);
         }
-
+        proto.write(NotificationChannelGroupProto.ALLOW_APP_OVERLAY, mAllowAppOverlay);
         proto.end(token);
     }
 }
diff --git a/core/java/android/app/ProcessMemoryState.java b/core/java/android/app/ProcessMemoryState.java
index 9bfdae0..d149243 100644
--- a/core/java/android/app/ProcessMemoryState.java
+++ b/core/java/android/app/ProcessMemoryState.java
@@ -33,10 +33,11 @@
     public final long cacheInBytes;
     public final long swapInBytes;
     public final long rssHighWatermarkInBytes;
+    public final long startTimeNanos;
 
     public ProcessMemoryState(int uid, String processName, int oomScore, long pgfault,
                               long pgmajfault, long rssInBytes, long cacheInBytes,
-                              long swapInBytes, long rssHighWatermarkInBytes) {
+                              long swapInBytes, long rssHighWatermarkInBytes, long startTimeNanos) {
         this.uid = uid;
         this.processName = processName;
         this.oomScore = oomScore;
@@ -46,6 +47,7 @@
         this.cacheInBytes = cacheInBytes;
         this.swapInBytes = swapInBytes;
         this.rssHighWatermarkInBytes = rssHighWatermarkInBytes;
+        this.startTimeNanos = startTimeNanos;
     }
 
     private ProcessMemoryState(Parcel in) {
@@ -58,6 +60,7 @@
         cacheInBytes = in.readLong();
         swapInBytes = in.readLong();
         rssHighWatermarkInBytes = in.readLong();
+        startTimeNanos = in.readLong();
     }
 
     public static final Creator<ProcessMemoryState> CREATOR = new Creator<ProcessMemoryState>() {
@@ -88,5 +91,6 @@
         parcel.writeLong(cacheInBytes);
         parcel.writeLong(swapInBytes);
         parcel.writeLong(rssHighWatermarkInBytes);
+        parcel.writeLong(startTimeNanos);
     }
 }
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index a2a6b9b..4de1dfc 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -52,7 +52,9 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.os.storage.StorageManager;
 import android.text.TextUtils;
 import android.util.EventLog;
 import android.util.Log;
@@ -88,6 +90,30 @@
  */
 public abstract class ContentResolver {
     /**
+     * Enables logic that supports deprecation of {@code _data} columns,
+     * typically by replacing values with fake paths that the OS then offers to
+     * redirect to {@link #openFileDescriptor(Uri, String)}, which developers
+     * should be using directly.
+     *
+     * @hide
+     */
+    public static final boolean DEPRECATE_DATA_COLUMNS = SystemProperties
+            .getBoolean(StorageManager.PROP_ISOLATED_STORAGE, false);
+
+    /**
+     * Special filesystem path prefix which indicates that a path should be
+     * treated as a {@code content://} {@link Uri} when
+     * {@link #DEPRECATE_DATA_COLUMNS} is enabled.
+     * <p>
+     * The remainder of the path after this prefix is a
+     * {@link Uri#getSchemeSpecificPart()} value, which includes authority, path
+     * segments, and query parameters.
+     *
+     * @hide
+     */
+    public static final String DEPRECATE_DATA_PREFIX = "/mnt/content/";
+
+    /**
      * @deprecated instead use
      * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)}
      */
@@ -3261,4 +3287,16 @@
             e.rethrowFromSystemServer();
         }
     }
+
+    /** {@hide} */
+    public static Uri translateDeprecatedDataPath(String path) {
+        final String ssp = "//" + path.substring(DEPRECATE_DATA_PREFIX.length());
+        return Uri.parse(new Uri.Builder().scheme(SCHEME_CONTENT)
+                .encodedOpaquePart(ssp).build().toString());
+    }
+
+    /** {@hide} */
+    public static String translateDeprecatedDataPath(Uri uri) {
+        return DEPRECATE_DATA_PREFIX + uri.getEncodedSchemeSpecificPart().substring(2);
+    }
 }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index ea1a2fe..5ab643c 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -5285,6 +5285,7 @@
             FLAG_RECEIVER_EXCLUDE_BACKGROUND,
             FLAG_RECEIVER_FROM_SHELL,
             FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS,
+            FLAG_RECEIVER_OFFLOAD,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface Flags {}
@@ -5329,6 +5330,7 @@
             FLAG_RECEIVER_EXCLUDE_BACKGROUND,
             FLAG_RECEIVER_FROM_SHELL,
             FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS,
+            FLAG_RECEIVER_OFFLOAD,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface MutableFlags {}
@@ -5755,6 +5757,12 @@
      */
     public static final int FLAG_RECEIVER_FOREGROUND = 0x10000000;
     /**
+     * If set, when sending a broadcast the recipient will be run on the offload queue.
+     *
+     * @hide
+     */
+    public static final int FLAG_RECEIVER_OFFLOAD = 0x80000000;
+    /**
      * If this is an ordered broadcast, don't allow receivers to abort the broadcast.
      * They can still propagate results through to later receivers, but they can not prevent
      * later receivers from seeing the broadcast.
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 4f58321..6f49cc4 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -703,6 +703,18 @@
     public abstract SparseArray<String> getAppsWithSharedUserIds();
 
     /**
+     * Get the value of attribute android:sharedUserId for the given packageName if specified,
+     * otherwise {@code null}.
+     */
+    public abstract String getSharedUserIdForPackage(@NonNull String packageName);
+
+    /**
+     * Get all packages which specified the given sharedUserId as android:sharedUserId attribute
+     * or an empty array if no package specified it.
+     */
+    public abstract String[] getPackagesForSharedUserId(@NonNull String sharedUserId, int userId);
+
+    /**
      * Return if device is currently in a "core" boot environment, typically
      * used to support full-disk encryption. Only apps marked with
      * {@code coreApp} attribute are available.
diff --git a/core/java/android/hardware/biometrics/BiometricConstants.java b/core/java/android/hardware/biometrics/BiometricConstants.java
index 2a64c2e..c814b7c 100644
--- a/core/java/android/hardware/biometrics/BiometricConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricConstants.java
@@ -38,7 +38,7 @@
      * BiometricManager.
      * @hide
      */
-    int BIOMETRIC_ERROR_NONE = 0;
+    int BIOMETRIC_SUCCESS = 0;
 
     /**
      * The hardware is unavailable. Try again later.
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index 1d40001..fe00604 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -35,24 +35,31 @@
     /**
      * No error detected.
      */
-    public static final int ERROR_NONE = BiometricConstants.BIOMETRIC_ERROR_NONE;
+    public static final int BIOMETRIC_SUCCESS =
+            BiometricConstants.BIOMETRIC_SUCCESS;
 
     /**
      * The hardware is unavailable. Try again later.
      */
-    public static final int ERROR_UNAVAILABLE = BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE;
+    public static final int BIOMETRIC_ERROR_UNAVAILABLE =
+            BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE;
 
     /**
      * The user does not have any biometrics enrolled.
      */
-    public static final int ERROR_NO_BIOMETRICS = BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS;
+    public static final int BIOMETRIC_ERROR_NO_BIOMETRICS =
+            BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS;
 
     /**
      * There is no biometric hardware.
      */
-    public static final int ERROR_NO_HARDWARE = BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT;
+    public static final int BIOMETRIC_ERROR_NO_HARDWARE =
+            BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT;
 
-    @IntDef({ERROR_NONE, ERROR_UNAVAILABLE, ERROR_NO_BIOMETRICS, ERROR_NO_HARDWARE})
+    @IntDef({BIOMETRIC_SUCCESS,
+            BIOMETRIC_ERROR_UNAVAILABLE,
+            BIOMETRIC_ERROR_NO_BIOMETRICS,
+            BIOMETRIC_ERROR_NO_HARDWARE})
     @interface BiometricError {}
 
     private final Context mContext;
@@ -72,9 +79,10 @@
      * Determine if biometrics can be used. In other words, determine if {@link BiometricPrompt}
      * can be expected to be shown (hardware available, templates enrolled, user-enabled).
      *
-     * @return Returns {@link #ERROR_NO_BIOMETRICS} if the user does not have any enrolled, or
-     *     {@link #ERROR_UNAVAILABLE} if none are currently supported/enabled. Returns
-     *     {@link #ERROR_NONE} if a biometric can currently be used (enrolled and available).
+     * @return Returns {@link #BIOMETRIC_ERROR_NO_BIOMETRICS} if the user does not have any
+     *     enrolled, or {@link #BIOMETRIC_ERROR_UNAVAILABLE} if none are currently
+     *     supported/enabled. Returns {@link #BIOMETRIC_SUCCESS} if a biometric can currently be
+     *     used (enrolled and available).
      */
     @RequiresPermission(USE_BIOMETRIC)
     public @BiometricError int canAuthenticate() {
@@ -86,7 +94,7 @@
             }
         } else {
             Slog.w(TAG, "hasEnrolledBiometrics(): Service not connected");
-            return ERROR_UNAVAILABLE;
+            return BIOMETRIC_ERROR_UNAVAILABLE;
         }
     }
 
diff --git a/core/java/android/net/UidRange.aidl b/core/java/android/net/UidRange.aidl
new file mode 100644
index 0000000..f70fc8e
--- /dev/null
+++ b/core/java/android/net/UidRange.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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 android.net;
+
+/**
+ * An inclusive range of UIDs.
+ *
+ * {@hide}
+ */
+parcelable UidRange;
\ No newline at end of file
diff --git a/core/java/android/net/UidRange.java b/core/java/android/net/UidRange.java
index 3164929..793c82d 100644
--- a/core/java/android/net/UidRange.java
+++ b/core/java/android/net/UidRange.java
@@ -19,17 +19,14 @@
 import static android.os.UserHandle.PER_USER_RANGE;
 
 import android.os.Parcel;
-import android.os.Parcelable;
 
 /**
  * An inclusive range of UIDs.
  *
  * @hide
  */
-public final class UidRange implements Parcelable {
-    public final int start;
-    public final int stop;
-
+public final class UidRange extends UidRangeParcel {
+    private UidRange() {}
     public UidRange(int startUid, int stopUid) {
         if (startUid < 0) throw new IllegalArgumentException("Invalid start UID.");
         if (stopUid < 0) throw new IllegalArgumentException("Invalid stop UID.");
@@ -89,26 +86,18 @@
         return start + "-" + stop;
     }
 
-    // implement the Parcelable interface
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(start);
-        dest.writeInt(stop);
-    }
+    /**
+     * DO NOT override "writeToParcel" and "readFromParcel" in this class.
+     * The parceling code is autogenerated by the superclass.
+     */
 
     public static final Creator<UidRange> CREATOR =
         new Creator<UidRange>() {
             @Override
             public UidRange createFromParcel(Parcel in) {
-                int start = in.readInt();
-                int stop = in.readInt();
-
-                return new UidRange(start, stop);
+                UidRange obj = new UidRange();
+                obj.readFromParcel(in);
+                return obj;
             }
             @Override
             public UidRange[] newArray(int size) {
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index f71fdd7..0b90f54 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -22,16 +22,19 @@
 import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
 import static android.os.ParcelFileDescriptor.MODE_TRUNCATE;
 import static android.os.ParcelFileDescriptor.MODE_WRITE_ONLY;
+import static android.system.OsConstants.F_OK;
 import static android.system.OsConstants.O_APPEND;
 import static android.system.OsConstants.O_CREAT;
 import static android.system.OsConstants.O_RDONLY;
 import static android.system.OsConstants.O_RDWR;
 import static android.system.OsConstants.O_TRUNC;
 import static android.system.OsConstants.O_WRONLY;
+import static android.system.OsConstants.R_OK;
 import static android.system.OsConstants.SPLICE_F_MORE;
 import static android.system.OsConstants.SPLICE_F_MOVE;
 import static android.system.OsConstants.S_ISFIFO;
 import static android.system.OsConstants.S_ISREG;
+import static android.system.OsConstants.W_OK;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -1300,6 +1303,23 @@
     }
 
     /** {@hide} */
+    public static int translateModeAccessToPosix(int mode) {
+        if (mode == F_OK) {
+            // There's not an exact mapping, so we attempt a read-only open to
+            // determine if a file exists
+            return O_RDONLY;
+        } else if ((mode & (R_OK | W_OK)) == (R_OK | W_OK)) {
+            return O_RDWR;
+        } else if ((mode & R_OK) == R_OK) {
+            return O_RDONLY;
+        } else if ((mode & W_OK) == W_OK) {
+            return O_WRONLY;
+        } else {
+            throw new IllegalArgumentException("Bad mode: " + mode);
+        }
+    }
+
+    /** {@hide} */
     @VisibleForTesting
     public static class MemoryPipe extends Thread implements AutoCloseable {
         private final FileDescriptor[] pipe;
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 00b989e..1a84197 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1278,6 +1278,8 @@
      * @return whether this process is running under the primary user.
      * @hide
      */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
     public boolean isPrimaryUser() {
         UserInfo user = getUserInfo(UserHandle.myUserId());
         return user != null && user.isPrimary();
@@ -1295,10 +1297,15 @@
     }
 
     /**
+     * Used to check if this process is running as an admin user. An admin user is allowed to
+     * modify or configure certain settings that aren't available to non-admin users,
+     * create and delete additional users, etc. There can be more than one admin users.
+     *
+     * @return whether this process is running under an admin user.
      * @hide
-     * Returns whether the caller is running as an admin user. There can be more than one admin
-     * user.
      */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
     public boolean isAdminUser() {
         return isUserAdmin(UserHandle.myUserId());
     }
@@ -1323,12 +1330,14 @@
     }
 
     /**
-     * Returns whether the caller is running as restricted profile. Restricted profile may have
-     * a reduced number of available apps, app restrictions and account restrictions.
-     * @return whether the user making this call is a linked user
+     * Used to check if this process is running under a restricted profile. Restricted profiles
+     * may have a reduced number of available apps, app restrictions, and account restrictions.
+     *
+     * @return whether this process is running under a restricted profile.
      * @hide
      */
     @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
     public boolean isRestrictedProfile() {
         try {
             return mService.isRestricted();
@@ -1374,10 +1383,13 @@
     }
 
     /**
-     * Checks if the calling app is running as a guest user.
-     * @return whether the caller is a guest user.
+     * Used to check if this process is running under a guest user. A guest user may be transient.
+     *
+     * @return whether this process is running under a guest user.
      * @hide
      */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
     public boolean isGuestUser() {
         UserInfo user = getUserInfo(UserHandle.myUserId());
         return user != null && user.isGuest();
diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java
index 63ff7b2..816a730 100644
--- a/core/java/android/os/storage/StorageManagerInternal.java
+++ b/core/java/android/os/storage/StorageManagerInternal.java
@@ -101,9 +101,11 @@
      * Delete storage sandbox for the given package.
      *
      * @param packageName The package for which the sandbox needs to be destroyed.
+     * @param sharedUserId The sharedUserId if specified by the package.
      * @param userId The userId in which the sandbox needs to be destroyed.
      */
-    public abstract void destroySandboxForApp(@NonNull String packageName, int userId);
+    public abstract void destroySandboxForApp(@NonNull String packageName,
+            @Nullable String sharedUserId, int userId);
 
     /**
      * @return Labels of storage volumes that are visible to the given userId.
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 0aab76e..1fce8e6 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -60,7 +60,10 @@
 public final class MediaStore {
     private final static String TAG = "MediaStore";
 
+    /** The authority for the media provider */
     public static final String AUTHORITY = "media";
+    /** A content:// style uri to the authority for the media provider */
+    public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
 
     private static final String CONTENT_AUTHORITY_SLASH = "content://" + AUTHORITY + "/";
 
@@ -2254,6 +2257,18 @@
     }
 
     /**
+     * Return the volume name that the given {@link Uri} references.
+     */
+    public static @NonNull String getVolumeName(@NonNull Uri uri) {
+        final List<String> segments = uri.getPathSegments();
+        if (uri.getAuthority().equals(AUTHORITY) && segments != null && segments.size() > 0) {
+            return segments.get(0);
+        } else {
+            throw new IllegalArgumentException("Not a media Uri: " + uri);
+        }
+    }
+
+    /**
      * Uri for querying the state of the media scanner.
      */
     public static Uri getMediaScannerUri() {
diff --git a/core/java/android/view/GhostView.java b/core/java/android/view/GhostView.java
index 98ed217..74c801b 100644
--- a/core/java/android/view/GhostView.java
+++ b/core/java/android/view/GhostView.java
@@ -52,7 +52,7 @@
             RecordingCanvas dlCanvas = (RecordingCanvas) canvas;
             mView.mRecreateDisplayList = true;
             RenderNode renderNode = mView.updateDisplayListIfDirty();
-            if (renderNode.isValid()) {
+            if (renderNode.hasDisplayList()) {
                 dlCanvas.insertReorderBarrier(); // enable shadow for this rendernode
                 dlCanvas.drawRenderNode(renderNode);
                 dlCanvas.insertInorderBarrier(); // re-disable reordering/shadows
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 9aab419..a4d3ce7 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -26,6 +26,7 @@
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.graphics.Canvas;
+import android.os.Build;
 import android.os.Handler;
 import android.os.Message;
 import android.os.Trace;
@@ -78,7 +79,7 @@
      * This field should be made private, so it is hidden from the SDK.
      * {@hide}
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     protected final Context mContext;
 
     // these are optional, set by the caller
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index c1ab4d4..f0f4c1c 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -694,7 +694,7 @@
         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Record View#draw()");
         updateViewTreeDisplayList(view);
 
-        if (mRootNodeNeedsUpdate || !mRootNode.isValid()) {
+        if (mRootNodeNeedsUpdate || !mRootNode.hasDisplayList()) {
             RecordingCanvas canvas = mRootNode.start(mSurfaceWidth, mSurfaceHeight);
             try {
                 final int saveCount = canvas.save();
@@ -857,7 +857,7 @@
 
 
     void buildLayer(RenderNode node) {
-        if (node.isValid()) {
+        if (node.hasDisplayList()) {
             nBuildLayer(mNativeProxy, node.mNativeRenderNode);
         }
     }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 1157b28..1493cd7 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -16658,7 +16658,7 @@
     @UnsupportedAppUsage
     void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) {
         if (!isHardwareAccelerated()
-                || !mRenderNode.isValid()
+                || !mRenderNode.hasDisplayList()
                 || (mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) {
             if (invalidateParent) {
                 invalidateParentCaches();
@@ -19047,7 +19047,7 @@
         switch (mLayerType) {
             case LAYER_TYPE_HARDWARE:
                 updateDisplayListIfDirty();
-                if (attachInfo.mThreadedRenderer != null && mRenderNode.isValid()) {
+                if (attachInfo.mThreadedRenderer != null && mRenderNode.hasDisplayList()) {
                     attachInfo.mThreadedRenderer.buildLayer(mRenderNode);
                 }
                 break;
@@ -19214,11 +19214,11 @@
         }
 
         if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0
-                || !renderNode.isValid()
+                || !renderNode.hasDisplayList()
                 || (mRecreateDisplayList)) {
             // Don't need to recreate the display list, just need to tell our
             // children to restore/recreate theirs
-            if (renderNode.isValid()
+            if (renderNode.hasDisplayList()
                     && !mRecreateDisplayList) {
                 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
                 mPrivateFlags &= ~PFLAG_DIRTY_MASK;
@@ -19235,7 +19235,7 @@
             int height = mBottom - mTop;
             int layerType = getLayerType();
 
-            final RecordingCanvas canvas = renderNode.start(width, height);
+            final RecordingCanvas canvas = renderNode.startRecording(width, height);
 
             try {
                 if (layerType == LAYER_TYPE_SOFTWARE) {
@@ -19266,7 +19266,7 @@
                     }
                 }
             } finally {
-                renderNode.end(canvas);
+                renderNode.endRecording();
                 setDisplayListProperties(renderNode);
             }
         } else {
@@ -20118,7 +20118,7 @@
             // Delay getting the display list until animation-driven alpha values are
             // set up and possibly passed on to the view
             renderNode = updateDisplayListIfDirty();
-            if (!renderNode.isValid()) {
+            if (!renderNode.hasDisplayList()) {
                 // Uncommon, but possible. If a view is removed from the hierarchy during the call
                 // to getDisplayList(), the display list will be marked invalid and we should not
                 // try to use it again.
@@ -20581,7 +20581,7 @@
             mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode);
 
             final RenderNode renderNode = mBackgroundRenderNode;
-            if (renderNode != null && renderNode.isValid()) {
+            if (renderNode != null && renderNode.hasDisplayList()) {
                 setBackgroundRenderNodeProperties(renderNode);
                 ((RecordingCanvas) canvas).drawRenderNode(renderNode);
                 return;
@@ -20635,7 +20635,7 @@
         final Rect bounds = drawable.getBounds();
         final int width = bounds.width();
         final int height = bounds.height();
-        final RecordingCanvas canvas = renderNode.start(width, height);
+        final RecordingCanvas canvas = renderNode.startRecording(width, height);
 
         // Reverse left/top translation done by drawable canvas, which will
         // instead be applied by rendernode's LTRB bounds below. This way, the
@@ -20646,7 +20646,7 @@
         try {
             drawable.draw(canvas);
         } finally {
-            renderNode.end(canvas);
+            renderNode.endRecording();
         }
 
         // Set up drawable properties that are view-independent.
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 48c164f..feef853 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -257,7 +257,7 @@
             needsToBeShifted = true;
         }
         boolean needsRecord() {
-            return isDirty || !renderNode.isValid();
+            return isDirty || !renderNode.hasDisplayList();
         }
     }
     private TextRenderNode[] mTextRenderNodes;
@@ -542,7 +542,7 @@
             for (int i = 0; i < mTextRenderNodes.length; i++) {
                 RenderNode displayList = mTextRenderNodes[i] != null
                         ? mTextRenderNodes[i].renderNode : null;
-                if (displayList != null && displayList.isValid()) {
+                if (displayList != null && displayList.hasDisplayList()) {
                     displayList.discardDisplayList();
                 }
             }
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 59c29e2..c96aaba 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -42,6 +42,7 @@
         "com_google_android_gles_jni_EGLImpl.cpp",
         "com_google_android_gles_jni_GLImpl.cpp", // TODO: .arm
         "android_app_Activity.cpp",
+	"android_app_ActivityThread.cpp",
         "android_app_NativeActivity.cpp",
         "android_app_admin_SecurityLog.cpp",
         "android_opengl_EGL14.cpp",
diff --git a/core/jni/android_app_ActivityThread.cpp b/core/jni/android_app_ActivityThread.cpp
new file mode 100644
index 0000000..d56e4c5
--- /dev/null
+++ b/core/jni/android_app_ActivityThread.cpp
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#include "jni.h"
+#include "GraphicsJNI.h"
+#include <nativehelper/JNIHelp.h>
+
+#include <minikin/Layout.h>
+#include <renderthread/RenderProxy.h>
+
+#include "core_jni_helpers.h"
+#include <unistd.h>
+
+namespace android {
+
+static void android_app_ActivityThread_purgePendingResources(JNIEnv* env, jobject clazz) {
+    // Don't care about return values.
+    mallopt(M_PURGE, 0);
+}
+
+static void
+android_app_ActivityThread_dumpGraphics(JNIEnv* env, jobject clazz, jobject javaFileDescriptor) {
+    int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
+    android::uirenderer::renderthread::RenderProxy::dumpGraphicsMemory(fd);
+    minikin::Layout::dumpMinikinStats(fd);
+}
+
+
+static JNINativeMethod gActivityThreadMethods[] = {
+    // ------------ Regular JNI ------------------
+    { "nPurgePendingResources",        "()V",
+      (void*) android_app_ActivityThread_purgePendingResources },
+    { "nDumpGraphicsInfo",        "(Ljava/io/FileDescriptor;)V",
+      (void*) android_app_ActivityThread_dumpGraphics }
+};
+
+int register_android_app_ActivityThread(JNIEnv* env) {
+    return RegisterMethodsOrDie(env, "android/app/ActivityThread",
+            gActivityThreadMethods, NELEM(gActivityThreadMethods));
+}
+
+};
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index dca2da3..84f53468 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -523,10 +523,11 @@
     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
     const Typeface* typeface = paint->getAndroidTypeface();
     ScopedCharArrayRO text(env, charArray);
+    // drawTextString and drawTextChars doesn't use context info
     get_canvas(canvasHandle)->drawText(
-            text.get(), text.size(),  // text buffer
-            index, count,  // draw range
-            0, text.size(),  // context range
+            text.get() + index, count,  // text buffer
+            0, count,  // draw range
+            0, count,  // context range
             x, y,  // draw position
             static_cast<minikin::Bidi>(bidiFlags), *paint, typeface, nullptr /* measured text */);
 }
@@ -537,10 +538,12 @@
     ScopedStringChars text(env, strObj);
     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
     const Typeface* typeface = paint->getAndroidTypeface();
+    const int count = end - start;
+    // drawTextString and drawTextChars doesn't use context info
     get_canvas(canvasHandle)->drawText(
-            text.get(), text.size(),  // text buffer
-            start, end - start,  // draw range
-            0, text.size(),  // context range
+            text.get() + start, count,  // text buffer
+            0, count,  // draw range
+            0, count,  // context range
             x, y,  // draw position
             static_cast<minikin::Bidi>(bidiFlags), *paint, typeface, nullptr /* measured text */);
 }
diff --git a/core/jni/android_view_DisplayListCanvas.cpp b/core/jni/android_view_DisplayListCanvas.cpp
index 8998cd7..e0fd1a6 100644
--- a/core/jni/android_view_DisplayListCanvas.cpp
+++ b/core/jni/android_view_DisplayListCanvas.cpp
@@ -88,17 +88,6 @@
     sp<InvokeRunnableMessage> mMessage;
 };
 
-
-// ---------------- Regular JNI -----------------------------
-
-static void
-android_app_ActivityThread_dumpGraphics(JNIEnv* env, jobject clazz, jobject javaFileDescriptor) {
-    int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
-    android::uirenderer::renderthread::RenderProxy::dumpGraphicsMemory(fd);
-    minikin::Layout::dumpMinikinStats(fd);
-}
-
-
 // ---------------- @FastNative -----------------------------
 
 static void android_view_DisplayListCanvas_callDrawGLFunction(JNIEnv* env, jobject clazz,
@@ -205,12 +194,6 @@
     { "nDrawRoundRect",           "(JJJJJJJJ)V",(void*) android_view_DisplayListCanvas_drawRoundRectProps },
 };
 
-static JNINativeMethod gActivityThreadMethods[] = {
-        // ------------ Regular JNI ------------------
-    { "nDumpGraphicsInfo",        "(Ljava/io/FileDescriptor;)V",
-                                               (void*) android_app_ActivityThread_dumpGraphics }
-};
-
 int register_android_view_DisplayListCanvas(JNIEnv* env) {
     jclass runnableClass = FindClassOrDie(env, "java/lang/Runnable");
     gRunnableMethodId = GetMethodIDOrDie(env, runnableClass, "run", "()V");
@@ -218,9 +201,4 @@
     return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
 }
 
-int register_android_app_ActivityThread(JNIEnv* env) {
-    return RegisterMethodsOrDie(env, "android/app/ActivityThread",
-            gActivityThreadMethods, NELEM(gActivityThreadMethods));
-}
-
 };
diff --git a/core/proto/android/app/notification_channel.proto b/core/proto/android/app/notification_channel.proto
index 75cc18b..435d32f 100644
--- a/core/proto/android/app/notification_channel.proto
+++ b/core/proto/android/app/notification_channel.proto
@@ -57,4 +57,7 @@
     // If this is a blockable system notification channel.
     optional bool is_blockable_system = 17;
     optional bool fg_service_shown = 18;
+    // Default is true.
+    // Allows the notifications to appear outside of the shade in floating windows
+    optional bool allow_app_overlay = 19;
 }
diff --git a/core/proto/android/app/notification_channel_group.proto b/core/proto/android/app/notification_channel_group.proto
index 4fb27b0..6d6ceb2 100644
--- a/core/proto/android/app/notification_channel_group.proto
+++ b/core/proto/android/app/notification_channel_group.proto
@@ -36,4 +36,7 @@
     optional string description = 3;
     optional bool is_blocked = 4;
     repeated NotificationChannelProto channels = 5;
+    // Default is true.
+    // Allows the notifications to appear outside of the shade in floating windows
+    optional bool allow_app_overlay = 6;
 }
diff --git a/core/tests/coretests/src/android/content/ContentResolverTest.java b/core/tests/coretests/src/android/content/ContentResolverTest.java
index 0036186..9940bf7 100644
--- a/core/tests/coretests/src/android/content/ContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/ContentResolverTest.java
@@ -158,4 +158,19 @@
 
         assertImageAspectAndContents(res);
     }
+
+    @Test
+    public void testTranslateDeprecatedDataPath() throws Exception {
+        assertTranslate(Uri.parse("content://com.example/path/?foo=bar&baz=meow"));
+        assertTranslate(Uri.parse("content://com.example/path/subpath/12/"));
+        assertTranslate(Uri.parse("content://com.example/path/subpath/12"));
+        assertTranslate(Uri.parse("content://com.example/path/12"));
+        assertTranslate(Uri.parse("content://com.example/"));
+        assertTranslate(Uri.parse("content://com.example"));
+    }
+
+    private static void assertTranslate(Uri uri) {
+        assertEquals(uri, ContentResolver
+                .translateDeprecatedDataPath(ContentResolver.translateDeprecatedDataPath(uri)));
+    }
 }
diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java
index 6966448..55e21a7 100644
--- a/core/tests/coretests/src/android/os/FileUtilsTest.java
+++ b/core/tests/coretests/src/android/os/FileUtilsTest.java
@@ -17,6 +17,7 @@
 package android.os;
 
 import static android.os.FileUtils.roundStorageSize;
+import static android.os.FileUtils.translateModeAccessToPosix;
 import static android.os.FileUtils.translateModePfdToPosix;
 import static android.os.FileUtils.translateModePosixToPfd;
 import static android.os.FileUtils.translateModePosixToString;
@@ -27,12 +28,16 @@
 import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
 import static android.os.ParcelFileDescriptor.MODE_TRUNCATE;
 import static android.os.ParcelFileDescriptor.MODE_WRITE_ONLY;
+import static android.system.OsConstants.F_OK;
 import static android.system.OsConstants.O_APPEND;
 import static android.system.OsConstants.O_CREAT;
 import static android.system.OsConstants.O_RDONLY;
 import static android.system.OsConstants.O_RDWR;
 import static android.system.OsConstants.O_TRUNC;
 import static android.system.OsConstants.O_WRONLY;
+import static android.system.OsConstants.R_OK;
+import static android.system.OsConstants.W_OK;
+import static android.system.OsConstants.X_OK;
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
 import static android.text.format.DateUtils.WEEK_IN_MILLIS;
@@ -525,6 +530,15 @@
         }
     }
 
+    @Test
+    public void testTranslateMode_Access() throws Exception {
+        assertEquals(O_RDONLY, translateModeAccessToPosix(F_OK));
+        assertEquals(O_RDONLY, translateModeAccessToPosix(R_OK));
+        assertEquals(O_WRONLY, translateModeAccessToPosix(W_OK));
+        assertEquals(O_RDWR, translateModeAccessToPosix(R_OK | W_OK));
+        assertEquals(O_RDWR, translateModeAccessToPosix(R_OK | W_OK | X_OK));
+    }
+
     private static void assertTranslate(String string, int posix, int pfd) {
         assertEquals(posix, translateModeStringToPosix(string));
         assertEquals(string, translateModePosixToString(posix));
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index e7a50d7..790b37e 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -1301,13 +1301,13 @@
             node.setLeftTopRightBottom(0, 0, width, height);
             node.setClipToBounds(false);
             node.setForceDarkAllowed(false);
-            final RecordingCanvas canvas = node.start(width, height);
+            final RecordingCanvas canvas = node.startRecording(width, height);
             if (source.getWidth() != width || source.getHeight() != height) {
                 canvas.scale(width / (float) source.getWidth(),
                         height / (float) source.getHeight());
             }
             canvas.drawPicture(source);
-            node.end(canvas);
+            node.endRecording();
             Bitmap bitmap = ThreadedRenderer.createHardwareBitmap(node, width, height);
             if (config != Config.HARDWARE) {
                 bitmap = bitmap.copy(config, false);
diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java
index b61488c..320fb20 100644
--- a/graphics/java/android/graphics/RenderNode.java
+++ b/graphics/java/android/graphics/RenderNode.java
@@ -19,7 +19,6 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.view.NativeVectorDrawableAnimator;
 import android.view.RenderNodeAnimator;
 import android.view.View;
@@ -33,89 +32,92 @@
 import java.lang.annotation.RetentionPolicy;
 
 /**
- * <p>A display list records a series of graphics related operations and can replay
- * them later. Display lists are usually built by recording operations on a
- * {@link RecordingCanvas}. Replaying the operations from a display list avoids
- * executing application code on every frame, and is thus much more efficient.</p>
+ * <p>RenderNode is used to build hardware accelerated rendering hierarchies. Each RenderNode
+ * contains both a display list as well as a set of properties that affect the rendering of the
+ * display list. RenderNodes are used internally for all Views by default and are not typically
+ * used directly.</p>
  *
- * <p>Display lists are used internally for all views by default, and are not
- * typically used directly. One reason to consider using a display is a custom
- * {@link View} implementation that needs to issue a large number of drawing commands.
- * When the view invalidates, all the drawing commands must be reissued, even if
- * large portions of the drawing command stream stay the same frame to frame, which
- * can become a performance bottleneck. To solve this issue, a custom View might split
- * its content into several display lists. A display list is updated only when its
- * content, and only its content, needs to be updated.</p>
+ * <p>RenderNodes are used to divide up the rendering content of a complex scene into smaller
+ * pieces that can then be updated individually more cheaply. Updating part of the scene only needs
+ * to update the display list or properties of a small number of RenderNode instead of redrawing
+ * everything from scratch. A RenderNode only needs its display list re-recorded when its content
+ * alone should be changed. RenderNodes can also be transformed without re-recording the display
+ * list through the transform properties.</p>
  *
- * <p>A text editor might for instance store each paragraph into its own display list.
+ * <p>A text editor might for instance store each paragraph into its own RenderNode.
  * Thus when the user inserts or removes characters, only the display list of the
  * affected paragraph needs to be recorded again.</p>
  *
  * <h3>Hardware acceleration</h3>
- * <p>Display lists can only be replayed using a {@link RecordingCanvas}. They are not
+ * <p>RenderNodes can be drawn using a {@link RecordingCanvas}. They are not
  * supported in software. Always make sure that the {@link android.graphics.Canvas}
  * you are using to render a display list is hardware accelerated using
  * {@link android.graphics.Canvas#isHardwareAccelerated()}.</p>
  *
- * <h3>Creating a display list</h3>
+ * <h3>Creating a RenderNode</h3>
  * <pre class="prettyprint">
- *     ThreadedRenderer renderer = myView.getThreadedRenderer();
- *     if (renderer != null) {
- *         DisplayList displayList = renderer.createDisplayList();
- *         RecordingCanvas canvas = displayList.start(width, height);
- *         try {
- *             // Draw onto the canvas
- *             // For instance: canvas.drawBitmap(...);
- *         } finally {
- *             displayList.end();
- *         }
+ *     RenderNode renderNode = RenderNode.create("myRenderNode");
+ *     renderNode.setLeftTopRightBottom(0, 0, 50, 50); // Set the size to 50x50
+ *     RecordingCanvas canvas = renderNode.startRecording();
+ *     try {
+ *         // Draw with the canvas
+ *         canvas.drawRect(...);
+ *     } finally {
+ *         renderNode.endRecording();
  *     }
  * </pre>
  *
- * <h3>Rendering a display list on a View</h3>
+ * <h3>Drawing a RenderNode in a View</h3>
  * <pre class="prettyprint">
  *     protected void onDraw(Canvas canvas) {
- *         if (canvas.isHardwareAccelerated()) {
- *             RecordingCanvas displayListCanvas = (RecordingCanvas) canvas;
- *             displayListCanvas.drawDisplayList(mDisplayList);
+ *         if (canvas instanceof RecordingCanvas) {
+ *             RecordingCanvas recordingCanvas = (RecordingCanvas) canvas;
+ *             // Check that the RenderNode has a display list, re-recording it if it does not.
+ *             if (!myRenderNode.hasDisplayList()) {
+ *                 updateDisplayList(myRenderNode);
+ *             }
+ *             // Draw the RenderNode into this canvas.
+ *             recordingCanvas.drawRenderNode(myRenderNode);
  *         }
  *     }
  * </pre>
  *
  * <h3>Releasing resources</h3>
  * <p>This step is not mandatory but recommended if you want to release resources
- * held by a display list as soon as possible.</p>
+ * held by a display list as soon as possible. Most significantly any bitmaps it may contain.</p>
  * <pre class="prettyprint">
- *     // Mark this display list invalid, it cannot be used for drawing anymore,
- *     // and release resources held by this display list
- *     displayList.clear();
+ *     // Discards the display list content allowing for any held resources to be released.
+ *     // After calling this
+ *     renderNode.discardDisplayList();
  * </pre>
  *
+ *
  * <h3>Properties</h3>
- * <p>In addition, a display list offers several properties, such as
+ * <p>In addition, a RenderNode offers several properties, such as
  * {@link #setScaleX(float)} or {@link #setLeft(int)}, that can be used to affect all
  * the drawing commands recorded within. For instance, these properties can be used
  * to move around a large number of images without re-issuing all the individual
- * <code>drawBitmap()</code> calls.</p>
+ * <code>canvas.drawBitmap()</code> calls.</p>
  *
  * <pre class="prettyprint">
  *     private void createDisplayList() {
- *         mDisplayList = DisplayList.create("MyDisplayList");
- *         RecordingCanvas canvas = mDisplayList.start(width, height);
+ *         mRenderNode = RenderNode.create("MyRenderNode");
+ *         mRenderNode.setLeftTopRightBottom(0, 0, width, height);
+ *         RecordingCanvas canvas = mRenderNode.startRecording();
  *         try {
  *             for (Bitmap b : mBitmaps) {
  *                 canvas.drawBitmap(b, 0.0f, 0.0f, null);
  *                 canvas.translate(0.0f, b.getHeight());
  *             }
  *         } finally {
- *             displayList.end();
+ *             mRenderNode.endRecording();
  *         }
  *     }
  *
  *     protected void onDraw(Canvas canvas) {
- *         if (canvas.isHardwareAccelerated()) {
- *             RecordingCanvas displayListCanvas = (RecordingCanvas) canvas;
- *             displayListCanvas.drawDisplayList(mDisplayList);
+ *         if (canvas instanceof RecordingCanvas) {
+ *             RecordingCanvas recordingCanvas = (RecordingCanvas) canvas;
+ *             recordingCanvas.drawRenderNode(mRenderNode);
  *         }
  *     }
  *
@@ -124,13 +126,16 @@
  *          // by x pixels to the right and redraw this view. All the commands
  *          // recorded in createDisplayList() won't be re-issued, only onDraw()
  *          // will be invoked and will execute very quickly
- *          mDisplayList.offsetLeftAndRight(x);
+ *          mRenderNode.offsetLeftAndRight(x);
  *          invalidate();
  *     }
  * </pre>
  *
  * <h3>Threading</h3>
- * <p>Display lists must be created on and manipulated from the UI thread only.</p>
+ * <p>RenderNode may be created and used on any thread but they are not thread-safe. Only
+ * a single thread may interact with a RenderNode at any given time. It is critical
+ * that the RenderNode is only used on the same thread it is drawn with. For example when using
+ * RenderNode with a custom View, then that RenderNode must only be used from the UI thread.</p>
  *
  * @hide
  */
@@ -147,6 +152,7 @@
      */
     public final long mNativeRenderNode;
     private final AnimationHost mAnimationHost;
+    private RecordingCanvas mCurrentRecordingCanvas;
 
     private RenderNode(String name, AnimationHost animationHost) {
         mNativeRenderNode = nCreate(name);
@@ -171,7 +177,6 @@
      *
      * @return A new RenderNode.
      */
-    @UnsupportedAppUsage
     public static RenderNode create(String name, @Nullable AnimationHost animationHost) {
         return new RenderNode(name, animationHost);
     }
@@ -226,64 +231,106 @@
      * operations performed on the returned canvas are recorded and
      * stored in this display list.
      *
-     * Calling this method will mark the render node invalid until
-     * {@link #end(RecordingCanvas)} is called.
-     * Only valid render nodes can be replayed.
+     * {@link #endRecording()} must be called when the recording is finished in order to apply
+     * the updated display list.
      *
-     * @param width The width of the recording viewport
-     * @param height The height of the recording viewport
+     * @param width The width of the recording viewport. This will not alter the width of the
+     *              RenderNode itself, that must be set with {@link #setLeft(int)} and
+     *              {@link #setRight(int)}
+     * @param height The height of the recording viewport. This will not alter the height of the
+     *               RenderNode itself, that must be set with {@link #setTop(int)} and
+     *               {@link #setBottom(int)}.
      *
      * @return A canvas to record drawing operations.
      *
-     * @see #end(RecordingCanvas)
-     * @see #isValid()
+     * @see #endRecording()
+     * @see #hasDisplayList()
      */
-    @UnsupportedAppUsage
-    public RecordingCanvas start(int width, int height) {
-        return RecordingCanvas.obtain(this, width, height);
+    public RecordingCanvas startRecording(int width, int height) {
+        if (mCurrentRecordingCanvas != null) {
+            throw new IllegalStateException(
+                    "Recording currently in progress - missing #endRecording() call?");
+        }
+        mCurrentRecordingCanvas = RecordingCanvas.obtain(this, width, height);
+        return mCurrentRecordingCanvas;
     }
 
     /**
-     * Same as {@link #start(int, int)} but with the RenderNode's width & height
+     * Same as {@link #startRecording(int, int)} with the width & height set
+     * to the RenderNode's own width & height. The RenderNode's width & height may be set
+     * with {@link #setLeftTopRightBottom(int, int, int, int)}.
      */
-    public RecordingCanvas start() {
+    public RecordingCanvas startRecording() {
         return RecordingCanvas.obtain(this,
                 nGetWidth(mNativeRenderNode), nGetHeight(mNativeRenderNode));
     }
 
     /**
-     * Ends the recording for this display list. A display list cannot be
-     * replayed if recording is not finished. Calling this method marks
-     * the display list valid and {@link #isValid()} will return true.
-     *
-     * @see #start(int, int)
-     * @see #isValid()
+     * @deprecated use {@link #startRecording(int, int)} instead
+     * @hide
      */
-    @UnsupportedAppUsage
-    public void end(RecordingCanvas canvas) {
+    @Deprecated
+    public RecordingCanvas start(int width, int height) {
+        return startRecording(width, height);
+    }
+
+    /**`
+     * Ends the recording for this display list. Calling this method marks
+     * the display list valid and {@link #hasDisplayList()} will return true.
+     *
+     * @see #startRecording(int, int)
+     * @see #hasDisplayList()
+     */
+    public void endRecording() {
+        if (mCurrentRecordingCanvas == null) {
+            throw new IllegalStateException(
+                    "No recording in progress, forgot to call #startRecording()?");
+        }
+        RecordingCanvas canvas = mCurrentRecordingCanvas;
+        mCurrentRecordingCanvas = null;
         long displayList = canvas.finishRecording();
         nSetDisplayList(mNativeRenderNode, displayList);
         canvas.recycle();
     }
 
     /**
+     * @deprecated use {@link #endRecording()} instead
+     * @hide
+     */
+    @Deprecated
+    public void end(RecordingCanvas canvas) {
+        if (mCurrentRecordingCanvas != canvas) {
+            throw new IllegalArgumentException(
+                    "Canvas given isn't the one that was returned from #startRecording");
+        }
+        endRecording();
+    }
+
+    /**
      * Reset native resources. This is called when cleaning up the state of display lists
      * during destruction of hardware resources, to ensure that we do not hold onto
      * obsolete resources after related resources are gone.
      */
-    @UnsupportedAppUsage
     public void discardDisplayList() {
         nSetDisplayList(mNativeRenderNode, 0);
     }
 
     /**
-     * Returns whether the RenderNode's display list content is currently usable.
-     * If this returns false, the display list should be re-recorded prior to replaying it.
+     * Returns whether the RenderNode has a display list. If this returns false, the RenderNode
+     * should be re-recorded with {@link #startRecording()} and {@link #endRecording()}.
      *
-     * @return boolean true if the display list is able to be replayed, false otherwise.
+     * A RenderNode without a display list may still be drawn, however it will have no impact
+     * on the rendering content until its display list is updated.
+     *
+     * When a RenderNode is no longer drawn by anything the system may automatically
+     * invoke {@link #discardDisplayList()}. It is therefore important to ensure that
+     * {@link #hasDisplayList()} is true on a RenderNode prior to drawing it.
+     *
+     * See {@link #discardDisplayList()}
+     *
+     * @return boolean true if this RenderNode has a display list, false otherwise.
      */
-    @UnsupportedAppUsage
-    public boolean isValid() {
+    public boolean hasDisplayList() {
         return nIsValid(mNativeRenderNode);
     }
 
@@ -358,7 +405,6 @@
      *
      * @param clipToBounds true if the display list should clip to its bounds
      */
-    @UnsupportedAppUsage
     public boolean setClipToBounds(boolean clipToBounds) {
         return nSetClipToBounds(mNativeRenderNode, clipToBounds);
     }
@@ -370,7 +416,6 @@
      * @param shouldProject true if the display list should be projected onto a
      *            containing volume.
      */
-    @UnsupportedAppUsage
     public boolean setProjectBackwards(boolean shouldProject) {
         return nSetProjectBackwards(mNativeRenderNode, shouldProject);
     }
@@ -521,7 +566,6 @@
      * @see android.view.View#hasOverlappingRendering()
      * @see #hasOverlappingRendering()
      */
-    @UnsupportedAppUsage
     public boolean setHasOverlappingRendering(boolean hasOverlappingRendering) {
         return nSetHasOverlappingRendering(mNativeRenderNode, hasOverlappingRendering);
     }
@@ -872,7 +916,6 @@
      * @see View#setRight(int)
      * @see View#setBottom(int)
      */
-    @UnsupportedAppUsage
     public boolean setLeftTopRightBottom(int left, int top, int right, int bottom) {
         return nSetLeftTopRightBottom(mNativeRenderNode, left, top, right, bottom);
     }
@@ -885,7 +928,6 @@
      *
      * @see View#offsetLeftAndRight(int)
      */
-    @UnsupportedAppUsage
     public boolean offsetLeftAndRight(int offset) {
         return nOffsetLeftAndRight(mNativeRenderNode, offset);
     }
@@ -906,7 +948,6 @@
      * Outputs the display list to the log. This method exists for use by
      * tools to output display lists for selected nodes to the log.
      */
-    @UnsupportedAppUsage
     public void output() {
         nOutput(mNativeRenderNode);
     }
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 9e435a5..f96b1f8 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -16,8 +16,6 @@
 
 #include "VulkanManager.h"
 
-#include <private/gui/SyncFeatures.h>
-
 #include "Properties.h"
 #include "RenderThread.h"
 #include "renderstate/RenderState.h"
@@ -1033,69 +1031,59 @@
         return INVALID_OPERATION;
     }
 
-    if (SyncFeatures::getInstance().useWaitSync() &&
-        SyncFeatures::getInstance().useNativeFenceSync()) {
-        // Block GPU on the fence.
-        int fenceFd = fence->dup();
-        if (fenceFd == -1) {
-            ALOGE("VulkanManager::fenceWait: error dup'ing fence fd: %d", errno);
-            return -errno;
-        }
-
-        VkSemaphoreCreateInfo semaphoreInfo;
-        semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
-        semaphoreInfo.pNext = nullptr;
-        semaphoreInfo.flags = 0;
-        VkSemaphore semaphore;
-        VkResult err = mCreateSemaphore(mDevice, &semaphoreInfo, nullptr, &semaphore);
-        if (VK_SUCCESS != err) {
-            ALOGE("Failed to create import semaphore, err: %d", err);
-            return UNKNOWN_ERROR;
-        }
-        VkImportSemaphoreFdInfoKHR importInfo;
-        importInfo.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR;
-        importInfo.pNext = nullptr;
-        importInfo.semaphore = semaphore;
-        importInfo.flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT;
-        importInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
-        importInfo.fd = fenceFd;
-
-        err = mImportSemaphoreFdKHR(mDevice, &importInfo);
-        if (VK_SUCCESS != err) {
-            ALOGE("Failed to import semaphore, err: %d", err);
-            return UNKNOWN_ERROR;
-        }
-
-        LOG_ALWAYS_FATAL_IF(mDummyCB == VK_NULL_HANDLE);
-
-        VkPipelineStageFlags waitDstStageFlags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
-
-        VkSubmitInfo submitInfo;
-        memset(&submitInfo, 0, sizeof(VkSubmitInfo));
-        submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
-        submitInfo.waitSemaphoreCount = 1;
-        // Wait to make sure aquire semaphore set above has signaled.
-        submitInfo.pWaitSemaphores = &semaphore;
-        submitInfo.pWaitDstStageMask = &waitDstStageFlags;
-        submitInfo.commandBufferCount = 1;
-        submitInfo.pCommandBuffers = &mDummyCB;
-        submitInfo.signalSemaphoreCount = 0;
-
-        mQueueSubmit(mGraphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
-
-        // On Android when we import a semaphore, it is imported using temporary permanence. That
-        // means as soon as we queue the semaphore for a wait it reverts to its previous permanent
-        // state before importing. This means it will now be in an idle state with no pending
-        // signal or wait operations, so it is safe to immediately delete it.
-        mDestroySemaphore(mDevice, semaphore, nullptr);
-    } else {
-        // Block CPU on the fence.
-        status_t err = fence->waitForever("VulkanManager::fenceWait");
-        if (err != NO_ERROR) {
-            ALOGE("VulkanManager::fenceWait: error waiting for fence: %d", err);
-            return err;
-        }
+    // Block GPU on the fence.
+    int fenceFd = fence->dup();
+    if (fenceFd == -1) {
+        ALOGE("VulkanManager::fenceWait: error dup'ing fence fd: %d", errno);
+        return -errno;
     }
+
+    VkSemaphoreCreateInfo semaphoreInfo;
+    semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+    semaphoreInfo.pNext = nullptr;
+    semaphoreInfo.flags = 0;
+    VkSemaphore semaphore;
+    VkResult err = mCreateSemaphore(mDevice, &semaphoreInfo, nullptr, &semaphore);
+    if (VK_SUCCESS != err) {
+        ALOGE("Failed to create import semaphore, err: %d", err);
+        return UNKNOWN_ERROR;
+    }
+    VkImportSemaphoreFdInfoKHR importInfo;
+    importInfo.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR;
+    importInfo.pNext = nullptr;
+    importInfo.semaphore = semaphore;
+    importInfo.flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT;
+    importInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
+    importInfo.fd = fenceFd;
+
+    err = mImportSemaphoreFdKHR(mDevice, &importInfo);
+    if (VK_SUCCESS != err) {
+        ALOGE("Failed to import semaphore, err: %d", err);
+        return UNKNOWN_ERROR;
+    }
+
+    LOG_ALWAYS_FATAL_IF(mDummyCB == VK_NULL_HANDLE);
+
+    VkPipelineStageFlags waitDstStageFlags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
+
+    VkSubmitInfo submitInfo;
+    memset(&submitInfo, 0, sizeof(VkSubmitInfo));
+    submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+    submitInfo.waitSemaphoreCount = 1;
+    // Wait to make sure aquire semaphore set above has signaled.
+    submitInfo.pWaitSemaphores = &semaphore;
+    submitInfo.pWaitDstStageMask = &waitDstStageFlags;
+    submitInfo.commandBufferCount = 1;
+    submitInfo.pCommandBuffers = &mDummyCB;
+    submitInfo.signalSemaphoreCount = 0;
+
+    mQueueSubmit(mGraphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
+
+    // On Android when we import a semaphore, it is imported using temporary permanence. That
+    // means as soon as we queue the semaphore for a wait it reverts to its previous permanent
+    // state before importing. This means it will now be in an idle state with no pending
+    // signal or wait operations, so it is safe to immediately delete it.
+    mDestroySemaphore(mDevice, semaphore, nullptr);
     return OK;
 }
 
@@ -1105,15 +1093,6 @@
         return INVALID_OPERATION;
     }
 
-    if (SyncFeatures::getInstance().useFenceSync()) {
-        ALOGE("VulkanManager::createReleaseFence: Vk backend doesn't support non-native fences");
-        return INVALID_OPERATION;
-    }
-
-    if (!SyncFeatures::getInstance().useNativeFenceSync()) {
-        return OK;
-    }
-
     VkExportSemaphoreCreateInfo exportInfo;
     exportInfo.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO;
     exportInfo.pNext = nullptr;
diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java
index e94413c..54b5ab1 100644
--- a/media/java/android/media/MediaPlayer2.java
+++ b/media/java/android/media/MediaPlayer2.java
@@ -1361,7 +1361,7 @@
     }
 
     /**
-     * Sets the callback to be invoked when the media source is ready for playback.
+     * Registers the callback to be invoked for various events covered by {@link EventCallback}.
      *
      * @param executor the executor through which the callback should be invoked
      * @param eventCallback the callback that will be run
@@ -1378,7 +1378,6 @@
     // This is a synchronous call.
     public abstract void unregisterEventCallback(EventCallback eventCallback);
 
-
     /* Do not change these values without updating their counterparts
      * in include/media/mediaplayer2.h!
      */
@@ -1387,7 +1386,8 @@
      */
     public static final int MEDIA_ERROR_UNKNOWN = 1;
 
-    /** The video is streamed and its container is not valid for progressive
+    /**
+     * The video is streamed and its container is not valid for progressive
      * playback i.e the video's index (e.g moov atom) is not at the start of the
      * file.
      * @see EventCallback#onError
@@ -1698,19 +1698,33 @@
      * @see EventCallback#onCallCompleted
      * @hide
      */
-    public static final int CALL_COMPLETED_SET_BUFFERING_PARAMS = 1001;
+    public static final int CALL_COMPLETED_SET_BUFFERING_PARAMS = 31;
 
-    /** The player just completed a call {@code setVideoScalingMode}.
+    /** The player just completed a call {@link #setVideoScalingMode}.
      * @see EventCallback#onCallCompleted
      * @hide
      */
-    public static final int CALL_COMPLETED_SET_VIDEO_SCALING_MODE = 1002;
+    public static final int CALL_COMPLETED_SET_VIDEO_SCALING_MODE = 32;
 
-    /** The player just completed a call {@code notifyWhenCommandLabelReached}.
+    /**
+     * The start of the methods which have separate call complete callback.
+     * @hide
+     */
+    public static final int SEPARATE_CALL_COMPLETED_CALLBACK_START = 1000;
+
+    /** The player just completed a call {@link #notifyWhenCommandLabelReached}.
      * @see EventCallback#onCommandLabelReached
      * @hide
      */
-    public static final int CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED = 1003;
+    public static final int CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED =
+            SEPARATE_CALL_COMPLETED_CALLBACK_START;
+
+    /** The player just completed a call {@link #prepareDrm}.
+     * @see DrmEventCallback#onDrmPrepared
+     * @hide
+     */
+    public static final int CALL_COMPLETED_PREPARE_DRM =
+            SEPARATE_CALL_COMPLETED_CALLBACK_START + 1;
 
     /**
      * @hide
@@ -1740,7 +1754,8 @@
             CALL_COMPLETED_CLEAR_NEXT_DATA_SOURCES,
             CALL_COMPLETED_SET_BUFFERING_PARAMS,
             CALL_COMPLETED_SET_VIDEO_SCALING_MODE,
-            CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED
+            CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED,
+            CALL_COMPLETED_PREPARE_DRM,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface CallCompleted {}
@@ -1864,20 +1879,22 @@
     }
 
     /**
-     * Sets the callback to be invoked when the media source is ready for playback.
+     * Registers the callback to be invoked for various DRM events.
      *
      * @param eventCallback the callback that will be run
      * @param executor the executor through which the callback should be invoked
      */
     // This is a synchronous call.
-    public abstract void setDrmEventCallback(@NonNull @CallbackExecutor Executor executor,
+    public abstract void registerDrmEventCallback(@NonNull @CallbackExecutor Executor executor,
             @NonNull DrmEventCallback eventCallback);
 
     /**
-     * Clears the {@link DrmEventCallback}.
+     * Unregisters the {@link DrmEventCallback}.
+     *
+     * @param eventCallback the callback to be unregistered
      */
     // This is a synchronous call.
-    public abstract void clearDrmEventCallback();
+    public abstract void unregisterDrmEventCallback(DrmEventCallback eventCallback);
 
     /**
      * The status codes for {@link DrmEventCallback#onDrmPrepared} listener.
@@ -1902,6 +1919,15 @@
      */
     public static final int PREPARE_DRM_STATUS_PREPARATION_ERROR = 3;
 
+    /**
+     * The crypto scheme UUID is not supported by the device.
+     */
+    public static final int PREPARE_DRM_STATUS_UNSUPPORTED_SCHEME = 4;
+
+    /**
+     * The hardware resources are not available, due to being in use.
+     */
+    public static final int PREPARE_DRM_STATUS_RESOURCE_BUSY = 5;
 
     /** @hide */
     @IntDef(flag = false, prefix = "PREPARE_DRM_STATUS", value = {
@@ -1909,6 +1935,8 @@
         PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR,
         PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR,
         PREPARE_DRM_STATUS_PREPARATION_ERROR,
+        PREPARE_DRM_STATUS_UNSUPPORTED_SCHEME,
+        PREPARE_DRM_STATUS_RESOURCE_BUSY,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface PrepareDrmStatusCode {}
@@ -1925,41 +1953,28 @@
      * <p>
      * If {@link OnDrmConfigHelper} is registered, it will be called during
      * preparation to allow configuration of the DRM properties before opening the
-     * DRM session. Note that the callback is called synchronously in the thread that called
-     * {@link #prepareDrm}. It should be used only for a series of {@code getDrmPropertyString}
-     * and {@code setDrmPropertyString} calls and refrain from any lengthy operation.
+     * DRM session. It should be used only for a series of {@link #getDrmPropertyString}
+     * and {@link #setDrmPropertyString} calls and refrain from any lengthy operation.
      * <p>
      * If the device has not been provisioned before, this call also provisions the device
      * which involves accessing the provisioning server and can take a variable time to
      * complete depending on the network connectivity.
-     * If {@code OnDrmPreparedListener} is registered, prepareDrm() runs in non-blocking
-     * mode by launching the provisioning in the background and returning. The listener
-     * will be called when provisioning and preparation has finished. If a
-     * {@code OnDrmPreparedListener} is not registered, prepareDrm() waits till provisioning
-     * and preparation has finished, i.e., runs in blocking mode.
+     * When needed, the provisioning will be launched  in the background.
+     * The listener {@link DrmEventCallback#onDrmPrepared}
+     * will be called when provisioning and preparation are finished. The application should
+     * check the status code returned with {@link DrmEventCallback#onDrmPrepared} to proceed.
      * <p>
-     * If {@code OnDrmPreparedListener} is registered, it is called to indicate the DRM
+     * The registered {@link DrmEventCallback#onDrmPrepared} is called to indicate the DRM
      * session being ready. The application should not make any assumption about its call
-     * sequence (e.g., before or after prepareDrm returns), or the thread context that will
-     * execute the listener (unless the listener is registered with a handler thread).
+     * sequence (e.g., before or after prepareDrm returns).
      * <p>
      *
      * @param uuid The UUID of the crypto scheme. If not known beforehand, it can be retrieved
-     * from the source through {@code getDrmInfo} or registering a {@code onDrmInfoListener}.
-     *
-     * @throws IllegalStateException              if called before being prepared or the DRM was
-     *                                            prepared already
-     * @throws UnsupportedSchemeException         if the crypto scheme is not supported
-     * @throws ResourceBusyException              if required DRM resources are in use
-     * @throws ProvisioningNetworkErrorException  if provisioning is required but failed due to a
-     *                                            network error
-     * @throws ProvisioningServerErrorException   if provisioning is required but failed due to
-     *                                            the request denied by the provisioning server
+     * from the source through {@code getDrmInfo} or registering a
+     * {@link DrmEventCallback#onDrmInfo}.
      */
-    // This is a synchronous call.
-    public abstract void prepareDrm(@NonNull UUID uuid)
-            throws UnsupportedSchemeException, ResourceBusyException,
-                   ProvisioningNetworkErrorException, ProvisioningServerErrorException;
+    // This is an asynchronous call.
+    public abstract void prepareDrm(@NonNull UUID uuid);
 
     /**
      * Releases the DRM session
@@ -2107,28 +2122,6 @@
           }
     }
 
-    /**
-     * Thrown when the device requires DRM provisioning but the provisioning attempt has
-     * failed due to a network error (Internet reachability, timeout, etc.).
-     * Extends MediaDrm.MediaDrmException
-     */
-    public abstract static class ProvisioningNetworkErrorException extends MediaDrmException {
-          protected ProvisioningNetworkErrorException(String detailMessage) {
-              super(detailMessage);
-          }
-    }
-
-    /**
-     * Thrown when the device requires DRM provisioning but the provisioning attempt has
-     * failed due to the provisioning server denying the request.
-     * Extends MediaDrm.MediaDrmException
-     */
-    public abstract static class ProvisioningServerErrorException extends MediaDrmException {
-          protected ProvisioningServerErrorException(String detailMessage) {
-              super(detailMessage);
-          }
-    }
-
     public static final class MetricsConstants {
         private MetricsConstants() {}
 
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index 6263e5d..a5eb1fb 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -2409,7 +2409,7 @@
         }
     }
 
-    public static void checkArgument(boolean expression, String errorMessage) {
+    private static void checkArgument(boolean expression, String errorMessage) {
         if (!expression) {
             throw new IllegalArgumentException(errorMessage);
         }
@@ -2473,15 +2473,8 @@
     private ArrayList<Pair<Executor, DrmEventCallback> > mDrmEventCallbackRecords
         = new ArrayList<Pair<Executor, DrmEventCallback> >();
 
-    /**
-     * Register a callback to be invoked when the media source is ready
-     * for playback.
-     *
-     * @param eventCallback the callback that will be run
-     * @param executor the executor through which the callback should be invoked
-     */
     @Override
-    public void setDrmEventCallback(@NonNull @CallbackExecutor Executor executor,
+    public void registerDrmEventCallback(@NonNull @CallbackExecutor Executor executor,
             @NonNull DrmEventCallback eventCallback) {
         if (eventCallback == null) {
             throw new IllegalArgumentException("Illegal null EventCallback");
@@ -2495,17 +2488,17 @@
         }
     }
 
-    /**
-     * Clears the {@link DrmEventCallback}.
-     */
     @Override
-    public void clearDrmEventCallback() {
+    public void unregisterDrmEventCallback(DrmEventCallback eventCallback) {
         synchronized (mDrmEventCbLock) {
-            mDrmEventCallbackRecords.clear();
+            for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
+                if (cb.second == eventCallback) {
+                    mDrmEventCallbackRecords.remove(cb);
+                }
+            }
         }
     }
 
-
     /**
      * Retrieves the DRM Info associated with the current source
      *
@@ -2532,54 +2525,80 @@
         return drmInfo;
     }
 
-
-    /**
-     * Prepares the DRM for the current source
-     * <p>
-     * If {@code OnDrmConfigHelper} is registered, it will be called during
-     * preparation to allow configuration of the DRM properties before opening the
-     * DRM session. Note that the callback is called synchronously in the thread that called
-     * {@code prepareDrm}. It should be used only for a series of {@code getDrmPropertyString}
-     * and {@code setDrmPropertyString} calls and refrain from any lengthy operation.
-     * <p>
-     * If the device has not been provisioned before, this call also provisions the device
-     * which involves accessing the provisioning server and can take a variable time to
-     * complete depending on the network connectivity.
-     * If {@code OnDrmPreparedListener} is registered, prepareDrm() runs in non-blocking
-     * mode by launching the provisioning in the background and returning. The listener
-     * will be called when provisioning and preparation has finished. If a
-     * {@code OnDrmPreparedListener} is not registered, prepareDrm() waits till provisioning
-     * and preparation has finished, i.e., runs in blocking mode.
-     * <p>
-     * If {@code OnDrmPreparedListener} is registered, it is called to indicate the DRM
-     * session being ready. The application should not make any assumption about its call
-     * sequence (e.g., before or after prepareDrm returns), or the thread context that will
-     * execute the listener (unless the listener is registered with a handler thread).
-     * <p>
-     *
-     * @param uuid The UUID of the crypto scheme. If not known beforehand, it can be retrieved
-     * from the source through {@code getDrmInfo} or registering a {@code onDrmInfoListener}.
-     *
-     * @throws IllegalStateException              if called before prepare(), or the DRM was
-     *                                            prepared already
-     * @throws UnsupportedSchemeException         if the crypto scheme is not supported
-     * @throws ResourceBusyException              if required DRM resources are in use
-     * @throws ProvisioningNetworkErrorException  if provisioning is required but failed due to a
-     *                                            network error
-     * @throws ProvisioningServerErrorException   if provisioning is required but failed due to
-     *                                            the request denied by the provisioning server
-     */
     @Override
-    public void prepareDrm(@NonNull UUID uuid)
+    public void prepareDrm(@NonNull UUID uuid) {
+        addTask(new Task(CALL_COMPLETED_PREPARE_DRM, true) {
+            @Override
+            void process() {
+                int status = PREPARE_DRM_STATUS_SUCCESS;
+                boolean sendEvent = true;
+
+                try {
+                    doPrepareDrm(uuid);
+                } catch (ResourceBusyException e) {
+                    status = PREPARE_DRM_STATUS_RESOURCE_BUSY;
+                } catch (UnsupportedSchemeException e) {
+                    status = PREPARE_DRM_STATUS_UNSUPPORTED_SCHEME;
+                } catch (NotProvisionedException e) {
+                    Log.w(TAG, "prepareDrm: NotProvisionedException");
+
+                    // handle provisioning internally; it'll reset mPrepareDrmInProgress
+                    status = HandleProvisioninig(uuid);
+
+                    if (status == PREPARE_DRM_STATUS_SUCCESS) {
+                        // DrmEventCallback will be fired in provisioning
+                        sendEvent = false;
+                    } else {
+                        synchronized (mDrmLock) {
+                            cleanDrmObj();
+                        }
+
+                        switch (status) {
+                        case PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR:
+                            Log.e(TAG, "prepareDrm: Provisioning was required but failed " +
+                                    "due to a network error.");
+                            break;
+
+                        case PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR:
+                            Log.e(TAG, "prepareDrm: Provisioning was required but the request " +
+                                    "was denied by the server.");
+                            break;
+
+                        case PREPARE_DRM_STATUS_PREPARATION_ERROR:
+                        default:
+                            Log.e(TAG, "prepareDrm: Post-provisioning preparation failed.");
+                            break;
+                        }
+                    }
+                } catch (Exception e) {
+                    status = PREPARE_DRM_STATUS_PREPARATION_ERROR;
+                }
+
+                if (sendEvent) {
+                    final int prepareDrmStatus = status;
+                    sendDrmEvent(new DrmEventNotifier() {
+                        @Override
+                        public void notify(DrmEventCallback callback) {
+                            callback.onDrmPrepared(
+                                    MediaPlayer2Impl.this, mCurrentDSD, prepareDrmStatus);
+                        }
+                    });
+
+                    synchronized (mTaskLock) {
+                        mCurrentTask = null;
+                        processPendingTask_l();
+                    }
+                }
+            }
+        });
+    }
+
+    private void doPrepareDrm(@NonNull UUID uuid)
             throws UnsupportedSchemeException, ResourceBusyException,
-                   ProvisioningNetworkErrorException, ProvisioningServerErrorException
-    {
+                   NotProvisionedException {
         Log.v(TAG, "prepareDrm: uuid: " + uuid + " mOnDrmConfigHelper: " + mOnDrmConfigHelper);
 
-        boolean allDoneWithoutProvisioning = false;
-
         synchronized (mDrmLock) {
-
             // only allowing if tied to a protected source; might relax for releasing offline keys
             if (mDrmInfoImpl == null) {
                 final String msg = "prepareDrm(): Wrong usage: The player must be prepared and " +
@@ -2623,8 +2642,7 @@
             }
 
             mDrmConfigAllowed = true;
-        }   // synchronized
-
+        }  // synchronized
 
         // call the callback outside the lock
         if (mOnDrmConfigHelper != null)  {
@@ -2640,74 +2658,28 @@
 
                 mDrmUUID = uuid;
                 mActiveDrmScheme = true;
-
-                allDoneWithoutProvisioning = true;
+                mPrepareDrmInProgress = false;
             } catch (IllegalStateException e) {
                 final String msg = "prepareDrm(): Wrong usage: The player must be " +
                         "in the prepared state to call prepareDrm().";
                 Log.e(TAG, msg);
                 earlyExit = true;
+                mPrepareDrmInProgress = false;
                 throw new IllegalStateException(msg);
             } catch (NotProvisionedException e) {
-                Log.w(TAG, "prepareDrm: NotProvisionedException");
-
-                // handle provisioning internally; it'll reset mPrepareDrmInProgress
-                int result = HandleProvisioninig(uuid);
-
-                // if blocking mode, we're already done;
-                // if non-blocking mode, we attempted to launch background provisioning
-                if (result != PREPARE_DRM_STATUS_SUCCESS) {
-                    earlyExit = true;
-                    String msg;
-
-                    switch (result) {
-                    case PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR:
-                        msg = "prepareDrm: Provisioning was required but failed " +
-                                "due to a network error.";
-                        Log.e(TAG, msg);
-                        throw new ProvisioningNetworkErrorExceptionImpl(msg);
-
-                    case PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR:
-                        msg = "prepareDrm: Provisioning was required but the request " +
-                                "was denied by the server.";
-                        Log.e(TAG, msg);
-                        throw new ProvisioningServerErrorExceptionImpl(msg);
-
-                    case PREPARE_DRM_STATUS_PREPARATION_ERROR:
-                    default: // default for safeguard
-                        msg = "prepareDrm: Post-provisioning preparation failed.";
-                        Log.e(TAG, msg);
-                        throw new IllegalStateException(msg);
-                    }
-                }
-                // nothing else to do;
-                // if blocking or non-blocking, HandleProvisioninig does the re-attempt & cleanup
+                Log.w(TAG, "prepareDrm: NotProvisionedException", e);
+                throw e;
             } catch (Exception e) {
                 Log.e(TAG, "prepareDrm: Exception " + e);
                 earlyExit = true;
+                mPrepareDrmInProgress = false;
                 throw e;
             } finally {
-                if (!mDrmProvisioningInProgress) {// if early exit other than provisioning exception
-                    mPrepareDrmInProgress = false;
-                }
-                if (earlyExit) {    // cleaning up object if didn't succeed
+                if (earlyExit) {  // clean up object if didn't succeed
                     cleanDrmObj();
                 }
-            } // finally
-        }   // synchronized
-
-
-        // if finished successfully without provisioning, call the callback outside the lock
-        if (allDoneWithoutProvisioning) {
-            sendDrmEvent(new DrmEventNotifier() {
-                @Override
-                public void notify(DrmEventCallback callback) {
-                    callback.onDrmPrepared(
-                            MediaPlayer2Impl.this, mCurrentDSD, PREPARE_DRM_STATUS_SUCCESS);
-                }
-            });
-        }
-
+            }  // finally
+        }  // synchronized
     }
 
 
@@ -3164,31 +3136,6 @@
         }
     }
 
-    /**
-     * Thrown when the device requires DRM provisioning but the provisioning attempt has
-     * failed due to a network error (Internet reachability, timeout, etc.).
-     * Extends MediaDrm.MediaDrmException
-     */
-    public static final class ProvisioningNetworkErrorExceptionImpl
-            extends ProvisioningNetworkErrorException {
-        public ProvisioningNetworkErrorExceptionImpl(String detailMessage) {
-            super(detailMessage);
-        }
-    }
-
-    /**
-     * Thrown when the device requires DRM provisioning but the provisioning attempt has
-     * failed due to the provisioning server denying the request.
-     * Extends MediaDrm.MediaDrmException
-     */
-    public static final class ProvisioningServerErrorExceptionImpl
-            extends ProvisioningServerErrorException {
-        public ProvisioningServerErrorExceptionImpl(String detailMessage) {
-            super(detailMessage);
-        }
-    }
-
-
     private native void _prepareDrm(@NonNull byte[] uuid, @NonNull byte[] drmSessionId);
 
     // Modular DRM helpers
@@ -3296,7 +3243,6 @@
         private Object drmLock;
         private MediaPlayer2Impl mediaPlayer;
         private int status;
-        private boolean finished;
         public  int status() {
             return status;
         }
@@ -3362,38 +3308,7 @@
 
             boolean succeeded = false;
 
-            boolean hasCallback = false;
-            synchronized (mDrmEventCbLock) {
-                hasCallback = !mDrmEventCallbackRecords.isEmpty();
-            }
-            // non-blocking mode needs the lock
-            if (hasCallback) {
-
-                synchronized (drmLock) {
-                    // continuing with prepareDrm
-                    if (provisioningSucceeded) {
-                        succeeded = mediaPlayer.resumePrepareDrm(uuid);
-                        status = (succeeded) ?
-                                PREPARE_DRM_STATUS_SUCCESS :
-                                PREPARE_DRM_STATUS_PREPARATION_ERROR;
-                    }
-                    mediaPlayer.mDrmProvisioningInProgress = false;
-                    mediaPlayer.mPrepareDrmInProgress = false;
-                    if (!succeeded) {
-                        cleanDrmObj();  // cleaning up if it hasn't gone through while in the lock
-                    }
-                } // synchronized
-
-                // calling the callback outside the lock
-                sendDrmEvent(new DrmEventNotifier() {
-                    @Override
-                    public void notify(DrmEventCallback callback) {
-                        callback.onDrmPrepared(
-                                mediaPlayer, mCurrentDSD, status);
-                    }
-                });
-            } else {   // blocking mode already has the lock
-
+            synchronized (drmLock) {
                 // continuing with prepareDrm
                 if (provisioningSucceeded) {
                     succeeded = mediaPlayer.resumePrepareDrm(uuid);
@@ -3404,12 +3319,28 @@
                 mediaPlayer.mDrmProvisioningInProgress = false;
                 mediaPlayer.mPrepareDrmInProgress = false;
                 if (!succeeded) {
-                    cleanDrmObj();  // cleaning up if it hasn't gone through
+                    cleanDrmObj();  // cleaning up if it hasn't gone through while in the lock
+                }
+            }  // synchronized
+
+            // calling the callback outside the lock
+            sendDrmEvent(new DrmEventNotifier() {
+                @Override
+                public void notify(DrmEventCallback callback) {
+                    callback.onDrmPrepared(
+                            mediaPlayer, mCurrentDSD, status);
+                }
+            });
+
+            synchronized (mTaskLock) {
+                if (mCurrentTask != null
+                        && mCurrentTask.mMediaCallType == CALL_COMPLETED_PREPARE_DRM
+                        && mCurrentTask.mNeedToWaitForEventToComplete) {
+                    mCurrentTask = null;
+                    processPendingTask_l();
                 }
             }
-
-            finished = true;
-        }   // run()
+        }
 
         /**
          * Returns a byte[] containing the remainder of 'in', closing it when done.
@@ -3437,50 +3368,29 @@
     }   // ProvisioningThread
 
     private int HandleProvisioninig(UUID uuid) {
-        // the lock is already held by the caller
-
-        if (mDrmProvisioningInProgress) {
-            Log.e(TAG, "HandleProvisioninig: Unexpected mDrmProvisioningInProgress");
-            return PREPARE_DRM_STATUS_PREPARATION_ERROR;
-        }
-
-        MediaDrm.ProvisionRequest provReq = mDrmObj.getProvisionRequest();
-        if (provReq == null) {
-            Log.e(TAG, "HandleProvisioninig: getProvisionRequest returned null.");
-            return PREPARE_DRM_STATUS_PREPARATION_ERROR;
-        }
-
-        Log.v(TAG, "HandleProvisioninig provReq " +
-                " data: " + provReq.getData() + " url: " + provReq.getDefaultUrl());
-
-        // networking in a background thread
-        mDrmProvisioningInProgress = true;
-
-        mDrmProvisioningThread = new ProvisioningThread().initialize(provReq, uuid, this);
-        mDrmProvisioningThread.start();
-
-        int result;
-
-        // non-blocking: this is not the final result
-        boolean hasCallback = false;
-        synchronized (mDrmEventCbLock) {
-            hasCallback = !mDrmEventCallbackRecords.isEmpty();
-        }
-        if (hasCallback) {
-            result = PREPARE_DRM_STATUS_SUCCESS;
-        } else {
-            // if blocking mode, wait till provisioning is done
-            try {
-                mDrmProvisioningThread.join();
-            } catch (Exception e) {
-                Log.w(TAG, "HandleProvisioninig: Thread.join Exception " + e);
+        synchronized (mDrmLock) {
+            if (mDrmProvisioningInProgress) {
+                Log.e(TAG, "HandleProvisioninig: Unexpected mDrmProvisioningInProgress");
+                return PREPARE_DRM_STATUS_PREPARATION_ERROR;
             }
-            result = mDrmProvisioningThread.status();
-            // no longer need the thread
-            mDrmProvisioningThread = null;
-        }
 
-        return result;
+            MediaDrm.ProvisionRequest provReq = mDrmObj.getProvisionRequest();
+            if (provReq == null) {
+                Log.e(TAG, "HandleProvisioninig: getProvisionRequest returned null.");
+                return PREPARE_DRM_STATUS_PREPARATION_ERROR;
+            }
+
+            Log.v(TAG, "HandleProvisioninig provReq " +
+                    " data: " + provReq.getData() + " url: " + provReq.getDefaultUrl());
+
+            // networking in a background thread
+            mDrmProvisioningInProgress = true;
+
+            mDrmProvisioningThread = new ProvisioningThread().initialize(provReq, uuid, this);
+            mDrmProvisioningThread.start();
+
+            return PREPARE_DRM_STATUS_SUCCESS;
+        }
     }
 
     private boolean resumePrepareDrm(UUID uuid) {
@@ -3691,7 +3601,9 @@
         private void sendCompleteNotification(int status) {
             // In {@link #notifyWhenCommandLabelReached} case, a separate callback
             // {@link #onCommandLabelReached} is already called in {@code process()}.
-            if (mMediaCallType == CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED) {
+            // CALL_COMPLETED_PREPARE_DRM is sent via DrmEventCallback
+            if (mMediaCallType == CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED
+                    || mMediaCallType == CALL_COMPLETED_PREPARE_DRM) {
                 return;
             }
             sendEvent(new EventNotifier() {
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index 32aba7f..84dfcb1 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -23,13 +23,12 @@
 import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources.NotFoundException;
 import android.database.Cursor;
-import android.media.MediaPlayer.OnCompletionListener;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.RemoteException;
 import android.provider.MediaStore;
-import android.provider.Settings;
 import android.provider.MediaStore.MediaColumns;
+import android.provider.Settings;
 import android.util.Log;
 
 import java.io.IOException;
@@ -50,7 +49,6 @@
 
     private static final String[] MEDIA_COLUMNS = new String[] {
         MediaStore.Audio.Media._ID,
-        MediaStore.Audio.Media.DATA,
         MediaStore.Audio.Media.TITLE
     };
     /** Selection that limits query results to just audio files */
@@ -254,7 +252,7 @@
                         cursor = res.query(uri, MEDIA_COLUMNS, mediaSelection, null, null);
                         if (cursor != null && cursor.getCount() == 1) {
                             cursor.moveToFirst();
-                            return cursor.getString(2);
+                            return cursor.getString(1);
                         }
                         // missing cursor is handled below
                     }
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 8664aa1..436897f 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -497,34 +497,6 @@
         return getUriFromCursor(mCursor);
     }
 
-    /**
-     * Queries the database for the Uri to a ringtone in a specific path (the ringtone has to have
-     * been scanned before)
-     *
-     * @param context Context used to query the database
-     * @param path Path to the ringtone file
-     * @return Uri of the ringtone, null if something fails in the query or the ringtone doesn't
-     *            exist
-     *
-     * @hide
-     */
-    private static Uri getExistingRingtoneUriFromPath(Context context, String path) {
-        final String[] proj = {MediaStore.Audio.Media._ID};
-        final String[] selectionArgs = {path};
-        try (final Cursor cursor = context.getContentResolver().query(
-                MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, proj,
-                MediaStore.Audio.Media.DATA + "=? ", selectionArgs, /* sortOrder */ null)) {
-            if (cursor == null || !cursor.moveToFirst()) {
-                return null;
-            }
-            final int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
-            if (id == -1) {
-                return null;
-            }
-            return Uri.withAppendedPath(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, "" + id);
-        }
-    }
-
     private static Uri getUriFromCursor(Cursor cursor) {
         return ContentUris.withAppendedId(Uri.parse(cursor.getString(URI_COLUMN_INDEX)), cursor
                 .getLong(ID_COLUMN_INDEX));
@@ -750,28 +722,6 @@
     }
 
     /**
-     * Look up the path for a given {@link Uri} referring to a ringtone sound (TYPE_RINGTONE,
-     * TYPE_NOTIFICATION, or TYPE_ALARM). This is saved in {@link MediaStore.Audio.Media#DATA}.
-     *
-     * @return a {@link File} pointing at the location of the {@param uri} on disk, or {@code null}
-     * if there is no such file.
-     */
-    private File getRingtonePathFromUri(Uri uri) {
-        // Query cursor to get ringtone path
-        final String[] projection = {MediaStore.Audio.Media.DATA};
-        setFilterColumnsList(TYPE_RINGTONE | TYPE_NOTIFICATION | TYPE_ALARM);
-
-        String path = null;
-        try (Cursor cursor = query(uri, projection, constructBooleanTrueWhereClause(mFilterColumns),
-                null, null)) {
-            if (cursor != null && cursor.moveToFirst()) {
-                path = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA));
-            }
-        }
-        return path != null ? new File(path) : null;
-    }
-
-    /**
      * Disables Settings.System.SYNC_PARENT_SOUNDS.
      *
      * @hide
@@ -879,32 +829,6 @@
                 : uriWithoutUserId.toString().startsWith(storage.toString());
     }
 
-    /** @hide */
-    public boolean isCustomRingtone(Uri uri) {
-        if(!isExternalRingtoneUri(uri)) {
-            // A custom ringtone would be in the external storage
-            return false;
-        }
-
-        final File ringtoneFile = (uri == null ? null : getRingtonePathFromUri(uri));
-        final File parent = (ringtoneFile == null ? null : ringtoneFile.getParentFile());
-        if (parent == null) {
-            return false;
-        }
-
-        final String[] directories = {
-            Environment.DIRECTORY_RINGTONES,
-            Environment.DIRECTORY_NOTIFICATIONS,
-            Environment.DIRECTORY_ALARMS
-        };
-        for (final String directory : directories) {
-            if (parent.equals(Environment.getExternalStoragePublicDirectory(directory))) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     /**
      * Adds an audio file to the list of ringtones.
      *
@@ -989,39 +913,6 @@
     }
 
     /**
-     * Deletes the actual file in the Uri and its ringtone database entry if the Uri's actual path
-     * is in one of the following directories: {@link android.is.Environment#DIRECTORY_RINGTONES},
-     * {@link android.is.Environment#DIRECTORY_NOTIFICATIONS} or
-     * {@link android.is.Environment#DIRECTORY_ALARMS}.
-     *
-     * The given Uri must be a ringtone Content Uri.
-     *
-     * Keep in mind that if the ringtone deleted is a default ringtone, it will still live in the
-     * ringtone cache file so it will be playable from there. However, if an app uses the ringtone
-     * as its own ringtone, it won't be played, which is the same behavior observed for 3rd party
-     * custom ringtones.
-     *
-     * @hide
-     */
-    public boolean deleteExternalRingtone(Uri uri) {
-        if(!isCustomRingtone(uri)) {
-            // We can only delete custom ringtones in the default ringtone storages
-            return false;
-        }
-
-        // Save the path of the ringtone before deleting from our content resolver.
-        final File ringtoneFile = getRingtonePathFromUri(uri);
-        try {
-            if (ringtoneFile != null && mContext.getContentResolver().delete(uri, null, null) > 0) {
-                return ringtoneFile.delete();
-            }
-        } catch (SecurityException e) {
-            Log.d(TAG, "Unable to delete custom ringtone", e);
-        }
-        return false;
-    }
-
-    /**
      * Try opening the given ringtone locally first, but failover to
      * {@link IRingtonePlayer} if we can't access it directly. Typically happens
      * when process doesn't hold
diff --git a/packages/ExtServices/src/android/ext/services/notification/ChannelImpressions.java b/packages/ExtServices/src/android/ext/services/notification/ChannelImpressions.java
index 29ee920..ca3daad 100644
--- a/packages/ExtServices/src/android/ext/services/notification/ChannelImpressions.java
+++ b/packages/ExtServices/src/android/ext/services/notification/ChannelImpressions.java
@@ -37,6 +37,8 @@
     static final String ATT_DISMISSALS = "dismisses";
     static final String ATT_VIEWS = "views";
     static final String ATT_STREAK = "streak";
+    static final String ATT_SENT = "sent";
+    static final String ATT_INTERRUPTIVE = "interruptive";
 
     private int mDismissals = 0;
     private int mViews = 0;
diff --git a/packages/PackageInstaller/res/drawable/app_icon_foreground.xml b/packages/PackageInstaller/res/drawable/app_icon_foreground.xml
index b1f40c1..2dcd49c 100644
--- a/packages/PackageInstaller/res/drawable/app_icon_foreground.xml
+++ b/packages/PackageInstaller/res/drawable/app_icon_foreground.xml
@@ -16,10 +16,10 @@
   -->
 <inset
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:insetTop="12dp"
-    android:insetRight="12dp"
-    android:insetBottom="12dp"
-    android:insetLeft="12dp">
+    android:insetTop="25%"
+    android:insetRight="25%"
+    android:insetBottom="25%"
+    android:insetLeft="25%">
 
     <vector
         android:width="24dp"
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index 2ae6f92..022bf69 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -26,9 +26,13 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.os.UserHandle;
 import android.telephony.TelephonyManager;
 import android.util.Log;
 
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+
 import com.android.settingslib.R;
 
 import java.util.ArrayList;
@@ -54,21 +58,32 @@
     private final BroadcastReceiver mProfileBroadcastReceiver = new BluetoothBroadcastReceiver();
     private final Collection<BluetoothCallback> mCallbacks = new ArrayList<>();
     private final android.os.Handler mReceiverHandler;
+    private final UserHandle mUserHandle;
     private final Context mContext;
 
     interface Handler {
         void onReceive(Context context, Intent intent, BluetoothDevice device);
     }
 
+    /**
+     * Creates BluetoothEventManager with the ability to pass in {@link UserHandle} that tells it to
+     * listen for bluetooth events for that particular userHandle.
+     *
+     * <p> If passing in userHandle that's different from the user running the process,
+     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission is required. If
+     * userHandle passed in is {@code null}, we register event receiver for the
+     * {@code context.getUser()} handle.
+     */
     BluetoothEventManager(LocalBluetoothAdapter adapter,
             CachedBluetoothDeviceManager deviceManager, Context context,
-            android.os.Handler handler) {
+            android.os.Handler handler, @Nullable UserHandle userHandle) {
         mLocalAdapter = adapter;
         mDeviceManager = deviceManager;
         mAdapterIntentFilter = new IntentFilter();
         mProfileIntentFilter = new IntentFilter();
         mHandlerMap = new HashMap<>();
         mContext = context;
+        mUserHandle = userHandle;
         mReceiverHandler = handler;
 
         // Bluetooth on/off broadcasts
@@ -104,7 +119,7 @@
         addHandler(TelephonyManager.ACTION_PHONE_STATE_CHANGED,
                 new AudioModeChangedHandler());
 
-        mContext.registerReceiver(mBroadcastReceiver, mAdapterIntentFilter, null, mReceiverHandler);
+        registerAdapterIntentReceiver();
     }
 
     /** Register to start receiving callbacks for Bluetooth events. */
@@ -121,10 +136,31 @@
         }
     }
 
+    @VisibleForTesting
     void registerProfileIntentReceiver() {
-        mContext.registerReceiver(mProfileBroadcastReceiver, mProfileIntentFilter, null, mReceiverHandler);
+        registerIntentReceiver(mProfileBroadcastReceiver, mProfileIntentFilter);
     }
 
+    @VisibleForTesting
+    void registerAdapterIntentReceiver() {
+        registerIntentReceiver(mBroadcastReceiver, mAdapterIntentFilter);
+    }
+
+    /**
+     * Registers the provided receiver to receive the broadcasts that correspond to the
+     * passed intent filter, in the context of the provided handler.
+     */
+    private void registerIntentReceiver(BroadcastReceiver receiver, IntentFilter filter) {
+        if (mUserHandle == null) {
+            // If userHandle has not been provided, simply call registerReceiver.
+            mContext.registerReceiver(receiver, filter, null, mReceiverHandler);
+        } else {
+            // userHandle was explicitly specified, so need to call multi-user aware API.
+            mContext.registerReceiverAsUser(receiver, mUserHandle, filter, null, mReceiverHandler);
+        }
+    }
+
+    @VisibleForTesting
     void addProfileHandler(String action, Handler handler) {
         mHandlerMap.put(action, handler);
         mProfileIntentFilter.addAction(action);
@@ -200,7 +236,8 @@
         }
     }
 
-    private void addHandler(String action, Handler handler) {
+    @VisibleForTesting
+    void addHandler(String action, Handler handler) {
         mHandlerMap.put(action, handler);
         mAdapterIntentFilter.addAction(action);
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothManager.java
index 7fe6205..53c6075 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothManager.java
@@ -18,10 +18,14 @@
 
 import android.content.Context;
 import android.os.Handler;
+import android.os.UserHandle;
 import android.util.Log;
 
 import java.lang.ref.WeakReference;
 
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresPermission;
+
 /**
  * LocalBluetoothManager provides a simplified interface on top of a subset of
  * the Bluetooth API. Note that {@link #getInstance} will return null
@@ -49,6 +53,7 @@
     /** The broadcast receiver event manager. */
     private final BluetoothEventManager mEventManager;
 
+    @Nullable
     public static synchronized LocalBluetoothManager getInstance(Context context,
             BluetoothManagerCallback onInitCallback) {
         if (sInstance == null) {
@@ -57,10 +62,11 @@
                 return null;
             }
             // This will be around as long as this process is
-            Context appContext = context.getApplicationContext();
-            sInstance = new LocalBluetoothManager(adapter, appContext, null);
+            sInstance = new LocalBluetoothManager(adapter, context, /* handler= */ null,
+                    /* userHandle= */ null);
             if (onInitCallback != null) {
-                onInitCallback.onBluetoothManagerInitialized(appContext, sInstance);
+                onInitCallback.onBluetoothManagerInitialized(context.getApplicationContext(),
+                        sInstance);
             }
         }
 
@@ -71,22 +77,43 @@
      * Returns a new instance of {@link LocalBluetoothManager} or null if Bluetooth is not
      * supported for this hardware. This instance should be globally cached by the caller.
      */
+    @Nullable
     public static LocalBluetoothManager create(Context context, Handler handler) {
         LocalBluetoothAdapter adapter = LocalBluetoothAdapter.getInstance();
         if (adapter == null) {
             return null;
         }
-        return new LocalBluetoothManager(adapter, context.getApplicationContext(), handler);
+        return new LocalBluetoothManager(adapter, context, handler, /* userHandle= */ null);
     }
 
-    private LocalBluetoothManager(
-            LocalBluetoothAdapter adapter, Context context, Handler handler) {
-        mContext = context;
+    /**
+     * Returns a new instance of {@link LocalBluetoothManager} or null if Bluetooth is not
+     * supported for this hardware. This instance should be globally cached by the caller.
+     *
+     * <p> Allows to specify a {@link UserHandle} for which to receive bluetooth events.
+     *
+     * <p> Requires {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission.
+     */
+    @Nullable
+    @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+    public static LocalBluetoothManager create(Context context, Handler handler,
+            UserHandle userHandle) {
+        LocalBluetoothAdapter adapter = LocalBluetoothAdapter.getInstance();
+        if (adapter == null) {
+            return null;
+        }
+        return new LocalBluetoothManager(adapter, context, handler,
+                userHandle);
+    }
+
+    private LocalBluetoothManager(LocalBluetoothAdapter adapter, Context context, Handler handler,
+            UserHandle userHandle) {
+        mContext = context.getApplicationContext();
         mLocalAdapter = adapter;
-        mCachedDeviceManager = new CachedBluetoothDeviceManager(context, this);
-        mEventManager = new BluetoothEventManager(mLocalAdapter,
-                mCachedDeviceManager, context, handler);
-        mProfileManager = new LocalBluetoothProfileManager(context,
+        mCachedDeviceManager = new CachedBluetoothDeviceManager(mContext, this);
+        mEventManager = new BluetoothEventManager(mLocalAdapter, mCachedDeviceManager, mContext,
+                handler, userHandle);
+        mProfileManager = new LocalBluetoothProfileManager(mContext,
                 mLocalAdapter, mCachedDeviceManager, mEventManager);
 
         mProfileManager.updateLocalProfiles();
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
index 662fa10..e1f9111 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
@@ -30,7 +30,7 @@
  * FeatureProvider for metrics.
  */
 public class MetricsFeatureProvider {
-    private List<LogWriter> mLoggerWriters;
+    protected List<LogWriter> mLoggerWriters;
 
     public MetricsFeatureProvider() {
         mLoggerWriters = new ArrayList<>();
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/bluetooth/BluetoothEventManagerIntegTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/bluetooth/BluetoothEventManagerIntegTest.java
new file mode 100644
index 0000000..d0ab46a
--- /dev/null
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/bluetooth/BluetoothEventManagerIntegTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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.settingslib.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.UserInfo;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * Test that verifies that BluetoothEventManager can receive broadcasts for non-current
+ * users for all bluetooth events.
+ *
+ * <p>Creation and deletion of users takes a long time, so marking this as a LargeTest.
+ */
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class BluetoothEventManagerIntegTest {
+    private static final int LATCH_TIMEOUT = 4;
+
+    private Context mContext;
+    private UserManager mUserManager;
+    private BluetoothEventManager mBluetoothEventManager;
+
+    private UserInfo mOtherUser;
+    private final Intent mTestIntent = new Intent("Test intent");
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mUserManager = UserManager.get(mContext);
+
+        mBluetoothEventManager = new BluetoothEventManager(
+                mock(LocalBluetoothAdapter.class), mock(CachedBluetoothDeviceManager.class),
+                mContext, /* handler= */ null, UserHandle.ALL);
+
+        // Create and start another user in the background.
+        mOtherUser = mUserManager.createUser("TestUser", /* flags= */ 0);
+        try {
+            ActivityManager.getService().startUserInBackground(mOtherUser.id);
+        } catch (RemoteException e) {
+            fail("Count't create an additional user.");
+        }
+    }
+
+    @After
+    public void tearDown() {
+        if (mOtherUser != null) {
+            mUserManager.removeUser(mOtherUser.id);
+        }
+    }
+
+    /**
+     * Verify that MultiUserAwareBluetoothEventManager's adapter receiver handles events coming from
+     * users other than current user.
+     */
+    @Test
+    public void registerAdapterReceiver_ifIntentFromAnotherUser_broadcastIsReceived()
+            throws Exception {
+        // Create a latch to listen for the intent.
+        final CountDownLatch broadcastLatch = new CountDownLatch(1);
+
+        // Register adapter receiver.
+        mBluetoothEventManager.addHandler(mTestIntent.getAction(),
+                (context, intent, device) -> broadcastLatch.countDown());
+        mBluetoothEventManager.registerAdapterIntentReceiver();
+
+        // Send broadcast from another user.
+        mContext.sendBroadcastAsUser(mTestIntent, mOtherUser.getUserHandle());
+
+        // Wait to receive it.
+        assertTrue(broadcastLatch.await(LATCH_TIMEOUT, SECONDS));
+    }
+
+    /**
+     * Verify that MultiUserAwareBluetoothEventManager's profile receiver handles events coming from
+     * users other than current user.
+     */
+    @Test
+    public void registerProfileReceiver_ifIntentFromAnotherUser_broadcastIsReceived()
+            throws Exception {
+        // Create a latch to listen for the intent.
+        final CountDownLatch broadcastLatch = new CountDownLatch(1);
+
+        // Register profile receiver.
+        mBluetoothEventManager.addProfileHandler(mTestIntent.getAction(),
+                (context, intent, device) -> broadcastLatch.countDown());
+        mBluetoothEventManager.registerProfileIntentReceiver();
+
+        // Send broadcast from another user.
+        mContext.sendBroadcastAsUser(mTestIntent, mOtherUser.getUserHandle());
+
+        // Wait to receive it.
+        assertTrue(broadcastLatch.await(LATCH_TIMEOUT, SECONDS));
+    }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
index b54d256..020234c6 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
@@ -15,12 +15,19 @@
  */
 package com.android.settingslib.bluetooth;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothProfile;
+import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Handler;
+import android.os.UserHandle;
 import android.telephony.TelephonyManager;
 
 import com.android.settingslib.SettingsLibRobolectricTestRunner;
@@ -54,7 +61,29 @@
         mContext = RuntimeEnvironment.application;
 
         mBluetoothEventManager = new BluetoothEventManager(mLocalAdapter,
-                mCachedDeviceManager, mContext, null);
+                mCachedDeviceManager, mContext, /* handler= */ null, /* userHandle= */ null);
+    }
+
+    @Test
+    public void ifUserHandleIsNull_registerReceiverIsCalled() {
+        Context mockContext = mock(Context.class);
+        BluetoothEventManager eventManager =
+                new BluetoothEventManager(mLocalAdapter, mCachedDeviceManager, mockContext,
+                        /* handler= */ null, /* userHandle= */ null);
+
+        verify(mockContext).registerReceiver(any(BroadcastReceiver.class), any(IntentFilter.class),
+                eq(null), eq(null));
+    }
+
+    @Test
+    public void ifUserHandleSpecified_registerReceiverAsUserIsCalled() {
+        Context mockContext = mock(Context.class);
+        BluetoothEventManager eventManager =
+                new BluetoothEventManager(mLocalAdapter, mCachedDeviceManager, mockContext,
+                        /* handler= */ null, UserHandle.ALL);
+
+        verify(mockContext).registerReceiverAsUser(any(BroadcastReceiver.class), eq(UserHandle.ALL),
+                any(IntentFilter.class), eq(null), eq(null));
     }
 
     /**
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
index 4c7f338..a3c3a54 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
@@ -78,7 +78,7 @@
         mContext = spy(RuntimeEnvironment.application);
         mLocalBluetoothAdapter = LocalBluetoothAdapter.getInstance();
         mEventManager = spy(new BluetoothEventManager(mLocalBluetoothAdapter, mDeviceManager,
-                mContext, null));
+                mContext, /* handler= */ null, /* userHandle= */ null));
         mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
         when(mDeviceManager.findDevice(mDevice)).thenReturn(mCachedBluetoothDevice);
         when(mCachedBluetoothDevice.getDevice()).thenReturn(mDevice);
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 9c33116..b770d5c 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -156,3 +156,43 @@
     ],
 
 }
+
+// Only used for products that are shipping legacy Recents
+android_app {
+    name: "SystemUIWithLegacyRecents",
+    overrides: [
+        "SystemUI",
+    ],
+
+    platform_apis: true,
+    certificate: "platform",
+    privileged: true,
+
+    dxflags: ["--multi-dex"],
+    aaptflags: [
+        "--extra-packages",
+        "com.android.keyguard",
+    ],
+    optimize: {
+        proguard_flags_files: ["proguard.flags", "legacy/recents/proguard.flags"],
+    },
+
+    static_libs: [
+        "SystemUI-core",
+    ],
+    libs: [
+        "telephony-common",
+        "android.car",
+        "android.car.user",
+    ],
+
+    srcs: [
+        "legacy/recents/src/**/*.java",
+        "legacy/recents/src/**/I*.aidl",
+    ],
+    resource_dirs: [
+        "legacy/recents/res",
+    ],
+
+    manifest: "legacy/recents/AndroidManifest.xml",
+}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index fef9ae8..44bc3f2 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -128,9 +128,6 @@
     <!-- Needed for WallpaperManager.clear in ImageWallpaper.updateWallpaperLocked -->
     <uses-permission android:name="android.permission.SET_WALLPAPER"/>
 
-    <!-- Recents -->
-    <uses-permission android:name="android.permission.BIND_APPWIDGET" />
-
     <!-- Wifi Display -->
     <uses-permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY" />
 
@@ -247,14 +244,14 @@
             android:exported="true"
         />
 
-        <!-- Recents depends on every user having their own SystemUI process, so on user switch,
-             ensure that the process is created by starting this service.
+        <!-- On user switch, this service is started to ensure that the associated SystemUI
+             process for the current user is started. See the resource
+             "config_systemUIServiceComponentsPerUser".
              -->
         <service android:name="SystemUISecondaryUserService"
-            android:exported="true"
+            android:exported="false"
             android:permission="com.android.systemui.permission.SELF" />
 
-
         <!-- started from PhoneWindowManager
              TODO: Should have an android:permission attribute -->
         <service android:name=".screenshot.TakeScreenshotService"
@@ -313,27 +310,6 @@
             </intent-filter>
         </activity-alias>
 
-        <!-- Service used by secondary users to register themselves with the system user. -->
-        <service android:name=".recents.RecentsSystemUserService"
-            android:exported="false"
-            android:permission="com.android.systemui.permission.SELF" />
-
-        <!-- Alternate Recents -->
-        <activity android:name=".recents.RecentsActivity"
-                  android:label="@string/accessibility_desc_recent_apps"
-                  android:exported="false"
-                  android:launchMode="singleInstance"
-                  android:excludeFromRecents="true"
-                  android:stateNotNeeded="true"
-                  android:resumeWhilePausing="true"
-                  android:resizeableActivity="true"
-                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|keyboard|keyboardHidden"
-                  android:theme="@style/RecentsTheme.Wallpaper">
-            <intent-filter>
-                <action android:name="com.android.systemui.recents.TOGGLE_RECENTS" />
-            </intent-filter>
-        </activity>
-
         <activity
             android:name=".stackdivider.ForcedResizableInfoActivity"
             android:theme="@style/ForcedResizableTheme"
diff --git a/packages/SystemUI/legacy/recents/AndroidManifest.xml b/packages/SystemUI/legacy/recents/AndroidManifest.xml
new file mode 100644
index 0000000..0d8b3cd
--- /dev/null
+++ b/packages/SystemUI/legacy/recents/AndroidManifest.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2018 Google Inc.
+ *
+ * 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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+          xmlns:tools="http://schemas.android.com/tools"
+          package="com.android.systemui"
+          android:sharedUserId="android.uid.systemui"
+          coreApp="true">
+
+    <application
+        android:name="com.android.systemui.SystemUIApplication">
+
+        <!-- Service used by secondary users to register themselves with the system user. -->
+        <service android:name=".recents.RecentsSystemUserService"
+            android:exported="false"
+            android:permission="com.android.systemui.permission.SELF" />
+
+        <!-- Alternate Recents -->
+        <activity android:name=".recents.RecentsActivity"
+                  android:label="@string/accessibility_desc_recent_apps"
+                  android:exported="false"
+                  android:launchMode="singleInstance"
+                  android:excludeFromRecents="true"
+                  android:stateNotNeeded="true"
+                  android:resumeWhilePausing="true"
+                  android:resizeableActivity="true"
+                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|keyboard|keyboardHidden"
+                  android:theme="@style/RecentsTheme.Wallpaper">
+            <intent-filter>
+                <action android:name="com.android.systemui.recents.TOGGLE_RECENTS" />
+            </intent-filter>
+        </activity>
+
+    </application>
+</manifest>
diff --git a/packages/SystemUI/legacy/recents/proguard.flags b/packages/SystemUI/legacy/recents/proguard.flags
new file mode 100644
index 0000000..c358949
--- /dev/null
+++ b/packages/SystemUI/legacy/recents/proguard.flags
@@ -0,0 +1,14 @@
+-keepclassmembers class ** {
+    public void onBusEvent(**);
+    public void onInterprocessBusEvent(**);
+}
+-keepclassmembers class ** extends **.EventBus$InterprocessEvent {
+    public <init>(android.os.Bundle);
+}
+
+-keep class com.android.systemui.recents.views.TaskView {
+    public int getDim();
+    public void setDim(int);
+    public float getTaskProgress();
+    public void setTaskProgress(float);
+}
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/recents_fast_toggle_app_home_exit.xml b/packages/SystemUI/legacy/recents/res/anim/recents_fast_toggle_app_home_exit.xml
similarity index 100%
rename from packages/SystemUI/res/anim/recents_fast_toggle_app_home_exit.xml
rename to packages/SystemUI/legacy/recents/res/anim/recents_fast_toggle_app_home_exit.xml
diff --git a/packages/SystemUI/res/anim/recents_from_launcher_enter.xml b/packages/SystemUI/legacy/recents/res/anim/recents_from_launcher_enter.xml
similarity index 100%
rename from packages/SystemUI/res/anim/recents_from_launcher_enter.xml
rename to packages/SystemUI/legacy/recents/res/anim/recents_from_launcher_enter.xml
diff --git a/packages/SystemUI/res/anim/recents_from_launcher_exit.xml b/packages/SystemUI/legacy/recents/res/anim/recents_from_launcher_exit.xml
similarity index 100%
rename from packages/SystemUI/res/anim/recents_from_launcher_exit.xml
rename to packages/SystemUI/legacy/recents/res/anim/recents_from_launcher_exit.xml
diff --git a/packages/SystemUI/res/anim/recents_from_unknown_enter.xml b/packages/SystemUI/legacy/recents/res/anim/recents_from_unknown_enter.xml
similarity index 100%
rename from packages/SystemUI/res/anim/recents_from_unknown_enter.xml
rename to packages/SystemUI/legacy/recents/res/anim/recents_from_unknown_enter.xml
diff --git a/packages/SystemUI/res/anim/recents_from_unknown_exit.xml b/packages/SystemUI/legacy/recents/res/anim/recents_from_unknown_exit.xml
similarity index 100%
rename from packages/SystemUI/res/anim/recents_from_unknown_exit.xml
rename to packages/SystemUI/legacy/recents/res/anim/recents_from_unknown_exit.xml
diff --git a/packages/SystemUI/res/anim/recents_launch_next_affiliated_task_bounce.xml b/packages/SystemUI/legacy/recents/res/anim/recents_launch_next_affiliated_task_bounce.xml
similarity index 100%
rename from packages/SystemUI/res/anim/recents_launch_next_affiliated_task_bounce.xml
rename to packages/SystemUI/legacy/recents/res/anim/recents_launch_next_affiliated_task_bounce.xml
diff --git a/packages/SystemUI/res/anim/recents_launch_next_affiliated_task_source.xml b/packages/SystemUI/legacy/recents/res/anim/recents_launch_next_affiliated_task_source.xml
similarity index 100%
rename from packages/SystemUI/res/anim/recents_launch_next_affiliated_task_source.xml
rename to packages/SystemUI/legacy/recents/res/anim/recents_launch_next_affiliated_task_source.xml
diff --git a/packages/SystemUI/res/anim/recents_launch_next_affiliated_task_target.xml b/packages/SystemUI/legacy/recents/res/anim/recents_launch_next_affiliated_task_target.xml
similarity index 100%
rename from packages/SystemUI/res/anim/recents_launch_next_affiliated_task_target.xml
rename to packages/SystemUI/legacy/recents/res/anim/recents_launch_next_affiliated_task_target.xml
diff --git a/packages/SystemUI/res/anim/recents_launch_prev_affiliated_task_bounce.xml b/packages/SystemUI/legacy/recents/res/anim/recents_launch_prev_affiliated_task_bounce.xml
similarity index 100%
rename from packages/SystemUI/res/anim/recents_launch_prev_affiliated_task_bounce.xml
rename to packages/SystemUI/legacy/recents/res/anim/recents_launch_prev_affiliated_task_bounce.xml
diff --git a/packages/SystemUI/res/anim/recents_launch_prev_affiliated_task_source.xml b/packages/SystemUI/legacy/recents/res/anim/recents_launch_prev_affiliated_task_source.xml
similarity index 100%
rename from packages/SystemUI/res/anim/recents_launch_prev_affiliated_task_source.xml
rename to packages/SystemUI/legacy/recents/res/anim/recents_launch_prev_affiliated_task_source.xml
diff --git a/packages/SystemUI/res/anim/recents_launch_prev_affiliated_task_target.xml b/packages/SystemUI/legacy/recents/res/anim/recents_launch_prev_affiliated_task_target.xml
similarity index 100%
rename from packages/SystemUI/res/anim/recents_launch_prev_affiliated_task_target.xml
rename to packages/SystemUI/legacy/recents/res/anim/recents_launch_prev_affiliated_task_target.xml
diff --git a/packages/SystemUI/res/anim/recents_to_launcher_enter.xml b/packages/SystemUI/legacy/recents/res/anim/recents_to_launcher_enter.xml
similarity index 100%
rename from packages/SystemUI/res/anim/recents_to_launcher_enter.xml
rename to packages/SystemUI/legacy/recents/res/anim/recents_to_launcher_enter.xml
diff --git a/packages/SystemUI/res/anim/recents_to_launcher_exit.xml b/packages/SystemUI/legacy/recents/res/anim/recents_to_launcher_exit.xml
similarity index 100%
rename from packages/SystemUI/res/anim/recents_to_launcher_exit.xml
rename to packages/SystemUI/legacy/recents/res/anim/recents_to_launcher_exit.xml
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_lower_gradient.9.png b/packages/SystemUI/legacy/recents/res/drawable-hdpi/recents_lower_gradient.9.png
similarity index 100%
rename from packages/SystemUI/res/drawable-hdpi/recents_lower_gradient.9.png
rename to packages/SystemUI/legacy/recents/res/drawable-hdpi/recents_lower_gradient.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_status_gradient.9.png b/packages/SystemUI/legacy/recents/res/drawable-hdpi/recents_status_gradient.9.png
similarity index 100%
rename from packages/SystemUI/res/drawable-hdpi/recents_status_gradient.9.png
rename to packages/SystemUI/legacy/recents/res/drawable-hdpi/recents_status_gradient.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_lower_gradient.9.png b/packages/SystemUI/legacy/recents/res/drawable-mdpi/recents_lower_gradient.9.png
similarity index 100%
rename from packages/SystemUI/res/drawable-mdpi/recents_lower_gradient.9.png
rename to packages/SystemUI/legacy/recents/res/drawable-mdpi/recents_lower_gradient.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_status_gradient.9.png b/packages/SystemUI/legacy/recents/res/drawable-mdpi/recents_status_gradient.9.png
similarity index 100%
rename from packages/SystemUI/res/drawable-mdpi/recents_status_gradient.9.png
rename to packages/SystemUI/legacy/recents/res/drawable-mdpi/recents_status_gradient.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_lower_gradient.9.png b/packages/SystemUI/legacy/recents/res/drawable-xhdpi/recents_lower_gradient.9.png
similarity index 100%
rename from packages/SystemUI/res/drawable-xhdpi/recents_lower_gradient.9.png
rename to packages/SystemUI/legacy/recents/res/drawable-xhdpi/recents_lower_gradient.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_status_gradient.9.png b/packages/SystemUI/legacy/recents/res/drawable-xhdpi/recents_status_gradient.9.png
similarity index 100%
rename from packages/SystemUI/res/drawable-xhdpi/recents_status_gradient.9.png
rename to packages/SystemUI/legacy/recents/res/drawable-xhdpi/recents_status_gradient.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/recents_lower_gradient.9.png b/packages/SystemUI/legacy/recents/res/drawable-xxhdpi/recents_lower_gradient.9.png
similarity index 100%
rename from packages/SystemUI/res/drawable-xxhdpi/recents_lower_gradient.9.png
rename to packages/SystemUI/legacy/recents/res/drawable-xxhdpi/recents_lower_gradient.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/recents_status_gradient.9.png b/packages/SystemUI/legacy/recents/res/drawable-xxhdpi/recents_status_gradient.9.png
similarity index 100%
rename from packages/SystemUI/res/drawable-xxhdpi/recents_status_gradient.9.png
rename to packages/SystemUI/legacy/recents/res/drawable-xxhdpi/recents_status_gradient.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/recents_task_shadow.9.png b/packages/SystemUI/legacy/recents/res/drawable-xxhdpi/recents_task_shadow.9.png
similarity index 100%
rename from packages/SystemUI/res/drawable-xxhdpi/recents_task_shadow.9.png
rename to packages/SystemUI/legacy/recents/res/drawable-xxhdpi/recents_task_shadow.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_lock_to_app_24dp.xml b/packages/SystemUI/legacy/recents/res/drawable/ic_lock_to_app_24dp.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_lock_to_app_24dp.xml
rename to packages/SystemUI/legacy/recents/res/drawable/ic_lock_to_app_24dp.xml
diff --git a/packages/SystemUI/res/drawable/recents_dismiss_dark.xml b/packages/SystemUI/legacy/recents/res/drawable/recents_dismiss_dark.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/recents_dismiss_dark.xml
rename to packages/SystemUI/legacy/recents/res/drawable/recents_dismiss_dark.xml
diff --git a/packages/SystemUI/res/drawable/recents_dismiss_light.xml b/packages/SystemUI/legacy/recents/res/drawable/recents_dismiss_light.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/recents_dismiss_light.xml
rename to packages/SystemUI/legacy/recents/res/drawable/recents_dismiss_light.xml
diff --git a/packages/SystemUI/res/drawable/recents_empty.xml b/packages/SystemUI/legacy/recents/res/drawable/recents_empty.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/recents_empty.xml
rename to packages/SystemUI/legacy/recents/res/drawable/recents_empty.xml
diff --git a/packages/SystemUI/res/drawable/recents_freeform_workspace_bg.xml b/packages/SystemUI/legacy/recents/res/drawable/recents_freeform_workspace_bg.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/recents_freeform_workspace_bg.xml
rename to packages/SystemUI/legacy/recents/res/drawable/recents_freeform_workspace_bg.xml
diff --git a/packages/SystemUI/res/drawable/recents_grid_task_view_focus_frame_background.xml b/packages/SystemUI/legacy/recents/res/drawable/recents_grid_task_view_focus_frame_background.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/recents_grid_task_view_focus_frame_background.xml
rename to packages/SystemUI/legacy/recents/res/drawable/recents_grid_task_view_focus_frame_background.xml
diff --git a/packages/SystemUI/res/drawable/recents_info_dark.xml b/packages/SystemUI/legacy/recents/res/drawable/recents_info_dark.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/recents_info_dark.xml
rename to packages/SystemUI/legacy/recents/res/drawable/recents_info_dark.xml
diff --git a/packages/SystemUI/res/drawable/recents_info_light.xml b/packages/SystemUI/legacy/recents/res/drawable/recents_info_light.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/recents_info_light.xml
rename to packages/SystemUI/legacy/recents/res/drawable/recents_info_light.xml
diff --git a/packages/SystemUI/res/drawable/recents_lock_to_app_pin.xml b/packages/SystemUI/legacy/recents/res/drawable/recents_lock_to_app_pin.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/recents_lock_to_app_pin.xml
rename to packages/SystemUI/legacy/recents/res/drawable/recents_lock_to_app_pin.xml
diff --git a/packages/SystemUI/res/drawable/recents_lock_to_task_button_bg.xml b/packages/SystemUI/legacy/recents/res/drawable/recents_lock_to_task_button_bg.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/recents_lock_to_task_button_bg.xml
rename to packages/SystemUI/legacy/recents/res/drawable/recents_lock_to_task_button_bg.xml
diff --git a/packages/SystemUI/res/drawable/recents_low_ram_stack_button_background.xml b/packages/SystemUI/legacy/recents/res/drawable/recents_low_ram_stack_button_background.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/recents_low_ram_stack_button_background.xml
rename to packages/SystemUI/legacy/recents/res/drawable/recents_low_ram_stack_button_background.xml
diff --git a/packages/SystemUI/res/drawable/recents_move_task_freeform_dark.xml b/packages/SystemUI/legacy/recents/res/drawable/recents_move_task_freeform_dark.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/recents_move_task_freeform_dark.xml
rename to packages/SystemUI/legacy/recents/res/drawable/recents_move_task_freeform_dark.xml
diff --git a/packages/SystemUI/res/drawable/recents_move_task_freeform_light.xml b/packages/SystemUI/legacy/recents/res/drawable/recents_move_task_freeform_light.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/recents_move_task_freeform_light.xml
rename to packages/SystemUI/legacy/recents/res/drawable/recents_move_task_freeform_light.xml
diff --git a/packages/SystemUI/res/drawable/recents_move_task_fullscreen_dark.xml b/packages/SystemUI/legacy/recents/res/drawable/recents_move_task_fullscreen_dark.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/recents_move_task_fullscreen_dark.xml
rename to packages/SystemUI/legacy/recents/res/drawable/recents_move_task_fullscreen_dark.xml
diff --git a/packages/SystemUI/res/drawable/recents_move_task_fullscreen_light.xml b/packages/SystemUI/legacy/recents/res/drawable/recents_move_task_fullscreen_light.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/recents_move_task_fullscreen_light.xml
rename to packages/SystemUI/legacy/recents/res/drawable/recents_move_task_fullscreen_light.xml
diff --git a/packages/SystemUI/res/drawable/recents_stack_action_background.xml b/packages/SystemUI/legacy/recents/res/drawable/recents_stack_action_background.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/recents_stack_action_background.xml
rename to packages/SystemUI/legacy/recents/res/drawable/recents_stack_action_background.xml
diff --git a/packages/SystemUI/res/interpolator/recents_from_launcher_exit_interpolator.xml b/packages/SystemUI/legacy/recents/res/interpolator/recents_from_launcher_exit_interpolator.xml
similarity index 100%
rename from packages/SystemUI/res/interpolator/recents_from_launcher_exit_interpolator.xml
rename to packages/SystemUI/legacy/recents/res/interpolator/recents_from_launcher_exit_interpolator.xml
diff --git a/packages/SystemUI/res/interpolator/recents_launch_next_affiliated_task_bounce_scale.xml b/packages/SystemUI/legacy/recents/res/interpolator/recents_launch_next_affiliated_task_bounce_scale.xml
similarity index 100%
rename from packages/SystemUI/res/interpolator/recents_launch_next_affiliated_task_bounce_scale.xml
rename to packages/SystemUI/legacy/recents/res/interpolator/recents_launch_next_affiliated_task_bounce_scale.xml
diff --git a/packages/SystemUI/res/interpolator/recents_launch_prev_affiliated_task_bounce_ydelta.xml b/packages/SystemUI/legacy/recents/res/interpolator/recents_launch_prev_affiliated_task_bounce_ydelta.xml
similarity index 100%
rename from packages/SystemUI/res/interpolator/recents_launch_prev_affiliated_task_bounce_ydelta.xml
rename to packages/SystemUI/legacy/recents/res/interpolator/recents_launch_prev_affiliated_task_bounce_ydelta.xml
diff --git a/packages/SystemUI/res/interpolator/recents_to_launcher_enter_interpolator.xml b/packages/SystemUI/legacy/recents/res/interpolator/recents_to_launcher_enter_interpolator.xml
similarity index 100%
rename from packages/SystemUI/res/interpolator/recents_to_launcher_enter_interpolator.xml
rename to packages/SystemUI/legacy/recents/res/interpolator/recents_to_launcher_enter_interpolator.xml
diff --git a/packages/SystemUI/res/layout/recents.xml b/packages/SystemUI/legacy/recents/res/layout/recents.xml
similarity index 100%
rename from packages/SystemUI/res/layout/recents.xml
rename to packages/SystemUI/legacy/recents/res/layout/recents.xml
diff --git a/packages/SystemUI/res/layout/recents_empty.xml b/packages/SystemUI/legacy/recents/res/layout/recents_empty.xml
similarity index 100%
rename from packages/SystemUI/res/layout/recents_empty.xml
rename to packages/SystemUI/legacy/recents/res/layout/recents_empty.xml
diff --git a/packages/SystemUI/res/layout/recents_grid_task_view.xml b/packages/SystemUI/legacy/recents/res/layout/recents_grid_task_view.xml
similarity index 100%
rename from packages/SystemUI/res/layout/recents_grid_task_view.xml
rename to packages/SystemUI/legacy/recents/res/layout/recents_grid_task_view.xml
diff --git a/packages/SystemUI/res/layout/recents_incompatible_app_overlay.xml b/packages/SystemUI/legacy/recents/res/layout/recents_incompatible_app_overlay.xml
similarity index 100%
rename from packages/SystemUI/res/layout/recents_incompatible_app_overlay.xml
rename to packages/SystemUI/legacy/recents/res/layout/recents_incompatible_app_overlay.xml
diff --git a/packages/SystemUI/res/layout/recents_low_ram_stack_action_button.xml b/packages/SystemUI/legacy/recents/res/layout/recents_low_ram_stack_action_button.xml
similarity index 100%
rename from packages/SystemUI/res/layout/recents_low_ram_stack_action_button.xml
rename to packages/SystemUI/legacy/recents/res/layout/recents_low_ram_stack_action_button.xml
diff --git a/packages/SystemUI/res/layout/recents_search_bar.xml b/packages/SystemUI/legacy/recents/res/layout/recents_search_bar.xml
similarity index 100%
rename from packages/SystemUI/res/layout/recents_search_bar.xml
rename to packages/SystemUI/legacy/recents/res/layout/recents_search_bar.xml
diff --git a/packages/SystemUI/res/layout/recents_stack_action_button.xml b/packages/SystemUI/legacy/recents/res/layout/recents_stack_action_button.xml
similarity index 100%
rename from packages/SystemUI/res/layout/recents_stack_action_button.xml
rename to packages/SystemUI/legacy/recents/res/layout/recents_stack_action_button.xml
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/legacy/recents/res/layout/recents_task_view.xml
similarity index 100%
rename from packages/SystemUI/res/layout/recents_task_view.xml
rename to packages/SystemUI/legacy/recents/res/layout/recents_task_view.xml
diff --git a/packages/SystemUI/res/layout/recents_task_view_header.xml b/packages/SystemUI/legacy/recents/res/layout/recents_task_view_header.xml
similarity index 100%
rename from packages/SystemUI/res/layout/recents_task_view_header.xml
rename to packages/SystemUI/legacy/recents/res/layout/recents_task_view_header.xml
diff --git a/packages/SystemUI/res/layout/recents_task_view_header_overlay.xml b/packages/SystemUI/legacy/recents/res/layout/recents_task_view_header_overlay.xml
similarity index 100%
rename from packages/SystemUI/res/layout/recents_task_view_header_overlay.xml
rename to packages/SystemUI/legacy/recents/res/layout/recents_task_view_header_overlay.xml
diff --git a/packages/SystemUI/res/layout/recents_task_view_header_progress_bar.xml b/packages/SystemUI/legacy/recents/res/layout/recents_task_view_header_progress_bar.xml
similarity index 100%
rename from packages/SystemUI/res/layout/recents_task_view_header_progress_bar.xml
rename to packages/SystemUI/legacy/recents/res/layout/recents_task_view_header_progress_bar.xml
diff --git a/packages/SystemUI/res/layout/recents_task_view_incompatible_app_toast.xml b/packages/SystemUI/legacy/recents/res/layout/recents_task_view_incompatible_app_toast.xml
similarity index 100%
rename from packages/SystemUI/res/layout/recents_task_view_incompatible_app_toast.xml
rename to packages/SystemUI/legacy/recents/res/layout/recents_task_view_incompatible_app_toast.xml
diff --git a/packages/SystemUI/res/layout/recents_task_view_lock_to_app.xml b/packages/SystemUI/legacy/recents/res/layout/recents_task_view_lock_to_app.xml
similarity index 100%
rename from packages/SystemUI/res/layout/recents_task_view_lock_to_app.xml
rename to packages/SystemUI/legacy/recents/res/layout/recents_task_view_lock_to_app.xml
diff --git a/packages/SystemUI/legacy/recents/res/values-sw600dp/dimens.xml b/packages/SystemUI/legacy/recents/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..20d6670
--- /dev/null
+++ b/packages/SystemUI/legacy/recents/res/values-sw600dp/dimens.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (c) 2012, 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>
+    <!-- The offsets the tasks animate from when recents is launched while docking -->
+    <dimen name="recents_task_stack_animation_launched_while_docking_offset">192dp</dimen>
+</resources>
diff --git a/packages/SystemUI/legacy/recents/res/values/attrs.xml b/packages/SystemUI/legacy/recents/res/values/attrs.xml
new file mode 100644
index 0000000..ef4cd5b
--- /dev/null
+++ b/packages/SystemUI/legacy/recents/res/values/attrs.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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>
+
+    <declare-styleable name="RecentsPanelView">
+        <attr name="recentItemLayout" format="reference" />
+        <!-- Style for the "Clear all" button. -->
+        <attr name="clearAllStyle" format="reference" />
+        <attr name="clearAllBackgroundColor" format="reference" />
+    </declare-styleable>
+
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/legacy/recents/res/values/colors.xml b/packages/SystemUI/legacy/recents/res/values/colors.xml
new file mode 100644
index 0000000..88b9b70
--- /dev/null
+++ b/packages/SystemUI/legacy/recents/res/values/colors.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright 2010, 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>
+	<!-- The disabled recents task bar background color. -->
+    <color name="recents_task_bar_disabled_background_color">#ff676767</color>
+    <!-- The default recents task bar background color. -->
+    <color name="recents_task_bar_default_background_color">#ffe6e6e6</color>
+    <!-- The default recents task view background color. -->
+    <color name="recents_task_view_default_background_color">#fff3f3f3</color>
+    <!-- The recents task bar light text color to be drawn on top of dark backgrounds. -->
+    <color name="recents_task_bar_light_text_color">#ffeeeeee</color>
+    <!-- The recents task bar dark text color to be drawn on top of light backgrounds. -->
+    <color name="recents_task_bar_dark_text_color">#cc000000</color>
+    <!-- The recents task bar light dismiss icon color to be drawn on top of dark backgrounds. -->
+    <color name="recents_task_bar_light_icon_color">#ccffffff</color>
+    <!-- The recents task bar dark dismiss icon color to be drawn on top of light backgrounds. -->
+    <color name="recents_task_bar_dark_icon_color">#99000000</color>
+    <!-- The lock to task button background color. -->
+    <color name="recents_task_view_lock_to_app_button_background_color">#ffe6e6e6</color>
+    <!-- The lock to task button foreground color. -->
+    <color name="recents_task_view_lock_to_app_button_color">#ff666666</color>
+    <!-- The background color for the freeform workspace. -->
+    <color name="recents_freeform_workspace_bg_color">#33FFFFFF</color>
+
+    <!-- The background color for clear all button on light backgrounds if not transparent. -->
+    <color name="recents_clear_all_button_bg_light_color">#CCFFFFFF</color>
+    <!-- The background color for clear all button on dark backgrounds if not transparent. -->
+    <color name="recents_clear_all_button_bg_dark_color">#CC000000</color>
+
+    <!-- Shadow color for the first pixels around the fake shadow for recents. -->
+    <color name="fake_shadow_start_color">#44000000</color>
+
+    <!-- Shadow color for the furthest pixels around the fake shadow for recents. -->
+    <color name="fake_shadow_end_color">#03000000</color>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/legacy/recents/res/values/config.xml b/packages/SystemUI/legacy/recents/res/values/config.xml
new file mode 100644
index 0000000..2ff9abf
--- /dev/null
+++ b/packages/SystemUI/legacy/recents/res/values/config.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2009, 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+
+    <!-- Component to be used as the recents implementation.  Must implement the
+     RecentsImplementation interface.  This name is in the ComponentName flattened format
+     (package/class)  -->
+    <string name="config_recentsComponent" translatable="false">com.android.systemui.recents.LegacyRecentsImpl</string>
+
+    <!-- Whether recents should use hardware layers for its taskviews. This flag can be enabled
+    for devices where the java drawing of round rects may be slow -->
+    <bool name="config_recents_use_hardware_layers">false</bool>
+
+    <!-- The number of app thumbnails we keep in memory -->
+    <integer name="config_recents_max_thumbnail_count">10</integer>
+
+    <!-- The number of app icons we keep in memory -->
+    <integer name="config_recents_max_icon_count">20</integer>
+
+    <!-- Whether to use cheap, less good looking shadows for recents -->
+    <bool name="config_recents_fake_shadows">false</bool>
+
+    <!-- The duration in seconds to wait before the dismiss buttons are shown. -->
+    <integer name="recents_task_bar_dismiss_delay_seconds">1000</integer>
+
+    <!-- The duration for animating the task decorations in after transitioning from an app. -->
+    <integer name="recents_task_enter_from_app_duration">200</integer>
+
+    <!-- The duration for animating the task decorations in after transitioning from an app. -->
+    <integer name="recents_task_enter_from_affiliated_app_duration">125</integer>
+
+    <!-- The duration for animating the task decorations out before transitioning to an app. -->
+    <integer name="recents_task_exit_to_app_duration">125</integer>
+
+    <!-- The min animation duration for animating the nav bar scrim in. -->
+    <integer name="recents_nav_bar_scrim_enter_duration">400</integer>
+
+    <!-- The animation duration for scrolling the stack to a particular item. -->
+    <integer name="recents_animate_task_stack_scroll_duration">200</integer>
+
+    <!-- The delay to enforce between each alt-tab key press. -->
+    <integer name="recents_alt_tab_key_delay">200</integer>
+
+    <!-- Svelte specific logic, see RecentsConfiguration.SVELTE_* constants. -->
+    <integer name="recents_svelte_level">0</integer>
+
+    <!-- Recents: The relative range of visible tasks from the current scroll position
+         while the stack is focused. -->
+    <item name="recents_layout_focused_range_min" format="float" type="integer">-3</item>
+    <item name="recents_layout_focused_range_max" format="float" type="integer">2</item>
+
+    <!-- Recents: The relative range of visible tasks from the current scroll position
+         while the stack is not focused. -->
+    <item name="recents_layout_unfocused_range_min" format="float" type="integer">-2</item>
+    <item name="recents_layout_unfocused_range_max" format="float" type="integer">2.5</item>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/legacy/recents/res/values/dimens.xml b/packages/SystemUI/legacy/recents/res/values/dimens.xml
new file mode 100644
index 0000000..528610e4
--- /dev/null
+++ b/packages/SystemUI/legacy/recents/res/values/dimens.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (c) 2006, 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>
+<!-- Recents Layout -->
+
+    <!-- The amount to inset the stack, specifically at the top and the other sides.  We also
+         don't want this to change across configurations that Recents can be opened in, so we
+         define them statically for all display sizes. -->
+    <dimen name="recents_layout_min_margin">16dp</dimen>
+    <dimen name="recents_layout_top_margin_phone">16dp</dimen>
+    <dimen name="recents_layout_top_margin_tablet">32dp</dimen>
+    <dimen name="recents_layout_top_margin_tablet_xlarge">40dp</dimen>
+    <dimen name="recents_layout_bottom_margin">16dp</dimen>
+    <dimen name="recents_layout_side_margin_phone">16dp</dimen>
+    <dimen name="recents_layout_side_margin_tablet">48dp</dimen>
+    <dimen name="recents_layout_side_margin_tablet_docked">16dp</dimen>
+    <dimen name="recents_layout_side_margin_tablet_xlarge">64dp</dimen>
+    <dimen name="recents_layout_side_margin_tablet_xlarge_docked">16dp</dimen>
+
+    <!-- The height between the top margin and the top of the focused task. -->
+    <dimen name="recents_layout_top_peek_size">48dp</dimen>
+    <!-- The height between the bottom margin and the top of task in front of the focused task. -->
+    <dimen name="recents_layout_bottom_peek_size">56dp</dimen>
+
+    <!-- The offset from the top and bottom of the stack of the focused task.  The bottom offset
+         will be additionally offset by the bottom system insets since it goes under the nav bar
+         in certain orientations. -->
+    <dimen name="recents_layout_initial_top_offset_phone_port">128dp</dimen>
+    <dimen name="recents_layout_initial_bottom_offset_phone_port">80dp</dimen>
+    <dimen name="recents_layout_initial_top_offset_phone_land">72dp</dimen>
+    <dimen name="recents_layout_initial_bottom_offset_phone_land">72dp</dimen>
+    <dimen name="recents_layout_initial_top_offset_tablet">160dp</dimen>
+    <dimen name="recents_layout_initial_bottom_offset_tablet">112dp</dimen>
+
+    <!-- The min/max translationZ for the tasks in the stack. -->
+    <dimen name="recents_layout_z_min">3dp</dimen>
+    <dimen name="recents_layout_z_max">24dp</dimen>
+
+    <!-- The margin between the freeform and stack.  We also don't want this to change across
+         configurations that Recents can be opened in, so we define them statically for all
+         display sizes. -->
+    <dimen name="recents_freeform_layout_bottom_margin">16dp</dimen>
+
+    <!-- The padding between each freeform task. -->
+    <dimen name="recents_freeform_layout_task_padding">8dp</dimen>
+
+<!-- Recents Views -->
+
+    <!-- The height of a task view bar.  This has to be large enough to cover the action bar
+         height in either orientation at this smallest width. -->
+    <dimen name="recents_task_view_header_height">56dp</dimen>
+    <dimen name="recents_task_view_header_height_tablet_land">64dp</dimen>
+
+    <!-- The padding of a button in the recents task view header. -->
+    <dimen name="recents_task_view_header_button_padding">16dp</dimen>
+    <dimen name="recents_task_view_header_button_padding_tablet_land">20dp</dimen>
+
+    <!-- The radius of the rounded corners on a task view and its shadow (which can be larger
+         to create a softer corner effect. -->
+    <dimen name="recents_task_view_rounded_corners_radius">2dp</dimen>
+    <dimen name="recents_task_view_shadow_rounded_corners_radius">6dp</dimen>
+
+    <!-- The amount of highlight to make on each task view. -->
+    <dimen name="recents_task_view_highlight">1dp</dimen>
+
+    <!-- The size of the lock-to-app button and its icon. -->
+    <dimen name="recents_lock_to_app_size">56dp</dimen>
+    <dimen name="recents_lock_to_app_icon_size">28dp</dimen>
+
+    <!-- The amount of overscroll allowed when flinging to the end of the stack. -->
+    <dimen name="recents_fling_overscroll_distance">24dp</dimen>
+
+    <!-- The size of the drag hint text. -->
+    <dimen name="recents_drag_hint_text_size">14sp</dimen>
+
+    <!-- The min alpha to apply to a task affiliation group color. -->
+    <item name="recents_task_affiliation_color_min_alpha_percentage" format="float" type="dimen">0.6</item>
+
+    <!-- The amount to offset when animating into an affiliate group. -->
+    <dimen name="recents_task_stack_animation_affiliate_enter_offset">32dp</dimen>
+
+    <!-- The offsets the tasks animate from when recents is launched while docking -->
+    <dimen name="recents_task_stack_animation_launched_while_docking_offset">144dp</dimen>
+
+    <!-- The amount to translate when animating the removal of a task. -->
+    <dimen name="recents_task_view_remove_anim_translation_x">100dp</dimen>
+
+    <!-- The alpha to apply to the recents row when it doesn't have focus -->
+    <item name="recents_recents_row_dim_alpha" format="float" type="dimen">0.5</item>
+
+    <!-- The speed in dp/s at which the user needs to be scrolling in recents such that we start
+         loading full resolution screenshots. -->
+    <dimen name="recents_fast_fling_velocity">600dp</dimen>
+
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/dimens_grid.xml b/packages/SystemUI/legacy/recents/res/values/dimens_grid.xml
similarity index 100%
rename from packages/SystemUI/res/values/dimens_grid.xml
rename to packages/SystemUI/legacy/recents/res/values/dimens_grid.xml
diff --git a/packages/SystemUI/legacy/recents/res/values/strings.xml b/packages/SystemUI/legacy/recents/res/values/strings.xml
new file mode 100644
index 0000000..4b44ba9
--- /dev/null
+++ b/packages/SystemUI/legacy/recents/res/values/strings.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2009, 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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+	
+    <!-- Content description for the recent apps panel (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_desc_recent_apps">Overview.</string>
+
+    <!-- Content description to tell the user that this button will remove an application from recents -->
+    <string name="accessibility_recents_item_will_be_dismissed">Dismiss <xliff:g id="app" example="Calendar">%s</xliff:g>.</string>
+    <!-- Content description to tell the user an application has been removed from recents -->
+    <string name="accessibility_recents_item_dismissed"><xliff:g id="app" example="Calendar">%s</xliff:g> dismissed.</string>
+    <!-- Content description to tell the user all applications has been removed from recents -->
+    <string name="accessibility_recents_all_items_dismissed">All recent applications dismissed.</string>
+    <!-- Content description to tell the user that this button will open application info for an application in recents -->
+    <string name="accessibility_recents_item_open_app_info">Open <xliff:g id="app" example="Calendar">%s</xliff:g> application info.</string>
+    <!-- Content description to tell the user an application has been launched from recents -->
+    <string name="accessibility_recents_item_launched">Starting <xliff:g id="app" example="Calendar">%s</xliff:g>.</string>
+
+    <!-- Recents: The empty recents string. [CHAR LIMIT=NONE] -->
+    <string name="recents_empty_message">No recent items</string>
+    <!-- Recents: The empty recents string after dismissing all tasks. [CHAR LIMIT=NONE] -->
+    <string name="recents_empty_message_dismissed_all">You\'ve cleared everything</string>
+    <!-- Recents: The info panel app info button string. [CHAR LIMIT=NONE] -->
+    <string name="recents_app_info_button_label">Application Info</string>
+    <!-- Recents: The screen pinning button. [CHAR LIMIT=NONE] -->
+    <string name="recents_lock_to_app_button_label">screen pinning</string>
+    <!-- Recents: Temporary string for the button in the recents search bar. [CHAR LIMIT=NONE] -->
+    <string name="recents_search_bar_label">search</string>
+    <!-- Recents: Launch error string. [CHAR LIMIT=NONE] -->
+    <string name="recents_launch_error_message">Could not start <xliff:g id="app" example="Calendar">%s</xliff:g>.</string>
+    <!-- Recents: Launch disabled string. [CHAR LIMIT=NONE] -->
+    <string name="recents_launch_disabled_message"><xliff:g id="app" example="Calendar">%s</xliff:g> is disabled in safe-mode.</string>
+    <!-- Recents: Stack action button string. [CHAR LIMIT=NONE] -->
+    <string name="recents_stack_action_button_label">Clear all</string>
+    <!-- Recents: Hint text that shows on the drop targets to start multiwindow. [CHAR LIMIT=NONE] -->
+    <string name="recents_drag_hint_message">Drag here to use split screen</string>
+
+    <!-- Recents: MultiStack add stack split horizontal radio button. [CHAR LIMIT=NONE] -->
+    <string name="recents_multistack_add_stack_dialog_split_horizontal">Split Horizontal</string>
+    <!-- Recents: MultiStack add stack split vertical radio button. [CHAR LIMIT=NONE] -->
+    <string name="recents_multistack_add_stack_dialog_split_vertical">Split Vertical</string>
+    <!-- Recents: MultiStack add stack split custom radio button. [CHAR LIMIT=NONE] -->
+    <string name="recents_multistack_add_stack_dialog_split_custom">Split Custom</string>
+    <!-- Recents: Accessibility split to the top -->
+    <string name="recents_accessibility_split_screen_top">Split screen to the top</string>
+    <!-- Recents: Accessibility split to the left -->
+    <string name="recents_accessibility_split_screen_left">Split screen to the left</string>
+    <!-- Recents: Accessibility split to the right -->
+    <string name="recents_accessibility_split_screen_right">Split screen to the right</string>
+
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/legacy/recents/res/values/styles.xml b/packages/SystemUI/legacy/recents/res/values/styles.xml
new file mode 100644
index 0000000..eb16be7
--- /dev/null
+++ b/packages/SystemUI/legacy/recents/res/values/styles.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2006 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 xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <style name="RecentsTheme" parent="@android:style/Theme.Material">
+        <!-- NoTitle -->
+        <item name="android:windowNoTitle">true</item>
+        <!-- Misc -->
+        <item name="android:statusBarColor">@android:color/transparent</item>
+        <item name="android:navigationBarColor">@android:color/transparent</item>
+        <item name="android:windowDrawsSystemBarBackgrounds">true</item>
+        <item name="android:windowAnimationStyle">@null</item>
+        <item name="android:ambientShadowAlpha">0.35</item>
+    </style>
+
+    <!-- Recents theme -->
+    <style name="RecentsTheme.Wallpaper">
+        <item name="android:windowBackground">@*android:color/transparent</item>
+        <item name="android:colorBackgroundCacheHint">@null</item>
+        <item name="android:windowShowWallpaper">true</item>
+        <item name="android:windowDisablePreview">true</item>
+        <item name="clearAllStyle">@style/ClearAllButtonDefaultMargins</item>
+        <item name="clearAllBackgroundColor">@color/recents_clear_all_button_bg_dark_color</item>
+        <item name="wallpaperTextColor">@*android:color/primary_text_material_dark</item>
+        <item name="wallpaperTextColorSecondary">@*android:color/secondary_text_material_dark</item>
+    </style>
+
+    <style name="RecentsTheme.Wallpaper.Light">
+        <item name="clearAllBackgroundColor">@color/recents_clear_all_button_bg_light_color</item>
+        <item name="wallpaperTextColor">@*android:color/primary_text_material_light</item>
+        <item name="wallpaperTextColorSecondary">@*android:color/secondary_text_material_light</item>
+    </style>
+
+    <!-- Performance optimized Recents theme (no wallpaper) -->
+    <style name="RecentsTheme.NoWallpaper">
+        <item name="android:windowBackground">@android:color/black</item>
+        <item name="wallpaperTextColor">@android:color/white</item>
+        <item name="wallpaperTextColorSecondary">@android:color/white</item>
+    </style>
+
+  </resources>
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/Constants.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/Constants.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/Constants.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
diff --git a/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
diff --git a/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/LegacyRecentsImpl.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/LegacyRecentsImpl.java
new file mode 100644
index 0000000..b7bb751
--- /dev/null
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/LegacyRecentsImpl.java
@@ -0,0 +1,744 @@
+/*
+ * Copyright (C) 2014 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.systemui.recents;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS;
+
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.hardware.display.DisplayManager;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.EventLog;
+import android.util.Log;
+import android.view.Display;
+import android.widget.Toast;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.EventLogConstants;
+import com.android.systemui.EventLogTags;
+import com.android.systemui.R;
+import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.pip.PipUI;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
+import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent;
+import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
+import com.android.systemui.recents.events.activity.LaunchTaskFailedEvent;
+import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
+import com.android.systemui.recents.events.component.ExpandPipEvent;
+import com.android.systemui.recents.events.component.HidePipMenuEvent;
+import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
+import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
+import com.android.systemui.recents.events.component.SetWaitingForTransitionStartEvent;
+import com.android.systemui.recents.events.component.ShowUserToastEvent;
+import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
+import com.android.systemui.recents.events.ui.RecentsGrowingEvent;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.model.RecentsTaskLoader;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.stackdivider.Divider;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * An implementation of the SystemUI recents component, which supports both system and secondary
+ * users.
+ */
+public class LegacyRecentsImpl implements RecentsImplementation {
+
+    private final static String TAG = "Recents";
+
+    public final static int EVENT_BUS_PRIORITY = 1;
+    public final static int BIND_TO_SYSTEM_USER_RETRY_DELAY = 5000;
+
+    public final static Set<String> RECENTS_ACTIVITIES = new HashSet<>();
+    static {
+        RECENTS_ACTIVITIES.add(RecentsImpl.RECENTS_ACTIVITY);
+    }
+
+    private static final String COUNTER_WINDOW_SUPPORTED = "window_enter_supported";
+    private static final String COUNTER_WINDOW_UNSUPPORTED = "window_enter_unsupported";
+    private static final String COUNTER_WINDOW_INCOMPATIBLE = "window_enter_incompatible";
+
+    private static SystemServicesProxy sSystemServicesProxy;
+    private static RecentsDebugFlags sDebugFlags;
+    private static RecentsTaskLoader sTaskLoader;
+    private static RecentsConfiguration sConfiguration;
+
+    private Context mContext;
+    private SysUiServiceProvider mSysUiServiceProvider;
+    private Handler mHandler;
+    private RecentsImpl mImpl;
+
+    // Only For system user, this is the callbacks instance we return to each secondary user
+    private RecentsSystemUser mSystemToUserCallbacks;
+
+    // Only for secondary users, this is the callbacks instance provided by the system user to make
+    // calls back
+    private IRecentsSystemUserCallbacks mUserToSystemCallbacks;
+
+    // The set of runnables to run after binding to the system user's service.
+    private final ArrayList<Runnable> mOnConnectRunnables = new ArrayList<>();
+
+    // Only for secondary users, this is the death handler for the binder from the system user
+    private final IBinder.DeathRecipient mUserToSystemCallbacksDeathRcpt = new IBinder.DeathRecipient() {
+        @Override
+        public void binderDied() {
+            mUserToSystemCallbacks = null;
+            EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_CONNECTION,
+                    EventLogConstants.SYSUI_RECENTS_CONNECTION_USER_SYSTEM_UNBOUND,
+                    sSystemServicesProxy.getProcessUser());
+
+            // Retry after a fixed duration
+            mHandler.postDelayed(new Runnable() {
+                @Override
+                public void run() {
+                    registerWithSystemUser();
+                }
+            }, BIND_TO_SYSTEM_USER_RETRY_DELAY);
+        }
+    };
+
+    // Only for secondary users, this is the service connection we use to connect to the system user
+    private final ServiceConnection mUserToSystemServiceConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            if (service != null) {
+                mUserToSystemCallbacks = IRecentsSystemUserCallbacks.Stub.asInterface(
+                        service);
+                EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_CONNECTION,
+                        EventLogConstants.SYSUI_RECENTS_CONNECTION_USER_SYSTEM_BOUND,
+                        sSystemServicesProxy.getProcessUser());
+
+                // Listen for system user's death, so that we can reconnect later
+                try {
+                    service.linkToDeath(mUserToSystemCallbacksDeathRcpt, 0);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Lost connection to (System) SystemUI", e);
+                }
+
+                // Run each of the queued runnables
+                runAndFlushOnConnectRunnables();
+            }
+
+            // Unbind ourselves now that we've registered our callbacks.  The
+            // binder to the system user are still valid at this point.
+            mContext.unbindService(this);
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            // Do nothing
+        }
+    };
+
+    /**
+     * Returns the callbacks interface that non-system users can call.
+     */
+    public IBinder getSystemUserCallbacks() {
+        return mSystemToUserCallbacks;
+    }
+
+    public static RecentsTaskLoader getTaskLoader() {
+        return sTaskLoader;
+    }
+
+
+    public static SystemServicesProxy getSystemServices() {
+        return sSystemServicesProxy;
+    }
+
+    public static RecentsConfiguration getConfiguration() {
+        return sConfiguration;
+    }
+
+    public static RecentsDebugFlags getDebugFlags() {
+        return sDebugFlags;
+    }
+
+    @Override
+    public void onStart(Context context, SysUiServiceProvider sysUiServiceProvider) {
+        mContext = context;
+        mSysUiServiceProvider = sysUiServiceProvider;
+        final Resources res = mContext.getResources();
+        final int defaultTaskBarBackgroundColor =
+                mContext.getColor(R.color.recents_task_bar_default_background_color);
+        final int defaultTaskViewBackgroundColor =
+                mContext.getColor(R.color.recents_task_view_default_background_color);
+        sDebugFlags = new RecentsDebugFlags();
+        sSystemServicesProxy = SystemServicesProxy.getInstance(mContext);
+        sConfiguration = new RecentsConfiguration(mContext);
+        sTaskLoader = new RecentsTaskLoader(mContext,
+                // TODO: Once we start building the AAR, move these into the loader
+                res.getInteger(R.integer.config_recents_max_thumbnail_count),
+                res.getInteger(R.integer.config_recents_max_icon_count),
+                res.getInteger(R.integer.recents_svelte_level));
+        sTaskLoader.setDefaultColors(defaultTaskBarBackgroundColor, defaultTaskViewBackgroundColor);
+        mHandler = new Handler();
+        mImpl = new RecentsImpl(mContext);
+
+        // Register with the event bus
+        EventBus.getDefault().register(this, EVENT_BUS_PRIORITY);
+        EventBus.getDefault().register(sSystemServicesProxy, EVENT_BUS_PRIORITY);
+        EventBus.getDefault().register(sTaskLoader, EVENT_BUS_PRIORITY);
+
+        // Due to the fact that RecentsActivity is per-user, we need to establish and interface for
+        // the system user's Recents component to pass events (like show/hide/toggleRecents) to the
+        // secondary user, and vice versa (like visibility change, screen pinning).
+        final int processUser = sSystemServicesProxy.getProcessUser();
+        if (sSystemServicesProxy.isSystemUser(processUser)) {
+            // For the system user, initialize an instance of the interface that we can pass to the
+            // secondary user
+            mSystemToUserCallbacks = new RecentsSystemUser(mContext, mImpl);
+        } else {
+            // For the secondary user, bind to the primary user's service to get a persistent
+            // interface to register its implementation and to later update its state
+            registerWithSystemUser();
+        }
+    }
+
+    @Override
+    public void onBootCompleted() {
+        mImpl.onBootCompleted();
+    }
+
+
+    @Override
+    public void growRecents() {
+        EventBus.getDefault().send(new RecentsGrowingEvent());
+    }
+
+    /**
+     * Shows the Recents.
+     */
+    @Override
+    public void showRecentApps(boolean triggeredFromAltTab) {
+        ActivityManagerWrapper.getInstance().closeSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS);
+        int recentsGrowTarget = getComponent(Divider.class).getView().growsRecents();
+        int currentUser = sSystemServicesProxy.getCurrentUser();
+        if (sSystemServicesProxy.isSystemUser(currentUser)) {
+            mImpl.showRecents(triggeredFromAltTab, false /* draggingInRecents */,
+                    true /* animate */, recentsGrowTarget);
+        } else {
+            if (mSystemToUserCallbacks != null) {
+                IRecentsNonSystemUserCallbacks callbacks =
+                        mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+                if (callbacks != null) {
+                    try {
+                        callbacks.showRecents(triggeredFromAltTab, false /* draggingInRecents */,
+                                true /* animate */, recentsGrowTarget);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Callback failed", e);
+                    }
+                } else {
+                    Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
+                }
+            }
+        }
+    }
+
+    /**
+     * Hides the Recents.
+     */
+    @Override
+    public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
+        int currentUser = sSystemServicesProxy.getCurrentUser();
+        if (sSystemServicesProxy.isSystemUser(currentUser)) {
+            mImpl.hideRecents(triggeredFromAltTab, triggeredFromHomeKey);
+        } else {
+            if (mSystemToUserCallbacks != null) {
+                IRecentsNonSystemUserCallbacks callbacks =
+                        mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+                if (callbacks != null) {
+                    try {
+                        callbacks.hideRecents(triggeredFromAltTab, triggeredFromHomeKey);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Callback failed", e);
+                    }
+                } else {
+                    Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
+                }
+            }
+        }
+    }
+
+    /**
+     * Toggles the Recents activity.
+     */
+    @Override
+    public void toggleRecentApps() {
+        int growTarget = getComponent(Divider.class).getView().growsRecents();
+        int currentUser = sSystemServicesProxy.getCurrentUser();
+        if (sSystemServicesProxy.isSystemUser(currentUser)) {
+            mImpl.toggleRecents(growTarget);
+        } else {
+            if (mSystemToUserCallbacks != null) {
+                IRecentsNonSystemUserCallbacks callbacks =
+                        mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+                if (callbacks != null) {
+                    try {
+                        callbacks.toggleRecents(growTarget);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Callback failed", e);
+                    }
+                } else {
+                    Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
+                }
+            }
+        }
+    }
+
+    /**
+     * Preloads info for the Recents activity.
+     */
+    @Override
+    public void preloadRecentApps() {
+        int currentUser = sSystemServicesProxy.getCurrentUser();
+        if (sSystemServicesProxy.isSystemUser(currentUser)) {
+            mImpl.preloadRecents();
+        } else {
+            if (mSystemToUserCallbacks != null) {
+                IRecentsNonSystemUserCallbacks callbacks =
+                        mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+                if (callbacks != null) {
+                    try {
+                        callbacks.preloadRecents();
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Callback failed", e);
+                    }
+                } else {
+                    Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void cancelPreloadRecentApps() {
+        int currentUser = sSystemServicesProxy.getCurrentUser();
+        if (sSystemServicesProxy.isSystemUser(currentUser)) {
+            mImpl.cancelPreloadingRecents();
+        } else {
+            if (mSystemToUserCallbacks != null) {
+                IRecentsNonSystemUserCallbacks callbacks =
+                        mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+                if (callbacks != null) {
+                    try {
+                        callbacks.cancelPreloadingRecents();
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Callback failed", e);
+                    }
+                } else {
+                    Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
+                }
+            }
+        }
+    }
+
+    @Override
+    public boolean splitPrimaryTask(int stackCreateMode, Rect initialBounds, int metricsDockAction) {
+        Point realSize = new Point();
+        if (initialBounds == null) {
+            mContext.getSystemService(DisplayManager.class).getDisplay(Display.DEFAULT_DISPLAY)
+                    .getRealSize(realSize);
+            initialBounds = new Rect(0, 0, realSize.x, realSize.y);
+        }
+
+        int currentUser = sSystemServicesProxy.getCurrentUser();
+        ActivityManager.RunningTaskInfo runningTask =
+                ActivityManagerWrapper.getInstance().getRunningTask();
+        final int activityType = runningTask != null
+                ? runningTask.configuration.windowConfiguration.getActivityType()
+                : ACTIVITY_TYPE_UNDEFINED;
+        boolean screenPinningActive = ActivityManagerWrapper.getInstance().isScreenPinningActive();
+        boolean isRunningTaskInHomeOrRecentsStack =
+                activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS;
+        if (runningTask != null && !isRunningTaskInHomeOrRecentsStack && !screenPinningActive) {
+            logDockAttempt(mContext, runningTask.topActivity, runningTask.resizeMode);
+            if (runningTask.supportsSplitScreenMultiWindow) {
+                if (metricsDockAction != -1) {
+                    MetricsLogger.action(mContext, metricsDockAction,
+                            runningTask.topActivity.flattenToShortString());
+                }
+                if (sSystemServicesProxy.isSystemUser(currentUser)) {
+                    mImpl.splitPrimaryTask(runningTask.id, stackCreateMode, initialBounds);
+                } else {
+                    if (mSystemToUserCallbacks != null) {
+                        IRecentsNonSystemUserCallbacks callbacks =
+                                mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+                        if (callbacks != null) {
+                            try {
+                                callbacks.splitPrimaryTask(runningTask.id, stackCreateMode,
+                                        initialBounds);
+                            } catch (RemoteException e) {
+                                Log.e(TAG, "Callback failed", e);
+                            }
+                        } else {
+                            Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
+                        }
+                    }
+                }
+
+                return true;
+            } else {
+                EventBus.getDefault().send(new ShowUserToastEvent(
+                        R.string.dock_non_resizeble_failed_to_dock_text, Toast.LENGTH_SHORT));
+                return false;
+            }
+        } else {
+            return false;
+        }
+    }
+
+    public static void logDockAttempt(Context ctx, ComponentName activity, int resizeMode) {
+        if (resizeMode == ActivityInfo.RESIZE_MODE_UNRESIZEABLE) {
+            MetricsLogger.action(ctx, MetricsEvent.ACTION_WINDOW_DOCK_UNRESIZABLE,
+                    activity.flattenToShortString());
+        }
+        MetricsLogger.count(ctx, getMetricsCounterForResizeMode(resizeMode), 1);
+    }
+
+    private static String getMetricsCounterForResizeMode(int resizeMode) {
+        switch (resizeMode) {
+            case ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE:
+                return COUNTER_WINDOW_UNSUPPORTED;
+            case ActivityInfo.RESIZE_MODE_RESIZEABLE:
+            case ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION:
+                return COUNTER_WINDOW_SUPPORTED;
+            default:
+                return COUNTER_WINDOW_INCOMPATIBLE;
+        }
+    }
+
+    @Override
+    public void onAppTransitionFinished() {
+        if (!LegacyRecentsImpl.getConfiguration().isLowRamDevice) {
+            // Fallback, reset the flag once an app transition ends
+            EventBus.getDefault().send(new SetWaitingForTransitionStartEvent(
+                    false /* waitingForTransitionStart */));
+        }
+    }
+
+    /**
+     * Updates on configuration change.
+     */
+    public void onConfigurationChanged(Configuration newConfig) {
+        int currentUser = sSystemServicesProxy.getCurrentUser();
+        if (sSystemServicesProxy.isSystemUser(currentUser)) {
+            mImpl.onConfigurationChanged();
+        } else {
+            if (mSystemToUserCallbacks != null) {
+                IRecentsNonSystemUserCallbacks callbacks =
+                        mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+                if (callbacks != null) {
+                    try {
+                        callbacks.onConfigurationChanged();
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Callback failed", e);
+                    }
+                } else {
+                    Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
+                }
+            }
+        }
+    }
+
+    /**
+     * Handle Recents activity visibility changed.
+     */
+    public final void onBusEvent(final RecentsVisibilityChangedEvent event) {
+        SystemServicesProxy ssp = LegacyRecentsImpl.getSystemServices();
+        int processUser = ssp.getProcessUser();
+        if (ssp.isSystemUser(processUser)) {
+            mImpl.onVisibilityChanged(event.applicationContext, event.visible);
+        } else {
+            postToSystemUser(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        mUserToSystemCallbacks.updateRecentsVisibility(event.visible);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Callback failed", e);
+                    }
+                }
+            });
+        }
+
+        // This will catch the cases when a user launches from recents to another app
+        // (and vice versa) that is not in the recents stack (such as home or bugreport) and it
+        // would not reset the wait for transition flag. This will catch it and make sure that the
+        // flag is reset.
+        if (!event.visible) {
+            mImpl.setWaitingForTransitionStart(false);
+        }
+    }
+
+    public final void onBusEvent(DockedFirstAnimationFrameEvent event) {
+        SystemServicesProxy ssp = LegacyRecentsImpl.getSystemServices();
+        int processUser = ssp.getProcessUser();
+        if (ssp.isSystemUser(processUser)) {
+            final Divider divider = getComponent(Divider.class);
+            if (divider != null) {
+                divider.onDockedFirstAnimationFrame();
+            }
+        } else {
+            postToSystemUser(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        mUserToSystemCallbacks.sendDockedFirstAnimationFrameEvent();
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Callback failed", e);
+                    }
+                }
+            });
+        }
+    }
+
+    /**
+     * Handle screen pinning request.
+     */
+    public final void onBusEvent(final ScreenPinningRequestEvent event) {
+        int processUser = sSystemServicesProxy.getProcessUser();
+        if (sSystemServicesProxy.isSystemUser(processUser)) {
+            mImpl.onStartScreenPinning(event.applicationContext, event.taskId);
+        } else {
+            postToSystemUser(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        mUserToSystemCallbacks.startScreenPinning(event.taskId);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Callback failed", e);
+                    }
+                }
+            });
+        }
+    }
+
+    public final void onBusEvent(final RecentsDrawnEvent event) {
+        int processUser = sSystemServicesProxy.getProcessUser();
+        if (sSystemServicesProxy.isSystemUser(processUser)) {
+            final Divider divider = getComponent(Divider.class);
+            if (divider != null) {
+                divider.onRecentsDrawn();
+            }
+        } else {
+            postToSystemUser(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        mUserToSystemCallbacks.sendRecentsDrawnEvent();
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Callback failed", e);
+                    }
+                }
+            });
+        }
+    }
+
+    public final void onBusEvent(final DockedTopTaskEvent event) {
+        int processUser = sSystemServicesProxy.getProcessUser();
+        if (sSystemServicesProxy.isSystemUser(processUser)) {
+            final Divider divider = getComponent(Divider.class);
+            if (divider != null) {
+                divider.onDockedTopTask();
+            }
+        } else {
+            postToSystemUser(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        mUserToSystemCallbacks.sendDockingTopTaskEvent(event.initialRect);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Callback failed", e);
+                    }
+                }
+            });
+        }
+    }
+
+    public final void onBusEvent(final RecentsActivityStartingEvent event) {
+        int processUser = sSystemServicesProxy.getProcessUser();
+        if (sSystemServicesProxy.isSystemUser(processUser)) {
+            final Divider divider = getComponent(Divider.class);
+            if (divider != null) {
+                divider.onRecentsActivityStarting();
+            }
+        } else {
+            postToSystemUser(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        mUserToSystemCallbacks.sendLaunchRecentsEvent();
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Callback failed", e);
+                    }
+                }
+            });
+        }
+    }
+
+    public final void onBusEvent(LaunchTaskFailedEvent event) {
+        // Reset the transition when tasks fail to launch
+        mImpl.setWaitingForTransitionStart(false);
+    }
+
+    public final void onBusEvent(ConfigurationChangedEvent event) {
+        // Update the configuration for the Recents component when the activity configuration
+        // changes as well
+        mImpl.onConfigurationChanged();
+    }
+
+    public final void onBusEvent(ShowUserToastEvent event) {
+        int currentUser = sSystemServicesProxy.getCurrentUser();
+        if (sSystemServicesProxy.isSystemUser(currentUser)) {
+            mImpl.onShowCurrentUserToast(event.msgResId, event.msgLength);
+        } else {
+            if (mSystemToUserCallbacks != null) {
+                IRecentsNonSystemUserCallbacks callbacks =
+                        mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+                if (callbacks != null) {
+                    try {
+                        callbacks.showCurrentUserToast(event.msgResId, event.msgLength);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Callback failed", e);
+                    }
+                } else {
+                    Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
+                }
+            }
+        }
+    }
+
+    public final void onBusEvent(SetWaitingForTransitionStartEvent event) {
+        int processUser = sSystemServicesProxy.getProcessUser();
+        if (sSystemServicesProxy.isSystemUser(processUser)) {
+            mImpl.setWaitingForTransitionStart(event.waitingForTransitionStart);
+        } else {
+            postToSystemUser(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        mUserToSystemCallbacks.setWaitingForTransitionStartEvent(
+                                event.waitingForTransitionStart);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Callback failed", e);
+                    }
+                }
+            });
+        }
+    }
+
+    public final void onBusEvent(ExpandPipEvent event) {
+        PipUI pipUi = getComponent(PipUI.class);
+        pipUi.expandPip();
+    }
+
+    public final void onBusEvent(HidePipMenuEvent event) {
+        PipUI pipUi = getComponent(PipUI.class);
+        event.getAnimationTrigger().increment();
+        pipUi.hidePipMenu(() -> {
+                event.getAnimationTrigger().increment();
+            }, () -> {
+                event.getAnimationTrigger().decrement();
+            });
+        event.getAnimationTrigger().decrement();
+    }
+
+    /**
+     * Attempts to register with the system user.
+     */
+    private void registerWithSystemUser() {
+        final int processUser = sSystemServicesProxy.getProcessUser();
+        postToSystemUser(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    mUserToSystemCallbacks.registerNonSystemUserCallbacks(
+                            new RecentsImplProxy(mImpl), processUser);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Failed to register", e);
+                }
+            }
+        });
+    }
+
+    /**
+     * Runs the runnable in the system user's Recents context, connecting to the service if
+     * necessary.
+     */
+    private void postToSystemUser(final Runnable onConnectRunnable) {
+        mOnConnectRunnables.add(onConnectRunnable);
+        if (mUserToSystemCallbacks == null) {
+            Intent systemUserServiceIntent = new Intent();
+            systemUserServiceIntent.setClass(mContext, RecentsSystemUserService.class);
+            boolean bound = mContext.bindServiceAsUser(systemUserServiceIntent,
+                    mUserToSystemServiceConnection, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM);
+            EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_CONNECTION,
+                    EventLogConstants.SYSUI_RECENTS_CONNECTION_USER_BIND_SERVICE,
+                    sSystemServicesProxy.getProcessUser());
+            if (!bound) {
+                // Retry after a fixed duration
+                mHandler.postDelayed(new Runnable() {
+                    @Override
+                    public void run() {
+                        registerWithSystemUser();
+                    }
+                }, BIND_TO_SYSTEM_USER_RETRY_DELAY);
+            }
+        } else {
+            runAndFlushOnConnectRunnables();
+        }
+    }
+
+    /**
+     * Runs all the queued runnables after a service connection is made.
+     */
+    private void runAndFlushOnConnectRunnables() {
+        for (Runnable r : mOnConnectRunnables) {
+            r.run();
+        }
+        mOnConnectRunnables.clear();
+    }
+
+    private <T> T getComponent(Class<T> clazz) {
+        return mSysUiServiceProvider.getComponent(clazz);
+    }
+
+    @Override
+    public void dump(PrintWriter pw) {
+        pw.println("Recents");
+        pw.println("  currentUserId=" + SystemServicesProxy.getInstance(mContext).getCurrentUser());
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/RecentsActivity.java
similarity index 94%
rename from packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/RecentsActivity.java
index 36a1255..cec97ab 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/RecentsActivity.java
@@ -87,16 +87,15 @@
 import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent;
 import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent.Direction;
 import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.shared.recents.utilities.Utilities;
-import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
-import com.android.systemui.shared.recents.model.RecentsTaskLoader;
+import com.android.systemui.recents.utilities.Utilities;
+import com.android.systemui.recents.model.RecentsTaskLoadPlan;
+import com.android.systemui.recents.model.RecentsTaskLoader;
 import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.recents.model.TaskStack;
+import com.android.systemui.recents.model.TaskStack;
 import com.android.systemui.recents.views.RecentsView;
 import com.android.systemui.recents.views.SystemBarScrimViews;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 
-import com.android.systemui.shared.system.WindowManagerWrapper;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
@@ -109,7 +108,7 @@
     private final static String TAG = "RecentsActivity";
     private final static boolean DEBUG = false;
 
-    public final static int EVENT_BUS_PRIORITY = Recents.EVENT_BUS_PRIORITY + 1;
+    public final static int EVENT_BUS_PRIORITY = LegacyRecentsImpl.EVENT_BUS_PRIORITY + 1;
     public final static int INCOMPATIBLE_APP_ALPHA_DURATION = 150;
 
     private PackageMonitor mPackageMonitor = new PackageMonitor() {
@@ -217,8 +216,8 @@
                                 LatencyTracker.ACTION_TOGGLE_RECENTS));
                     }
                     DejankUtils.postAfterTraversal(() -> {
-                        Recents.getTaskLoader().startLoader(RecentsActivity.this);
-                        Recents.getTaskLoader().getHighResThumbnailLoader().setVisible(true);
+                        LegacyRecentsImpl.getTaskLoader().startLoader(RecentsActivity.this);
+                        LegacyRecentsImpl.getTaskLoader().getHighResThumbnailLoader().setVisible(true);
                     });
                     return true;
                 }
@@ -228,7 +227,7 @@
      * Dismisses recents if we are already visible and the intent is to toggle the recents view.
      */
     boolean dismissRecentsToFocusedTask(int logCategory) {
-        SystemServicesProxy ssp = Recents.getSystemServices();
+        SystemServicesProxy ssp = LegacyRecentsImpl.getSystemServices();
         if (ssp.isRecentsActivityVisible()) {
             // If we have a focused Task, launch that Task now
             if (mRecentsView.launchFocusedTask(logCategory)) return true;
@@ -240,7 +239,7 @@
      * Dismisses recents back to the launch target task.
      */
     boolean dismissRecentsToLaunchTargetTaskOrHome() {
-        SystemServicesProxy ssp = Recents.getSystemServices();
+        SystemServicesProxy ssp = LegacyRecentsImpl.getSystemServices();
         if (ssp.isRecentsActivityVisible()) {
             // If we have a focused Task, launch that Task now
             if (mRecentsView.launchPreviousTask()) return true;
@@ -254,7 +253,7 @@
      * Dismisses recents if we are already visible and the intent is to toggle the recents view.
      */
     boolean dismissRecentsToFocusedTaskOrHome() {
-        SystemServicesProxy ssp = Recents.getSystemServices();
+        SystemServicesProxy ssp = LegacyRecentsImpl.getSystemServices();
         if (ssp.isRecentsActivityVisible()) {
             // If we have a focused Task, launch that Task now
             if (mRecentsView.launchFocusedTask(0 /* logCategory */)) return true;
@@ -289,7 +288,7 @@
 
     /** Dismisses Recents directly to Home if we currently aren't transitioning. */
     boolean dismissRecentsToHomeIfVisible(boolean animated) {
-        SystemServicesProxy ssp = Recents.getSystemServices();
+        SystemServicesProxy ssp = LegacyRecentsImpl.getSystemServices();
         if (ssp.isRecentsActivityVisible()) {
             // Return to Home
             dismissRecentsToHome(animated);
@@ -306,7 +305,7 @@
 
         // In the case that the activity starts up before the Recents component has initialized
         // (usually when debugging/pushing the SysUI apk), just finish this activity.
-        SystemServicesProxy ssp = Recents.getSystemServices();
+        SystemServicesProxy ssp = LegacyRecentsImpl.getSystemServices();
         if (ssp == null) {
             mFinishedOnStartup = true;
             finish();
@@ -335,7 +334,7 @@
         mScrimViews = new SystemBarScrimViews(this);
         getWindow().getAttributes().privateFlags |=
                 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
-        if (Recents.getConfiguration().isLowRamDevice) {
+        if (LegacyRecentsImpl.getConfiguration().isLowRamDevice) {
             getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
         }
 
@@ -384,7 +383,7 @@
         // reset launch state with dock, app and home set to false
         Object isRelaunching = getLastNonConfigurationInstance();
         if (isRelaunching != null && isRelaunching instanceof Boolean && (boolean) isRelaunching) {
-            RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
+            RecentsActivityLaunchState launchState = LegacyRecentsImpl.getConfiguration().getLaunchState();
             launchState.launchedViaDockGesture = false;
             launchState.launchedFromApp = false;
             launchState.launchedFromHome = false;
@@ -418,14 +417,14 @@
     private void reloadStackView() {
         // If the Recents component has preloaded a load plan, then use that to prevent
         // reconstructing the task stack
-        RecentsTaskLoader loader = Recents.getTaskLoader();
+        RecentsTaskLoader loader = LegacyRecentsImpl.getTaskLoader();
         RecentsTaskLoadPlan loadPlan = RecentsImpl.consumeInstanceLoadPlan();
         if (loadPlan == null) {
             loadPlan = new RecentsTaskLoadPlan(this);
         }
 
         // Start loading tasks according to the load plan
-        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsConfiguration config = LegacyRecentsImpl.getConfiguration();
         RecentsActivityLaunchState launchState = config.getLaunchState();
         if (!loadPlan.hasTasks()) {
             loader.preloadTasks(loadPlan, launchState.launchedToTaskId);
@@ -538,7 +537,7 @@
         mIsVisible = false;
         EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, false));
         MetricsLogger.hidden(this, MetricsEvent.OVERVIEW_ACTIVITY);
-        Recents.getTaskLoader().getHighResThumbnailLoader().setVisible(false);
+        LegacyRecentsImpl.getTaskLoader().getHighResThumbnailLoader().setVisible(false);
 
         // When recents starts again before onStop, do not reset launch flags so entrance animation
         // can run
@@ -546,13 +545,13 @@
             // Workaround for b/22542869, if the RecentsActivity is started again, but without going
             // through SystemUI, we need to reset the config launch flags to ensure that we do not
             // wait on the system to send a signal that was never queued.
-            RecentsConfiguration config = Recents.getConfiguration();
+            RecentsConfiguration config = LegacyRecentsImpl.getConfiguration();
             RecentsActivityLaunchState launchState = config.getLaunchState();
             launchState.reset();
         }
 
         // Force a gc to attempt to clean up bitmap references more quickly (b/38258699)
-        Recents.getSystemServices().gc();
+        LegacyRecentsImpl.getSystemServices().gc();
     }
 
     @Override
@@ -587,7 +586,7 @@
 
     @Override
     public void onTrimMemory(int level) {
-        RecentsTaskLoader loader = Recents.getTaskLoader();
+        RecentsTaskLoader loader = LegacyRecentsImpl.getTaskLoader();
         if (loader != null) {
             loader.onTrimMemory(level);
         }
@@ -656,7 +655,7 @@
     /**** EventBus events ****/
 
     public final void onBusEvent(ToggleRecentsEvent event) {
-        RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
+        RecentsActivityLaunchState launchState = LegacyRecentsImpl.getConfiguration().getLaunchState();
         if (launchState.launchedFromHome) {
             dismissRecentsToHome(true /* animateTaskViews */);
         } else {
@@ -700,7 +699,7 @@
     }
 
     public final void onBusEvent(CancelEnterRecentsWindowAnimationEvent event) {
-        RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
+        RecentsActivityLaunchState launchState = LegacyRecentsImpl.getConfiguration().getLaunchState();
         int launchToTaskId = launchState.launchedToTaskId;
         if (launchToTaskId != -1 &&
                 (event.launchTask == null || launchToTaskId != event.launchTask.key.id)) {
@@ -748,7 +747,7 @@
 
     public final void onBusEvent(DeleteTaskDataEvent event) {
         // Remove any stored data from the loader
-        RecentsTaskLoader loader = Recents.getTaskLoader();
+        RecentsTaskLoader loader = LegacyRecentsImpl.getTaskLoader();
         loader.deleteTaskData(event.task, false);
 
         // Remove the task from activity manager
@@ -760,7 +759,7 @@
     }
 
     public final void onBusEvent(AllTaskViewsDismissedEvent event) {
-        SystemServicesProxy ssp = Recents.getSystemServices();
+        SystemServicesProxy ssp = LegacyRecentsImpl.getSystemServices();
         if (ssp.hasDockedTask()) {
             mRecentsView.showEmptyView(event.msgResId);
         } else {
@@ -808,9 +807,9 @@
 
     private void reloadTaskStack(boolean isInMultiWindowMode, boolean sendConfigChangedEvent) {
         // Reload the task stack completely
-        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsConfiguration config = LegacyRecentsImpl.getConfiguration();
         RecentsActivityLaunchState launchState = config.getLaunchState();
-        RecentsTaskLoader loader = Recents.getTaskLoader();
+        RecentsTaskLoader loader = LegacyRecentsImpl.getTaskLoader();
         RecentsTaskLoadPlan loadPlan = new RecentsTaskLoadPlan(this);
         loader.preloadTasks(loadPlan, -1 /* runningTaskId */);
 
@@ -839,7 +838,7 @@
     }
 
     public void onPackageChanged(String packageName, int userId) {
-        Recents.getTaskLoader().onPackageChanged(packageName);
+        LegacyRecentsImpl.getTaskLoader().onPackageChanged(packageName);
         EventBus.getDefault().send(new PackagesChangedEvent(packageName, userId));
     }
 
@@ -847,7 +846,7 @@
     public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
         super.dump(prefix, fd, writer, args);
         EventBus.getDefault().dump(prefix, writer);
-        Recents.getTaskLoader().dump(prefix, writer);
+        LegacyRecentsImpl.getTaskLoader().dump(prefix, writer);
 
         String id = Integer.toHexString(System.identityHashCode(this));
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/RecentsActivityLaunchState.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/RecentsActivityLaunchState.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/RecentsConfiguration.java
similarity index 95%
rename from packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/RecentsConfiguration.java
index 68df1d5..ee53734 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -26,7 +26,6 @@
 import com.android.systemui.R;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.views.DockState;
-import com.android.systemui.shared.recents.model.TaskStack;
 
 /**
  * Represents the dock regions for each orientation.
@@ -86,7 +85,7 @@
     public RecentsConfiguration(Context context) {
         // Load only resources that can not change after the first load either through developer
         // settings or via multi window
-        SystemServicesProxy ssp = Recents.getSystemServices();
+        SystemServicesProxy ssp = LegacyRecentsImpl.getSystemServices();
         mAppContext = context.getApplicationContext();
         Resources res = mAppContext.getResources();
         fakeShadows = res.getBoolean(R.bool.config_recents_fake_shadows);
@@ -116,7 +115,7 @@
     public DockState[] getDockStatesForCurrentOrientation() {
         boolean isLandscape = mAppContext.getResources().getConfiguration().orientation ==
                 Configuration.ORIENTATION_LANDSCAPE;
-        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsConfiguration config = LegacyRecentsImpl.getConfiguration();
         if (config.isLargeScreen) {
             return isLandscape ? DockRegion.TABLET_LANDSCAPE : DockRegion.TABLET_PORTRAIT;
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/RecentsDebugFlags.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/RecentsDebugFlags.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/RecentsImpl.java
similarity index 93%
rename from packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/RecentsImpl.java
index d95c731..3e5acab 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/RecentsImpl.java
@@ -47,7 +47,6 @@
 import android.widget.Toast;
 
 import com.android.systemui.Dependency;
-import com.android.systemui.OverviewProxyService;
 import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.pip.phone.ForegroundThread;
 import com.google.android.collect.Lists;
@@ -55,7 +54,6 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.policy.DockedDividerUtils;
 import com.android.systemui.R;
-import com.android.systemui.SystemUIApplication;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
 import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
@@ -75,11 +73,11 @@
 import com.android.systemui.recents.misc.DozeTrigger;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
-import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
-import com.android.systemui.shared.recents.model.RecentsTaskLoader;
+import com.android.systemui.recents.model.RecentsTaskLoadPlan;
+import com.android.systemui.recents.model.RecentsTaskLoader;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.Task.TaskKey;
-import com.android.systemui.shared.recents.model.TaskStack;
+import com.android.systemui.recents.model.TaskStack;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 import com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
 import com.android.systemui.recents.views.TaskStackLayoutAlgorithm.VisibilityReport;
@@ -143,7 +141,7 @@
             }
 
             // Preloads the next task
-            RecentsConfiguration config = Recents.getConfiguration();
+            RecentsConfiguration config = LegacyRecentsImpl.getConfiguration();
             if (config.svelteLevel == RecentsTaskLoader.SVELTE_NONE) {
                 Rect windowRect = getWindowRect(null /* windowRectOverride */);
                 if (windowRect.isEmpty()) {
@@ -153,7 +151,7 @@
                 // Load the next task only if we aren't svelte
                 ActivityManager.RunningTaskInfo runningTaskInfo =
                         ActivityManagerWrapper.getInstance().getRunningTask();
-                RecentsTaskLoader loader = Recents.getTaskLoader();
+                RecentsTaskLoader loader = LegacyRecentsImpl.getTaskLoader();
                 RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(mContext);
                 loader.preloadTasks(plan, -1);
                 TaskStack stack = plan.getTaskStack();
@@ -195,8 +193,8 @@
 
             // This time needs to be fetched the same way the last active time is fetched in
             // {@link TaskRecord#touchActiveTime}
-            Recents.getConfiguration().getLaunchState().launchedFromPipApp = true;
-            Recents.getConfiguration().getLaunchState().launchedWithNextPipApp = false;
+            LegacyRecentsImpl.getConfiguration().getLaunchState().launchedFromPipApp = true;
+            LegacyRecentsImpl.getConfiguration().getLaunchState().launchedWithNextPipApp = false;
             EventBus.getDefault().send(new ActivityPinnedEvent(taskId));
             consumeInstanceLoadPlan();
             sLastPipTime = System.currentTimeMillis();
@@ -278,7 +276,7 @@
         public void onConnectionChanged(boolean isConnected) {
             if (!isConnected) {
                 // Clear everything when the connection to the overview service
-                Recents.getTaskLoader().onTrimMemory(ComponentCallbacks2.TRIM_MEMORY_COMPLETE);
+                LegacyRecentsImpl.getTaskLoader().onTrimMemory(ComponentCallbacks2.TRIM_MEMORY_COMPLETE);
             }
         }
     };
@@ -313,7 +311,7 @@
 
         // When we start, preload the data associated with the previous recent tasks.
         // We can use a new plan since the caches will be the same.
-        RecentsTaskLoader loader = Recents.getTaskLoader();
+        RecentsTaskLoader loader = LegacyRecentsImpl.getTaskLoader();
         RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(mContext);
         loader.preloadTasks(plan, -1);
         RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
@@ -334,16 +332,16 @@
     /**
      * This is only called from the system user's Recents.  Secondary users will instead proxy their
      * visibility change events through to the system user via
-     * {@link Recents#onBusEvent(RecentsVisibilityChangedEvent)}.
+     * {@link LegacyRecentsImpl#onBusEvent(RecentsVisibilityChangedEvent)}.
      */
     public void onVisibilityChanged(Context context, boolean visible) {
-        Recents.getSystemServices().setRecentsVisibility(visible);
+        LegacyRecentsImpl.getSystemServices().setRecentsVisibility(visible);
     }
 
     /**
      * This is only called from the system user's Recents.  Secondary users will instead proxy their
      * visibility change events through to the system user via
-     * {@link Recents#onBusEvent(ScreenPinningRequestEvent)}.
+     * {@link LegacyRecentsImpl#onBusEvent(ScreenPinningRequestEvent)}.
      */
     public void onStartScreenPinning(Context context, int taskId) {
         final StatusBar statusBar = getStatusBar();
@@ -354,13 +352,13 @@
 
     public void showRecents(boolean triggeredFromAltTab, boolean draggingInRecents,
             boolean animate, int growTarget) {
-        final SystemServicesProxy ssp = Recents.getSystemServices();
+        final SystemServicesProxy ssp = LegacyRecentsImpl.getSystemServices();
         final MutableBoolean isHomeStackVisible = new MutableBoolean(true);
-        final boolean isRecentsVisible = Recents.getSystemServices().isRecentsActivityVisible(
+        final boolean isRecentsVisible = LegacyRecentsImpl.getSystemServices().isRecentsActivityVisible(
                 isHomeStackVisible);
         final boolean fromHome = isHomeStackVisible.value;
         final boolean launchedWhileDockingTask =
-                Recents.getSystemServices().getSplitScreenPrimaryStack() != null;
+                LegacyRecentsImpl.getSystemServices().getSplitScreenPrimaryStack() != null;
 
         mTriggeredFromAltTab = triggeredFromAltTab;
         mDraggingInRecents = draggingInRecents;
@@ -439,12 +437,12 @@
             MutableBoolean isHomeStackVisible = new MutableBoolean(true);
             long elapsedTime = SystemClock.elapsedRealtime() - mLastToggleTime;
 
-            SystemServicesProxy ssp = Recents.getSystemServices();
+            SystemServicesProxy ssp = LegacyRecentsImpl.getSystemServices();
             if (ssp.isRecentsActivityVisible(isHomeStackVisible)) {
-                RecentsConfiguration config = Recents.getConfiguration();
+                RecentsConfiguration config = LegacyRecentsImpl.getConfiguration();
                 RecentsActivityLaunchState launchState = config.getLaunchState();
                 if (!launchState.launchedWithAltTab) {
-                    if (Recents.getConfiguration().isGridEnabled) {
+                    if (LegacyRecentsImpl.getConfiguration().isGridEnabled) {
                         // Has the user tapped quickly?
                         boolean isQuickTap = elapsedTime < ViewConfiguration.getDoubleTapTimeout();
                         if (isQuickTap) {
@@ -509,7 +507,7 @@
         // RecentsActivity) only if there is a task to animate to.  Post this to ensure that we
         // don't block the touch feedback on the nav bar button which triggers this.
         mHandler.post(() -> {
-            SystemServicesProxy ssp = Recents.getSystemServices();
+            SystemServicesProxy ssp = LegacyRecentsImpl.getSystemServices();
             if (!ssp.isRecentsActivityVisible(null)) {
                 ActivityManager.RunningTaskInfo runningTask =
                         ActivityManagerWrapper.getInstance().getRunningTask();
@@ -517,7 +515,7 @@
                     return;
                 }
 
-                RecentsTaskLoader loader = Recents.getTaskLoader();
+                RecentsTaskLoader loader = LegacyRecentsImpl.getTaskLoader();
                 sInstanceLoadPlan = new RecentsTaskLoadPlan(mContext);
                 loader.preloadTasks(sInstanceLoadPlan, runningTask.id);
                 TaskStack stack = sInstanceLoadPlan.getTaskStack();
@@ -556,8 +554,8 @@
      * Transitions to the next recent task in the stack.
      */
     public void showNextTask() {
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        RecentsTaskLoader loader = Recents.getTaskLoader();
+        SystemServicesProxy ssp = LegacyRecentsImpl.getSystemServices();
+        RecentsTaskLoader loader = LegacyRecentsImpl.getTaskLoader();
         RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(mContext);
         loader.preloadTasks(plan, -1);
         TaskStack focusedStack = plan.getTaskStack();
@@ -612,8 +610,8 @@
      * Transitions to the next affiliated task.
      */
     public void showRelativeAffiliatedTask(boolean showNextTask) {
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        RecentsTaskLoader loader = Recents.getTaskLoader();
+        SystemServicesProxy ssp = LegacyRecentsImpl.getSystemServices();
+        RecentsTaskLoader loader = LegacyRecentsImpl.getTaskLoader();
         RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(mContext);
         loader.preloadTasks(plan, -1);
         TaskStack focusedStack = plan.getTaskStack();
@@ -678,20 +676,8 @@
                 null /* resultListener */, null /* resultCallbackHandler */);
     }
 
-    public void showNextAffiliatedTask() {
-        // Keep track of when the affiliated task is triggered
-        MetricsLogger.count(mContext, "overview_affiliated_task_next", 1);
-        showRelativeAffiliatedTask(true);
-    }
-
-    public void showPrevAffiliatedTask() {
-        // Keep track of when the affiliated task is triggered
-        MetricsLogger.count(mContext, "overview_affiliated_task_prev", 1);
-        showRelativeAffiliatedTask(false);
-    }
-
     public void splitPrimaryTask(int taskId, int stackCreateMode, Rect initialBounds) {
-        SystemServicesProxy ssp = Recents.getSystemServices();
+        SystemServicesProxy ssp = LegacyRecentsImpl.getSystemServices();
 
         // Make sure we inform DividerView before we actually start the activity so we can change
         // the resize mode already.
@@ -758,7 +744,7 @@
 
     private void updateDummyStackViewLayout(TaskStackLayoutAlgorithm stackLayout,
             TaskStack stack, Rect windowRect) {
-        SystemServicesProxy ssp = Recents.getSystemServices();
+        SystemServicesProxy ssp = LegacyRecentsImpl.getSystemServices();
         Rect displayRect = ssp.getDisplayRect();
         Rect systemInsets = new Rect();
         ssp.getStableInsets(systemInsets);
@@ -789,7 +775,7 @@
     private Rect getWindowRect(Rect windowRectOverride) {
        return windowRectOverride != null
                 ? new Rect(windowRectOverride)
-                : Recents.getSystemServices().getWindowRect();
+                : LegacyRecentsImpl.getSystemServices().getWindowRect();
     }
 
     /**
@@ -871,7 +857,7 @@
         launchOpts.runningTaskId = runningTaskId;
         launchOpts.loadThumbnails = false;
         launchOpts.onlyLoadForCache = true;
-        Recents.getTaskLoader().loadTasks(sInstanceLoadPlan, launchOpts);
+        LegacyRecentsImpl.getTaskLoader().loadTasks(sInstanceLoadPlan, launchOpts);
     }
 
     /**
@@ -900,7 +886,7 @@
     private Pair<ActivityOptions, AppTransitionAnimationSpecsFuture>
             getThumbnailTransitionActivityOptions(ActivityManager.RunningTaskInfo runningTask,
                     Rect windowOverrideRect) {
-        final boolean isLowRamDevice = Recents.getConfiguration().isLowRamDevice;
+        final boolean isLowRamDevice = LegacyRecentsImpl.getConfiguration().isLowRamDevice;
 
         // Update the destination rect
         Task toTask = new Task();
@@ -955,7 +941,7 @@
      */
     private Bitmap drawThumbnailTransitionBitmap(Task toTask,
             TaskViewTransform toTransform) {
-        SystemServicesProxy ssp = Recents.getSystemServices();
+        SystemServicesProxy ssp = LegacyRecentsImpl.getSystemServices();
         int width = (int) toTransform.rect.width();
         int height = (int) toTransform.rect.height();
         if (toTransform != null && toTask.key != null && width > 0 && height > 0) {
@@ -1007,8 +993,8 @@
 
     private void startRecentsActivity(ActivityManager.RunningTaskInfo runningTask,
             boolean isHomeStackVisible, boolean animate, int growTarget) {
-        RecentsTaskLoader loader = Recents.getTaskLoader();
-        RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
+        RecentsTaskLoader loader = LegacyRecentsImpl.getTaskLoader();
+        RecentsActivityLaunchState launchState = LegacyRecentsImpl.getConfiguration().getLaunchState();
 
         int runningTaskId = !mLaunchedWhileDocking && (runningTask != null)
                 ? runningTask.id
@@ -1087,10 +1073,10 @@
             return SystemServicesProxy.getInstance(mContext).getWindowRect();
         }
         Rect result = new Rect();
-        Rect displayRect = Recents.getSystemServices().getDisplayRect();
+        Rect displayRect = LegacyRecentsImpl.getSystemServices().getDisplayRect();
         DockedDividerUtils.calculateBoundsForPosition(growTarget, WindowManager.DOCKED_BOTTOM,
                 result, displayRect.width(), displayRect.height(),
-                Recents.getSystemServices().getDockedDividerSize(mContext));
+                LegacyRecentsImpl.getSystemServices().getDockedDividerSize(mContext));
         return result;
     }
 
@@ -1110,7 +1096,7 @@
                 | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
         HidePipMenuEvent hideMenuEvent = new HidePipMenuEvent();
         hideMenuEvent.addPostAnimationCallback(() -> {
-            Recents.getSystemServices().startActivityAsUserAsync(intent, opts);
+            LegacyRecentsImpl.getSystemServices().startActivityAsUserAsync(intent, opts);
             EventBus.getDefault().send(new RecentsActivityStartingEvent());
             if (future != null) {
                 future.composeSpecsSynchronous();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/RecentsImplProxy.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/RecentsImplProxy.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/RecentsSystemUser.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/RecentsSystemUser.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUserService.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/RecentsSystemUserService.java
similarity index 91%
rename from packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUserService.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/RecentsSystemUserService.java
index b4212d3..b5a0181 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUserService.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/RecentsSystemUserService.java
@@ -22,7 +22,6 @@
 import android.util.Log;
 
 import com.android.systemui.SysUiServiceProvider;
-import com.android.systemui.SystemUIApplication;
 
 /**
  * A strictly system-user service that is started by the secondary user's Recents (with a limited
@@ -41,7 +40,7 @@
 
     @Override
     public IBinder onBind(Intent intent) {
-        Recents recents = SysUiServiceProvider.getComponent(this, Recents.class);
+        LegacyRecentsImpl recents = SysUiServiceProvider.getComponent(this, LegacyRecentsImpl.class);
         if (DEBUG) {
             Log.d(TAG, "onBind: " + recents);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/EventBus.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/EventBus.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/AppTransitionFinishedEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/AppTransitionFinishedEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/activity/AppTransitionFinishedEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/AppTransitionFinishedEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/CancelEnterRecentsWindowAnimationEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/CancelEnterRecentsWindowAnimationEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/activity/CancelEnterRecentsWindowAnimationEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/CancelEnterRecentsWindowAnimationEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/DismissRecentsToHomeAnimationStarted.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/DismissRecentsToHomeAnimationStarted.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/activity/DismissRecentsToHomeAnimationStarted.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/DismissRecentsToHomeAnimationStarted.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockedFirstAnimationFrameEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/DockedFirstAnimationFrameEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/activity/DockedFirstAnimationFrameEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/DockedFirstAnimationFrameEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockedTopTaskEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/DockedTopTaskEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/activity/DockedTopTaskEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/DockedTopTaskEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/EnterRecentsWindowAnimationCompletedEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/EnterRecentsWindowAnimationCompletedEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/activity/EnterRecentsWindowAnimationCompletedEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/EnterRecentsWindowAnimationCompletedEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/EnterRecentsWindowLastAnimationFrameEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/EnterRecentsWindowLastAnimationFrameEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/activity/EnterRecentsWindowLastAnimationFrameEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/EnterRecentsWindowLastAnimationFrameEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ExitRecentsWindowFirstAnimationFrameEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/ExitRecentsWindowFirstAnimationFrameEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/activity/ExitRecentsWindowFirstAnimationFrameEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/ExitRecentsWindowFirstAnimationFrameEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideRecentsEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/HideRecentsEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/activity/HideRecentsEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/HideRecentsEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideStackActionButtonEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/HideStackActionButtonEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/activity/HideStackActionButtonEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/HideStackActionButtonEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchMostRecentTaskRequestEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/LaunchMostRecentTaskRequestEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchMostRecentTaskRequestEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/LaunchMostRecentTaskRequestEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchNextTaskRequestEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/LaunchNextTaskRequestEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchNextTaskRequestEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/LaunchNextTaskRequestEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskFailedEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/LaunchTaskFailedEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskFailedEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/LaunchTaskFailedEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskStartedEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/LaunchTaskStartedEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskStartedEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/LaunchTaskStartedEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskSucceededEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/LaunchTaskSucceededEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskSucceededEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/LaunchTaskSucceededEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java
similarity index 95%
rename from packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java
index e4972b1..64eeafa 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java
@@ -17,7 +17,7 @@
 package com.android.systemui.recents.events.activity;
 
 import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.shared.recents.model.TaskStack;
+import com.android.systemui.recents.model.TaskStack;
 
 /**
  * This is sent by the activity whenever the multi-window state has changed.
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/PackagesChangedEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/PackagesChangedEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/activity/PackagesChangedEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/PackagesChangedEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/RecentsActivityStartingEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/RecentsActivityStartingEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/activity/RecentsActivityStartingEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/RecentsActivityStartingEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowEmptyViewEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/ShowEmptyViewEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowEmptyViewEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/ShowEmptyViewEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowStackActionButtonEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/ShowStackActionButtonEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowStackActionButtonEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/ShowStackActionButtonEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java
similarity index 94%
rename from packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java
index 51d02b5..0d614e8c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java
@@ -17,7 +17,7 @@
 package com.android.systemui.recents.events.activity;
 
 import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.shared.recents.model.TaskStack;
+import com.android.systemui.recents.model.TaskStack;
 
 /**
  * This is sent by the activity whenever the task stach has changed.
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ToggleRecentsEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/ToggleRecentsEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/activity/ToggleRecentsEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/ToggleRecentsEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/UndockingTaskEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/UndockingTaskEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/activity/UndockingTaskEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/activity/UndockingTaskEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/component/ActivityPinnedEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/component/ActivityPinnedEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/component/ActivityPinnedEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/component/ActivityPinnedEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/component/ActivityUnpinnedEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/component/ActivityUnpinnedEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/component/ActivityUnpinnedEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/component/ActivityUnpinnedEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/component/ExpandPipEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/component/ExpandPipEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/component/ExpandPipEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/component/ExpandPipEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/component/HidePipMenuEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/component/HidePipMenuEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/component/HidePipMenuEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/component/HidePipMenuEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/component/RecentsVisibilityChangedEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/component/RecentsVisibilityChangedEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/component/RecentsVisibilityChangedEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/component/RecentsVisibilityChangedEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/component/ScreenPinningRequestEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/component/ScreenPinningRequestEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/component/ScreenPinningRequestEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/component/ScreenPinningRequestEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/component/SetWaitingForTransitionStartEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/component/SetWaitingForTransitionStartEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/component/SetWaitingForTransitionStartEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/component/SetWaitingForTransitionStartEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/component/ShowUserToastEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/component/ShowUserToastEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/component/ShowUserToastEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/component/ShowUserToastEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/AllTaskViewsDismissedEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/AllTaskViewsDismissedEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/ui/AllTaskViewsDismissedEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/AllTaskViewsDismissedEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/DeleteTaskDataEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/DeleteTaskDataEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/ui/DeleteTaskDataEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/DeleteTaskDataEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissAllTaskViewsEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/DismissAllTaskViewsEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissAllTaskViewsEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/DismissAllTaskViewsEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskViewEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/DismissTaskViewEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskViewEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/DismissTaskViewEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/DraggingInRecentsEndedEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/DraggingInRecentsEndedEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/ui/DraggingInRecentsEndedEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/DraggingInRecentsEndedEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/DraggingInRecentsEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/DraggingInRecentsEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/ui/DraggingInRecentsEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/DraggingInRecentsEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/HideIncompatibleAppOverlayEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/HideIncompatibleAppOverlayEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/ui/HideIncompatibleAppOverlayEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/HideIncompatibleAppOverlayEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/RecentsDrawnEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/RecentsDrawnEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/ui/RecentsDrawnEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/RecentsDrawnEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/RecentsGrowingEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/RecentsGrowingEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/ui/RecentsGrowingEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/RecentsGrowingEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/ShowApplicationInfoEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/ShowApplicationInfoEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/ui/ShowApplicationInfoEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/ShowApplicationInfoEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/ShowIncompatibleAppOverlayEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/ShowIncompatibleAppOverlayEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/ui/ShowIncompatibleAppOverlayEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/ShowIncompatibleAppOverlayEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/StackViewScrolledEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/StackViewScrolledEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/ui/StackViewScrolledEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/StackViewScrolledEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskSnapshotChangedEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/TaskSnapshotChangedEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskSnapshotChangedEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/TaskSnapshotChangedEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskViewDismissedEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/TaskViewDismissedEvent.java
similarity index 94%
rename from packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskViewDismissedEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/TaskViewDismissedEvent.java
index 881a64a..9738124 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskViewDismissedEvent.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/TaskViewDismissedEvent.java
@@ -18,7 +18,7 @@
 
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.recents.utilities.AnimationProps;
+import com.android.systemui.recents.utilities.AnimationProps;
 import com.android.systemui.recents.views.TaskView;
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/UserInteractionEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/UserInteractionEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/ui/UserInteractionEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/UserInteractionEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndCancelledEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/dragndrop/DragEndCancelledEvent.java
similarity index 95%
rename from packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndCancelledEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/dragndrop/DragEndCancelledEvent.java
index 297afc5..c11936e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndCancelledEvent.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/dragndrop/DragEndCancelledEvent.java
@@ -18,7 +18,7 @@
 
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.recents.model.TaskStack;
+import com.android.systemui.recents.model.TaskStack;
 import com.android.systemui.recents.views.TaskView;
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/dragndrop/DragEndEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/dragndrop/DragEndEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartInitializeDropTargetsEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/dragndrop/DragStartInitializeDropTargetsEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartInitializeDropTargetsEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/dragndrop/DragStartInitializeDropTargetsEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/DismissFocusedTaskViewEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/focus/DismissFocusedTaskViewEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/DismissFocusedTaskViewEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/focus/DismissFocusedTaskViewEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusNextTaskViewEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/focus/FocusNextTaskViewEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusNextTaskViewEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/focus/FocusNextTaskViewEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusPreviousTaskViewEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/focus/FocusPreviousTaskViewEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusPreviousTaskViewEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/focus/FocusPreviousTaskViewEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/NavigateTaskViewEvent.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/focus/NavigateTaskViewEvent.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/NavigateTaskViewEvent.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/events/ui/focus/NavigateTaskViewEvent.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/misc/DozeTrigger.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/misc/DozeTrigger.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/FreePathInterpolator.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/misc/FreePathInterpolator.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/misc/FreePathInterpolator.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/misc/FreePathInterpolator.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/ReferenceCountedTrigger.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/misc/ReferenceCountedTrigger.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/misc/ReferenceCountedTrigger.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/misc/ReferenceCountedTrigger.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SysUiTaskStackChangeListener.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/misc/SysUiTaskStackChangeListener.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/misc/SysUiTaskStackChangeListener.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/misc/SysUiTaskStackChangeListener.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/misc/SystemServicesProxy.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 350fe78..f8b61cd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -34,7 +34,6 @@
 import android.app.IActivityTaskManager;
 import android.app.WindowConfiguration;
 import android.content.ComponentName;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.IPackageManager;
@@ -51,10 +50,8 @@
 import android.graphics.drawable.Drawable;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.provider.Settings;
 import android.service.dreams.DreamService;
 import android.service.dreams.IDreamManager;
 import android.util.Log;
@@ -71,7 +68,7 @@
 import com.android.internal.os.BackgroundThread;
 import com.android.systemui.Dependency;
 import com.android.systemui.UiOffloadThread;
-import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.LegacyRecentsImpl;
 import com.android.systemui.recents.RecentsImpl;
 import com.android.systemui.statusbar.policy.UserInfoController;
 
@@ -237,7 +234,7 @@
                     recentsStackInfo.topActivity : null;
             return (recentsStackVisibleNotOccluded && topActivity != null
                     && topActivity.getPackageName().equals(RecentsImpl.RECENTS_PACKAGE)
-                    && Recents.RECENTS_ACTIVITIES.contains(topActivity.getClassName()));
+                    && LegacyRecentsImpl.RECENTS_ACTIVITIES.contains(topActivity.getClassName()));
         } catch (RemoteException e) {
             e.printStackTrace();
         }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/BackgroundTaskLoader.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/model/BackgroundTaskLoader.java
similarity index 96%
rename from packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/BackgroundTaskLoader.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/model/BackgroundTaskLoader.java
index 114d69e..e85a7fb 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/BackgroundTaskLoader.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/model/BackgroundTaskLoader.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package com.android.systemui.shared.recents.model;
+package com.android.systemui.recents.model;
 
 import android.content.Context;
 import android.graphics.drawable.Drawable;
@@ -22,12 +22,14 @@
 import android.os.HandlerThread;
 import android.util.Log;
 
+import com.android.systemui.shared.recents.model.IconLoader;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.ThumbnailData;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 
 /**
  * Background task resource loader
  */
-@Deprecated
 class BackgroundTaskLoader implements Runnable {
     static String TAG = "BackgroundTaskLoader";
     static boolean DEBUG = false;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/FilteredTaskList.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/model/FilteredTaskList.java
similarity index 97%
rename from packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/FilteredTaskList.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/model/FilteredTaskList.java
index 7e0f8fe2..005be75 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/FilteredTaskList.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/model/FilteredTaskList.java
@@ -14,11 +14,12 @@
  * limitations under the License
  */
 
-package com.android.systemui.shared.recents.model;
+package com.android.systemui.recents.model;
 
 import android.util.ArrayMap;
 import android.util.SparseArray;
 
+import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.Task.TaskKey;
 
 import java.util.ArrayList;
@@ -27,7 +28,6 @@
 /**
  * A list of filtered tasks.
  */
-@Deprecated
 class FilteredTaskList {
 
     private final ArrayList<Task> mTasks = new ArrayList<>();
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/HighResThumbnailLoader.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/model/HighResThumbnailLoader.java
similarity index 97%
rename from packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/HighResThumbnailLoader.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/model/HighResThumbnailLoader.java
index f02bc5a..34bc334 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/HighResThumbnailLoader.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/model/HighResThumbnailLoader.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package com.android.systemui.shared.recents.model;
+package com.android.systemui.recents.model;
 
 import static android.os.Process.setThreadPriority;
 
@@ -25,7 +25,9 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.Task.TaskCallbacks;
+import com.android.systemui.shared.recents.model.ThumbnailData;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 
 import java.util.ArrayDeque;
@@ -34,7 +36,6 @@
 /**
  * Loader class that loads full-resolution thumbnails when appropriate.
  */
-@Deprecated
 public class HighResThumbnailLoader implements
         TaskCallbacks, BackgroundTaskLoader.OnIdleChangedListener {
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
similarity index 97%
rename from packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 8b3ae42..7c6a76f 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.shared.recents.model;
+package com.android.systemui.recents.model;
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 
@@ -29,7 +29,9 @@
 import android.graphics.drawable.Drawable;
 import android.util.SparseBooleanArray;
 
+import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.Task.TaskKey;
+import com.android.systemui.shared.recents.model.ThumbnailData;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 
 import java.util.ArrayList;
@@ -45,7 +47,6 @@
  *   3) executePlan() will actually load and fill in the icons and thumbnails according to the load
  *      options specified, such that we can transition into the Recents activity seamlessly
  */
-@Deprecated
 public class RecentsTaskLoadPlan {
 
     /** The set of conditions to preload tasks. */
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/model/RecentsTaskLoader.java
similarity index 97%
rename from packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index b50aa76..012913a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.shared.recents.model;
+package com.android.systemui.recents.model;
 
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
@@ -29,10 +29,14 @@
 import android.util.LruCache;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan.Options;
-import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan.PreloadOptions;
+import com.android.systemui.recents.model.RecentsTaskLoadPlan.Options;
+import com.android.systemui.recents.model.RecentsTaskLoadPlan.PreloadOptions;
+import com.android.systemui.shared.recents.model.IconLoader;
+import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.Task.TaskKey;
+import com.android.systemui.shared.recents.model.TaskKeyLruCache;
 import com.android.systemui.shared.recents.model.TaskKeyLruCache.EvictionCallback;
+import com.android.systemui.shared.recents.model.ThumbnailData;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 
 import java.io.PrintWriter;
@@ -42,7 +46,6 @@
 /**
  * Recents task loader
  */
-@Deprecated
 public class RecentsTaskLoader {
     private static final String TAG = "RecentsTaskLoader";
     private static final boolean DEBUG = false;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/model/TaskFilter.java
similarity index 90%
rename from packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/model/TaskFilter.java
index d378189..9b734ec 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/model/TaskFilter.java
@@ -14,14 +14,14 @@
  * limitations under the License
  */
 
-package com.android.systemui.shared.recents.model;
+package com.android.systemui.recents.model;
 
 import android.util.SparseArray;
+import com.android.systemui.shared.recents.model.Task;
 
 /**
  * An interface for a task filter to query whether a particular task should show in a stack.
  */
-@Deprecated
 public interface TaskFilter {
     /** Returns whether the filter accepts the specified task */
     boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index);
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyStrongCache.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/model/TaskKeyStrongCache.java
similarity index 88%
rename from packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyStrongCache.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/model/TaskKeyStrongCache.java
index 4408ece..27f2098 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyStrongCache.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/model/TaskKeyStrongCache.java
@@ -14,12 +14,14 @@
  * limitations under the License
  */
 
-package com.android.systemui.shared.recents.model;
+package com.android.systemui.recents.model;
 
 import android.util.ArrayMap;
 
 import com.android.systemui.shared.recents.model.Task.TaskKey;
 
+import com.android.systemui.shared.recents.model.TaskKeyCache;
+import com.android.systemui.shared.recents.model.TaskKeyLruCache;
 import java.io.PrintWriter;
 
 /**
@@ -31,7 +33,7 @@
 
     private final ArrayMap<Integer, V> mCache = new ArrayMap<>();
 
-    final void copyEntries(TaskKeyStrongCache<V> other) {
+    public final void copyEntries(TaskKeyStrongCache<V> other) {
         for (int i = other.mKeys.size() - 1; i >= 0; i--) {
             TaskKey key = other.mKeys.valueAt(i);
             put(key, other.mCache.get(key.id));
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskResourceLoadQueue.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/model/TaskResourceLoadQueue.java
similarity index 93%
rename from packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskResourceLoadQueue.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/model/TaskResourceLoadQueue.java
index 6b9b9f5..fe89ad5 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskResourceLoadQueue.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/model/TaskResourceLoadQueue.java
@@ -14,14 +14,14 @@
  * limitations under the License
  */
 
-package com.android.systemui.shared.recents.model;
+package com.android.systemui.recents.model;
 
+import com.android.systemui.shared.recents.model.Task;
 import java.util.concurrent.ConcurrentLinkedQueue;
 
 /**
  * A Task load queue
  */
-@Deprecated
 class TaskResourceLoadQueue {
 
     private final ConcurrentLinkedQueue<Task> mQueue = new ConcurrentLinkedQueue<>();
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskStack.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/model/TaskStack.java
similarity index 98%
rename from packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskStack.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/model/TaskStack.java
index fd92bca..01e6ba3 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskStack.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/model/TaskStack.java
@@ -14,15 +14,16 @@
  * limitations under the License.
  */
 
-package com.android.systemui.shared.recents.model;
+package com.android.systemui.recents.model;
 
 import android.content.ComponentName;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.SparseArray;
 
+import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.Task.TaskKey;
-import com.android.systemui.shared.recents.utilities.AnimationProps;
+import com.android.systemui.recents.utilities.AnimationProps;
 import com.android.systemui.shared.system.PackageManagerWrapper;
 
 import java.io.PrintWriter;
@@ -33,7 +34,6 @@
 /**
  * The task stack contains a list of multiple tasks.
  */
-@Deprecated
 public class TaskStack {
 
     private static final String TAG = "TaskStack";
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/AnimationProps.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/utilities/AnimationProps.java
similarity index 98%
rename from packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/AnimationProps.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/utilities/AnimationProps.java
index 26f6b59..5463998 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/AnimationProps.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/utilities/AnimationProps.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.shared.recents.utilities;
+package com.android.systemui.recents.utilities;
 
 import android.animation.Animator;
 import android.animation.AnimatorSet;
@@ -34,7 +34,6 @@
  * The generic set of animation properties to animate a {@link View}. The animation can have
  * different interpolators, start delays and durations for each of the different properties.
  */
-@Deprecated
 public class AnimationProps {
 
     private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
diff --git a/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/utilities/Utilities.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/utilities/Utilities.java
new file mode 100644
index 0000000..ff58eba
--- /dev/null
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/utilities/Utilities.java
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2014 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.systemui.recents.utilities;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.RectEvaluator;
+import android.annotation.FloatRange;
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Trace;
+import android.util.ArraySet;
+import android.util.IntProperty;
+import android.util.Property;
+import android.util.TypedValue;
+import android.view.Surface;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.view.ViewRootImpl;
+import android.view.ViewStub;
+
+import com.android.systemui.shared.recents.utilities.RectFEvaluator;
+import java.util.ArrayList;
+import java.util.Collections;
+
+/* Common code */
+public class Utilities {
+
+    public static final Property<Drawable, Integer> DRAWABLE_ALPHA =
+            new IntProperty<Drawable>("drawableAlpha") {
+                @Override
+                public void setValue(Drawable object, int alpha) {
+                    object.setAlpha(alpha);
+                }
+
+                @Override
+                public Integer get(Drawable object) {
+                    return object.getAlpha();
+                }
+            };
+
+    public static final Property<Drawable, Rect> DRAWABLE_RECT =
+            new Property<Drawable, Rect>(Rect.class, "drawableBounds") {
+                @Override
+                public void set(Drawable object, Rect bounds) {
+                    object.setBounds(bounds);
+                }
+
+                @Override
+                public Rect get(Drawable object) {
+                    return object.getBounds();
+                }
+            };
+
+    public static final RectFEvaluator RECTF_EVALUATOR = new RectFEvaluator();
+    public static final RectEvaluator RECT_EVALUATOR = new RectEvaluator(new Rect());
+
+    /**
+     * @return the first parent walking up the view hierarchy that has the given class type.
+     *
+     * @param parentClass must be a class derived from {@link View}
+     */
+    public static <T extends View> T findParent(View v, Class<T> parentClass) {
+        ViewParent parent = v.getParent();
+        while (parent != null) {
+            if (parentClass.isAssignableFrom(parent.getClass())) {
+                return (T) parent;
+            }
+            parent = parent.getParent();
+        }
+        return null;
+    }
+
+    /**
+     * Initializes the {@param setOut} with the given object.
+     */
+    public static <T> ArraySet<T> objectToSet(T obj, ArraySet<T> setOut) {
+        setOut.clear();
+        if (obj != null) {
+            setOut.add(obj);
+        }
+        return setOut;
+    }
+
+    /**
+     * Replaces the contents of {@param setOut} with the contents of the {@param array}.
+     */
+    public static <T> ArraySet<T> arrayToSet(T[] array, ArraySet<T> setOut) {
+        setOut.clear();
+        if (array != null) {
+            Collections.addAll(setOut, array);
+        }
+        return setOut;
+    }
+
+    /**
+     * @return the clamped {@param value} between the provided {@param min} and {@param max}.
+     */
+    public static int clamp(int value, int min, int max) {
+        return Math.max(min, Math.min(max, value));
+    }
+
+    /**
+     * @return the clamped {@param value} between 0 and 1.
+     */
+    public static float clamp01(float value) {
+        return Math.max(0f, Math.min(1f, value));
+    }
+
+    /**
+     * Scales the {@param value} to be proportionally between the {@param min} and
+     * {@param max} values.
+     *
+     * @param value must be between 0 and 1
+     */
+    public static float mapRange(@FloatRange(from=0.0,to=1.0) float value, float min, float max) {
+        return min + (value * (max - min));
+    }
+
+    /**
+     * Scales the {@param value} proportionally from {@param min} and {@param max} to 0 and 1.
+     *
+     * @param value must be between {@param min} and {@param max}
+     */
+    public static float unmapRange(float value, float min, float max) {
+        return (value - min) / (max - min);
+    }
+
+    /** Scales a rect about its centroid */
+    public static void scaleRectAboutCenter(RectF r, float scale) {
+        if (scale != 1.0f) {
+            float cx = r.centerX();
+            float cy = r.centerY();
+            r.offset(-cx, -cy);
+            r.left *= scale;
+            r.top *= scale;
+            r.right *= scale;
+            r.bottom *= scale;
+            r.offset(cx, cy);
+        }
+    }
+
+    /** Returns the base color overlaid with another overlay color with a specified alpha. */
+    public static int getColorWithOverlay(int baseColor, int overlayColor, float overlayAlpha) {
+        return Color.rgb(
+            (int) (overlayAlpha * Color.red(baseColor) +
+                    (1f - overlayAlpha) * Color.red(overlayColor)),
+            (int) (overlayAlpha * Color.green(baseColor) +
+                    (1f - overlayAlpha) * Color.green(overlayColor)),
+            (int) (overlayAlpha * Color.blue(baseColor) +
+                    (1f - overlayAlpha) * Color.blue(overlayColor)));
+    }
+
+    /**
+     * Cancels an animation ensuring that if it has listeners, onCancel and onEnd
+     * are not called.
+     */
+    public static void cancelAnimationWithoutCallbacks(Animator animator) {
+        if (animator != null && animator.isStarted()) {
+            removeAnimationListenersRecursive(animator);
+            animator.cancel();
+        }
+    }
+
+    /**
+     * Recursively removes all the listeners of all children of this animator
+     */
+    public static void removeAnimationListenersRecursive(Animator animator) {
+        if (animator instanceof AnimatorSet) {
+            ArrayList<Animator> animators = ((AnimatorSet) animator).getChildAnimations();
+            for (int i = animators.size() - 1; i >= 0; i--) {
+                removeAnimationListenersRecursive(animators.get(i));
+            }
+        }
+        animator.removeAllListeners();
+    }
+
+    /**
+     * Sets the given {@link View}'s frame from its current translation.
+     */
+    public static void setViewFrameFromTranslation(View v) {
+        RectF taskViewRect = new RectF(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
+        taskViewRect.offset(v.getTranslationX(), v.getTranslationY());
+        v.setTranslationX(0);
+        v.setTranslationY(0);
+        v.setLeftTopRightBottom((int) taskViewRect.left, (int) taskViewRect.top,
+                (int) taskViewRect.right, (int) taskViewRect.bottom);
+    }
+
+    /**
+     * Returns a view stub for the given view id.
+     */
+    public static ViewStub findViewStubById(View v, int stubId) {
+        return (ViewStub) v.findViewById(stubId);
+    }
+
+    /**
+     * Returns a view stub for the given view id.
+     */
+    public static ViewStub findViewStubById(Activity a, int stubId) {
+        return (ViewStub) a.findViewById(stubId);
+    }
+
+    /**
+     * Used for debugging, converts DP to PX.
+     */
+    public static float dpToPx(Resources res, float dp) {
+        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, res.getDisplayMetrics());
+    }
+
+    /**
+     * Adds a trace event for debugging.
+     */
+    public static void addTraceEvent(String event) {
+        Trace.traceBegin(Trace.TRACE_TAG_VIEW, event);
+        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+    }
+
+    /**
+     * Returns whether this view, or one of its descendants have accessibility focus.
+     */
+    public static boolean isDescendentAccessibilityFocused(View v) {
+        if (v.isAccessibilityFocused()) {
+            return true;
+        }
+
+        if (v instanceof ViewGroup) {
+            ViewGroup vg = (ViewGroup) v;
+            int childCount = vg.getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                if (isDescendentAccessibilityFocused(vg.getChildAt(i))) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns the application configuration, which is independent of the activity's current
+     * configuration in multiwindow.
+     */
+    public static Configuration getAppConfiguration(Context context) {
+        return context.getApplicationContext().getResources().getConfiguration();
+    }
+
+    /**
+     * @return The next frame name for the specified surface or -1 if the surface is no longer
+     *         valid.
+     */
+    public static long getNextFrameNumber(Surface s) {
+        return s != null && s.isValid()
+                ? s.getNextFrameNumber()
+                : -1;
+
+    }
+
+    /**
+     * @return The surface for the specified view.
+     */
+    public static @Nullable Surface getSurface(View v) {
+        ViewRootImpl viewRoot = v.getViewRootImpl();
+        if (viewRoot == null) {
+            return null;
+        }
+        return viewRoot.mSurface;
+    }
+
+    /**
+     * Returns a lightweight dump of a rect.
+     */
+    public static String dumpRect(Rect r) {
+        if (r == null) {
+            return "N:0,0-0,0";
+        }
+        return r.left + "," + r.top + "-" + r.right + "," + r.bottom;
+    }
+
+    /**
+     * Posts a runnable on a handler at the front of the queue ignoring any sync barriers.
+     */
+    public static void postAtFrontOfQueueAsynchronously(Handler h, Runnable r) {
+        Message msg = h.obtainMessage().setCallback(r);
+        h.sendMessageAtFrontOfQueue(msg);
+    }
+
+    /** Calculates the constrast between two colors, using the algorithm provided by the WCAG v2. */
+    public static float computeContrastBetweenColors(int bg, int fg) {
+        float bgR = Color.red(bg) / 255f;
+        float bgG = Color.green(bg) / 255f;
+        float bgB = Color.blue(bg) / 255f;
+        bgR = (bgR < 0.03928f) ? bgR / 12.92f : (float) Math.pow((bgR + 0.055f) / 1.055f, 2.4f);
+        bgG = (bgG < 0.03928f) ? bgG / 12.92f : (float) Math.pow((bgG + 0.055f) / 1.055f, 2.4f);
+        bgB = (bgB < 0.03928f) ? bgB / 12.92f : (float) Math.pow((bgB + 0.055f) / 1.055f, 2.4f);
+        float bgL = 0.2126f * bgR + 0.7152f * bgG + 0.0722f * bgB;
+
+        float fgR = Color.red(fg) / 255f;
+        float fgG = Color.green(fg) / 255f;
+        float fgB = Color.blue(fg) / 255f;
+        fgR = (fgR < 0.03928f) ? fgR / 12.92f : (float) Math.pow((fgR + 0.055f) / 1.055f, 2.4f);
+        fgG = (fgG < 0.03928f) ? fgG / 12.92f : (float) Math.pow((fgG + 0.055f) / 1.055f, 2.4f);
+        fgB = (fgB < 0.03928f) ? fgB / 12.92f : (float) Math.pow((fgB + 0.055f) / 1.055f, 2.4f);
+        float fgL = 0.2126f * fgR + 0.7152f * fgG + 0.0722f * fgB;
+
+        return Math.abs((fgL + 0.05f) / (bgL + 0.05f));
+    }
+
+    /**
+     * @return the clamped {@param value} between the provided {@param min} and {@param max}.
+     */
+    public static float clamp(float value, float min, float max) {
+        return Math.max(min, Math.min(max, value));
+    }
+
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AnimateableViewBounds.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/AnimateableViewBounds.java
similarity index 95%
rename from packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AnimateableViewBounds.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/AnimateableViewBounds.java
index 30bea32..e188506 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AnimateableViewBounds.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/AnimateableViewBounds.java
@@ -14,20 +14,18 @@
  * limitations under the License.
  */
 
-package com.android.systemui.shared.recents.view;
+package com.android.systemui.recents.views;
 
 import android.graphics.Outline;
 import android.graphics.Rect;
 import android.view.View;
-import android.view.ViewDebug;
 import android.view.ViewOutlineProvider;
 
-import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.recents.utilities.Utilities;
 
 /**
  * An outline provider that has a clip and outline that can be animated.
  */
-@Deprecated
 public class AnimateableViewBounds extends ViewOutlineProvider {
 
     private static final float MIN_ALPHA = 0.1f;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/DockState.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/DockState.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/recents/views/DockState.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/DockState.java
index a246141..d9c921c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/DockState.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/DockState.java
@@ -45,8 +45,8 @@
 import com.android.internal.policy.DockedDividerUtils;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.recents.Recents;
-import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.recents.LegacyRecentsImpl;
+import com.android.systemui.recents.utilities.Utilities;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -132,7 +132,7 @@
         private ViewState(int areaAlpha, int hintAlpha, @TextOrientation int hintOrientation,
                 int hintTextResId) {
             dockAreaAlpha = areaAlpha;
-            dockAreaOverlay = new ColorDrawable(Recents.getConfiguration().isGridEnabled
+            dockAreaOverlay = new ColorDrawable(LegacyRecentsImpl.getConfiguration().isGridEnabled
                     ? DOCK_AREA_GRID_BG_COLOR : DOCK_AREA_BG_COLOR);
             dockAreaOverlay.setAlpha(0);
             hintTextAlpha = hintAlpha;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/DropTarget.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/DropTarget.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/views/DropTarget.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/DropTarget.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/FakeShadowDrawable.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/FakeShadowDrawable.java
index 79a774f..86b4297 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/FakeShadowDrawable.java
@@ -30,7 +30,7 @@
 import android.util.Log;
 
 import com.android.systemui.R;
-import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.LegacyRecentsImpl;
 import com.android.systemui.recents.RecentsConfiguration;
 
 /**
@@ -91,7 +91,7 @@
         mCornerShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
         mCornerShadowPaint.setStyle(Paint.Style.FILL);
         mCornerShadowPaint.setDither(true);
-        mCornerRadius = Recents.getConfiguration().isGridEnabled ?
+        mCornerRadius = LegacyRecentsImpl.getConfiguration().isGridEnabled ?
                 resources.getDimensionPixelSize(
                     R.dimen.recents_grid_task_view_rounded_corners_radius) :
                 resources.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FixedSizeFrameLayout.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/FixedSizeFrameLayout.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/views/FixedSizeFrameLayout.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/FixedSizeFrameLayout.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FixedSizeImageView.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/FixedSizeImageView.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/views/FixedSizeImageView.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/FixedSizeImageView.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsEntrancePathInterpolator.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsEntrancePathInterpolator.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/views/RecentsEntrancePathInterpolator.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsEntrancePathInterpolator.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionComposer.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsTransitionComposer.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionComposer.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsTransitionComposer.java
index 1c47430..ce66318 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionComposer.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsTransitionComposer.java
@@ -24,11 +24,10 @@
 
 import android.content.Context;
 import android.graphics.Bitmap;
-import android.graphics.GraphicBuffer;
 import android.graphics.Rect;
 import android.util.Log;
 
-import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.LegacyRecentsImpl;
 import com.android.systemui.recents.RecentsDebugFlags;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat;
@@ -71,7 +70,7 @@
         // height (stackView height) and when transitioning to fullscreen app, the code below would
         // force the task thumbnail to full stackView height immediately causing the transition
         // jarring.
-        if (!Recents.getConfiguration().isLowRamDevice && taskView.getTask() !=
+        if (!LegacyRecentsImpl.getConfiguration().isLowRamDevice && taskView.getTask() !=
                 stackView.getStack().getFrontMostTask()) {
             taskRect.bottom = taskRect.top + stackView.getMeasuredHeight();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsView.java
similarity index 95%
rename from packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsView.java
index 5c925fd..0d758df 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsView.java
@@ -56,7 +56,7 @@
 import com.android.settingslib.Utils;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.LegacyRecentsImpl;
 import com.android.systemui.recents.RecentsActivity;
 import com.android.systemui.recents.RecentsActivityLaunchState;
 import com.android.systemui.recents.RecentsConfiguration;
@@ -88,8 +88,8 @@
 import com.android.systemui.recents.misc.ReferenceCountedTrigger;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.recents.model.TaskStack;
-import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.utilities.Utilities;
 import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat;
 import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
 import com.android.systemui.shared.recents.view.RecentsTransition;
@@ -166,7 +166,7 @@
         super(context, attrs, defStyleAttr, defStyleRes);
         setWillNotDraw(false);
 
-        SystemServicesProxy ssp = Recents.getSystemServices();
+        SystemServicesProxy ssp = LegacyRecentsImpl.getSystemServices();
         mHandler = new Handler();
         mTransitionHelper = new RecentsTransitionComposer(getContext());
         mDividerSize = ssp.getDockedDividerSize(context);
@@ -182,7 +182,7 @@
         if (mStackActionButton != null) {
             removeView(mStackActionButton);
         }
-        mStackActionButton = (TextView) inflater.inflate(Recents.getConfiguration()
+        mStackActionButton = (TextView) inflater.inflate(LegacyRecentsImpl.getConfiguration()
                         .isLowRamDevice
                     ? R.layout.recents_low_ram_stack_action_button
                     : R.layout.recents_stack_action_button,
@@ -231,7 +231,7 @@
      * Called from RecentsActivity when it is relaunched.
      */
     public void onReload(TaskStack stack, boolean isResumingFromVisible) {
-        final RecentsConfiguration config = Recents.getConfiguration();
+        final RecentsConfiguration config = LegacyRecentsImpl.getConfiguration();
         final RecentsActivityLaunchState launchState = config.getLaunchState();
         final boolean isTaskStackEmpty = stack.getTaskCount() == 0;
 
@@ -350,7 +350,7 @@
 
     /** Launches the task that recents was launched from if possible */
     public boolean launchPreviousTask() {
-        if (Recents.getConfiguration().getLaunchState().launchedFromPipApp) {
+        if (LegacyRecentsImpl.getConfiguration().getLaunchState().launchedFromPipApp) {
             // If the app auto-entered PiP on the way to Recents, then just re-expand it
             EventBus.getDefault().send(new ExpandPipEvent());
             return true;
@@ -481,14 +481,14 @@
             mAwaitingFirstLayout = false;
             // If launched via dragging from the nav bar, then we should translate the whole view
             // down offscreen
-            RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
+            RecentsActivityLaunchState launchState = LegacyRecentsImpl.getConfiguration().getLaunchState();
             if (launchState.launchedViaDragGesture) {
                 setTranslationY(getMeasuredHeight());
             } else {
                 setTranslationY(0f);
             }
 
-            if (Recents.getConfiguration().isLowRamDevice
+            if (LegacyRecentsImpl.getConfiguration().isLowRamDevice
                     && mEmptyView.getVisibility() == View.VISIBLE) {
                 animateEmptyView(true /* show */, null /* postAnimationTrigger */);
             }
@@ -540,7 +540,7 @@
     public final void onBusEvent(LaunchTaskEvent event) {
         launchTaskFromRecents(getStack(), event.task, mTaskStackView, event.taskView,
                 event.screenPinningRequested, event.targetWindowingMode, event.targetActivityType);
-        if (Recents.getConfiguration().isLowRamDevice) {
+        if (LegacyRecentsImpl.getConfiguration().isLowRamDevice) {
             EventBus.getDefault().send(new HideStackActionButtonEvent(false /* translate */));
         }
     }
@@ -551,13 +551,13 @@
         EventBus.getDefault().send(new HideStackActionButtonEvent());
         animateBackgroundScrim(0f, taskViewExitToHomeDuration);
 
-        if (Recents.getConfiguration().isLowRamDevice) {
+        if (LegacyRecentsImpl.getConfiguration().isLowRamDevice) {
             animateEmptyView(false /* show */, event.getAnimationTrigger());
         }
     }
 
     public final void onBusEvent(DragStartEvent event) {
-        updateVisibleDockRegions(Recents.getConfiguration().getDockStatesForCurrentOrientation(),
+        updateVisibleDockRegions(LegacyRecentsImpl.getConfiguration().getDockStatesForCurrentOrientation(),
                 true /* isDefaultDockState */, DockState.NONE.viewState.dockAreaAlpha,
                 DockState.NONE.viewState.hintTextAlpha,
                 true /* animateAlpha */, false /* animateBounds */);
@@ -575,7 +575,7 @@
     public final void onBusEvent(DragDropTargetChangedEvent event) {
         if (event.dropTarget == null || !(event.dropTarget instanceof DockState)) {
             updateVisibleDockRegions(
-                    Recents.getConfiguration().getDockStatesForCurrentOrientation(),
+                    LegacyRecentsImpl.getConfiguration().getDockStatesForCurrentOrientation(),
                     true /* isDefaultDockState */, DockState.NONE.viewState.dockAreaAlpha,
                     DockState.NONE.viewState.hintTextAlpha,
                     true /* animateAlpha */, true /* animateBounds */);
@@ -695,7 +695,7 @@
     }
 
     public final void onBusEvent(EnterRecentsWindowAnimationCompletedEvent event) {
-        RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
+        RecentsActivityLaunchState launchState = LegacyRecentsImpl.getConfiguration().getLaunchState();
         if (!launchState.launchedViaDockGesture && !launchState.launchedFromApp
                 && getStack().getTaskCount() > 0) {
             animateBackgroundScrim(getOpaqueScrimAlpha(),
@@ -708,7 +708,7 @@
     }
 
     public final void onBusEvent(DismissAllTaskViewsEvent event) {
-        SystemServicesProxy ssp = Recents.getSystemServices();
+        SystemServicesProxy ssp = LegacyRecentsImpl.getSystemServices();
         if (!ssp.hasDockedTask()) {
             // Animate the background away only if we are dismissing Recents to home
             animateBackgroundScrim(0f, DEFAULT_UPDATE_SCRIM_DURATION);
@@ -741,7 +741,7 @@
             mStackActionButton.setAlpha(0f);
             if (translate) {
                 mStackActionButton.setTranslationY(mStackActionButton.getMeasuredHeight() *
-                        (Recents.getConfiguration().isLowRamDevice ? 1 : -0.25f));
+                        (LegacyRecentsImpl.getConfiguration().isLowRamDevice ? 1 : -0.25f));
             } else {
                 mStackActionButton.setTranslationY(0f);
             }
@@ -780,7 +780,7 @@
         if (mStackActionButton.getVisibility() == View.VISIBLE) {
             if (translate) {
                 mStackActionButton.animate().translationY(mStackActionButton.getMeasuredHeight()
-                        * (Recents.getConfiguration().isLowRamDevice ? 1 : -0.25f));
+                        * (LegacyRecentsImpl.getConfiguration().isLowRamDevice ? 1 : -0.25f));
             }
             mStackActionButton.animate()
                     .alpha(0f)
@@ -896,8 +896,8 @@
         Rect actionButtonRect = new Rect(
                 mTaskStackView.mLayoutAlgorithm.getStackActionButtonRect());
         int left, top;
-        if (Recents.getConfiguration().isLowRamDevice) {
-            Rect windowRect = Recents.getSystemServices().getWindowRect();
+        if (LegacyRecentsImpl.getConfiguration().isLowRamDevice) {
+            Rect windowRect = LegacyRecentsImpl.getSystemServices().getWindowRect();
             int spaceLeft = windowRect.width() - mSystemInsets.left - mSystemInsets.right;
             left = (spaceLeft - mStackActionButton.getMeasuredWidth()) / 2 + mSystemInsets.left;
             top = windowRect.height() - (mStackActionButton.getMeasuredHeight()
@@ -932,7 +932,7 @@
 
             // Fetch window rect here already in order not to be blocked on lock contention in WM
             // when the future calls it.
-            final Rect windowRect = Recents.getSystemServices().getWindowRect();
+            final Rect windowRect = LegacyRecentsImpl.getSystemServices().getWindowRect();
             transitionFuture = new AppTransitionAnimationSpecsFuture(stackView.getHandler()) {
                 @Override
                 public List<AppTransitionAnimationSpecCompat> composeSpecs() {
@@ -964,7 +964,7 @@
                         }, 350);
                     }
 
-                    if (!Recents.getConfiguration().isLowRamDevice) {
+                    if (!LegacyRecentsImpl.getConfiguration().isLowRamDevice) {
                         // Reset the state where we are waiting for the transition to start
                         EventBus.getDefault().send(new SetWaitingForTransitionStartEvent(false));
                     }
@@ -989,7 +989,7 @@
                     EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
                     stackView.cancelAllTaskViewAnimations();
 
-                    if (!Recents.getConfiguration().isLowRamDevice) {
+                    if (!LegacyRecentsImpl.getConfiguration().isLowRamDevice) {
                         // Reset the state where we are waiting for the transition to start
                         EventBus.getDefault().send(new SetWaitingForTransitionStartEvent(false));
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
index 53a91e5..1a827d5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.recents.views;
 
-import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -28,7 +27,7 @@
 import android.view.ViewDebug;
 
 import com.android.internal.policy.DividerSnapAlgorithm;
-import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.LegacyRecentsImpl;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
 import com.android.systemui.recents.events.activity.HideRecentsEvent;
@@ -115,7 +114,7 @@
     /**** Events ****/
 
     public final void onBusEvent(DragStartEvent event) {
-        SystemServicesProxy ssp = Recents.getSystemServices();
+        SystemServicesProxy ssp = LegacyRecentsImpl.getSystemServices();
         mRv.getParent().requestDisallowInterceptTouchEvent(true);
         mDragRequested = true;
         // We defer starting the actual drag handling until the user moves past the drag slop
@@ -140,13 +139,13 @@
         mVisibleDockStates.clear();
         if (ActivityTaskManager.supportsMultiWindow(mRv.getContext()) && !ssp.hasDockedTask()
                 && mDividerSnapAlgorithm.isSplitScreenFeasible()) {
-            Recents.logDockAttempt(mRv.getContext(), event.task.getTopComponent(),
+            LegacyRecentsImpl.logDockAttempt(mRv.getContext(), event.task.getTopComponent(),
                     event.task.resizeMode);
             if (!event.task.isDockable) {
                 EventBus.getDefault().send(new ShowIncompatibleAppOverlayEvent());
             } else {
                 // Add the dock state drop targets (these take priority)
-                DockState[] dockStates = Recents.getConfiguration()
+                DockState[] dockStates = LegacyRecentsImpl.getConfiguration()
                         .getDockStatesForCurrentOrientation();
                 for (DockState dockState : dockStates) {
                     registerDropTargetForCurrentDrag(dockState);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/SystemBarScrimViews.java
similarity index 94%
rename from packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/SystemBarScrimViews.java
index 170e39d..22c12b4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/SystemBarScrimViews.java
@@ -21,7 +21,7 @@
 
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.LegacyRecentsImpl;
 import com.android.systemui.recents.RecentsActivity;
 import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
 import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
@@ -30,7 +30,7 @@
 import com.android.systemui.recents.events.activity.MultiWindowStateChangedEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragEndCancelledEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
-import com.android.systemui.shared.recents.utilities.AnimationProps;
+import com.android.systemui.recents.utilities.AnimationProps;
 
 /** Manages the scrims for the various system bars. */
 public class SystemBarScrimViews {
@@ -53,8 +53,8 @@
         mNavBarScrimView.forceHasOverlappingRendering(false);
         mNavBarScrimEnterDuration = activity.getResources().getInteger(
                 R.integer.recents_nav_bar_scrim_enter_duration);
-        mHasNavBarScrim = Recents.getSystemServices().hasTransposedNavigationBar();
-        mHasDockedTasks = Recents.getSystemServices().hasDockedTask();
+        mHasNavBarScrim = LegacyRecentsImpl.getSystemServices().hasTransposedNavigationBar();
+        mHasDockedTasks = LegacyRecentsImpl.getSystemServices().hasDockedTask();
     }
 
     /**
@@ -147,7 +147,7 @@
 
     public final void onBusEvent(ConfigurationChangedEvent event) {
         if (event.fromDeviceOrientationChange) {
-            mHasNavBarScrim = Recents.getSystemServices().hasTransposedNavigationBar();
+            mHasNavBarScrim = LegacyRecentsImpl.getSystemServices().hasTransposedNavigationBar();
         }
         animateScrimToCurrentNavBarState(event.hasStackTasks);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
index 67d0978..5574934 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
@@ -28,7 +28,7 @@
 
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.LegacyRecentsImpl;
 import com.android.systemui.recents.RecentsActivityLaunchState;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.RecentsDebugFlags;
@@ -36,9 +36,9 @@
 import com.android.systemui.recents.events.component.SetWaitingForTransitionStartEvent;
 import com.android.systemui.recents.misc.ReferenceCountedTrigger;
 import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.recents.model.TaskStack;
+import com.android.systemui.recents.model.TaskStack;
 import com.android.systemui.recents.views.lowram.TaskStackLowRamLayoutAlgorithm;
-import com.android.systemui.shared.recents.utilities.AnimationProps;
+import com.android.systemui.recents.utilities.AnimationProps;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -115,7 +115,7 @@
 
     public TaskStackAnimationHelper(Context context, TaskStackView stackView) {
         mStackView = stackView;
-        mEnterAndExitFromHomeTranslationOffset = Recents.getConfiguration().isGridEnabled
+        mEnterAndExitFromHomeTranslationOffset = LegacyRecentsImpl.getConfiguration().isGridEnabled
                 ? 0 : DOUBLE_FRAME_OFFSET_MS;
     }
 
@@ -124,7 +124,7 @@
      * the in-app enter animations start (after the window-transition completes).
      */
     public void prepareForEnterAnimation() {
-        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsConfiguration config = LegacyRecentsImpl.getConfiguration();
         RecentsActivityLaunchState launchState = config.getLaunchState();
         Resources res = mStackView.getResources();
         Resources appResources = mStackView.getContext().getApplicationContext().getResources();
@@ -148,7 +148,7 @@
                 == Configuration.ORIENTATION_LANDSCAPE;
 
         float top = 0;
-        final boolean isLowRamDevice = Recents.getConfiguration().isLowRamDevice;
+        final boolean isLowRamDevice = LegacyRecentsImpl.getConfiguration().isLowRamDevice;
         if (isLowRamDevice && launchState.launchedFromApp && !launchState.launchedViaDockGesture) {
             stackLayout.getStackTransform(launchTargetTask, stackScroller.getStackScroll(),
                     mTmpTransform, null /* frontTransform */);
@@ -212,7 +212,7 @@
      * depending on how Recents was triggered.
      */
     public void startEnterAnimation(final ReferenceCountedTrigger postAnimationTrigger) {
-        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsConfiguration config = LegacyRecentsImpl.getConfiguration();
         RecentsActivityLaunchState launchState = config.getLaunchState();
         Resources res = mStackView.getResources();
         Resources appRes = mStackView.getContext().getApplicationContext().getResources();
@@ -227,7 +227,7 @@
             return;
         }
 
-        final boolean isLowRamDevice = Recents.getConfiguration().isLowRamDevice;
+        final boolean isLowRamDevice = LegacyRecentsImpl.getConfiguration().isLowRamDevice;
         int taskViewEnterFromAppDuration = res.getInteger(
                 R.integer.recents_task_enter_from_app_duration);
         int taskViewEnterFromAffiliatedAppDuration = res.getInteger(
@@ -342,7 +342,7 @@
                 taskAnimation = new AnimationProps()
                         .setDuration(AnimationProps.BOUNDS, EXIT_TO_HOME_TRANSLATION_DURATION)
                         .setListener(postAnimationTrigger.decrementOnAnimationEnd());
-                if (Recents.getConfiguration().isLowRamDevice) {
+                if (LegacyRecentsImpl.getConfiguration().isLowRamDevice) {
                     taskAnimation.setInterpolator(AnimationProps.BOUNDS,
                             Interpolators.FAST_OUT_SLOW_IN);
                 } else {
@@ -356,7 +356,7 @@
             }
 
             mTmpTransform.fillIn(tv);
-            if (Recents.getConfiguration().isLowRamDevice) {
+            if (LegacyRecentsImpl.getConfiguration().isLowRamDevice) {
                 taskAnimation.setInterpolator(AnimationProps.ALPHA,
                                 EXIT_TO_HOME_TRANSLATION_INTERPOLATOR)
                         .setDuration(AnimationProps.ALPHA, EXIT_TO_HOME_TRANSLATION_DURATION);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
similarity index 95%
rename from packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index d9f79bb..58a3f12 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -29,15 +29,15 @@
 import android.view.ViewDebug;
 
 import com.android.systemui.R;
-import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.LegacyRecentsImpl;
 import com.android.systemui.recents.RecentsActivityLaunchState;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.RecentsDebugFlags;
 import com.android.systemui.recents.misc.FreePathInterpolator;
 import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.recents.utilities.Utilities;
 import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.recents.model.TaskStack;
+import com.android.systemui.recents.model.TaskStack;
 import com.android.systemui.recents.views.lowram.TaskStackLowRamLayoutAlgorithm;
 import com.android.systemui.recents.views.grid.TaskGridLayoutAlgorithm;
 
@@ -149,7 +149,7 @@
      * @return True if we should use the grid layout.
      */
     boolean useGridLayout() {
-        return Recents.getConfiguration().isGridEnabled;
+        return LegacyRecentsImpl.getConfiguration().isGridEnabled;
     }
 
     // A report of the visibility state of the stack
@@ -432,7 +432,7 @@
      */
     public void update(TaskStack stack, ArraySet<Task.TaskKey> ignoreTasksSet,
             RecentsActivityLaunchState launchState, float lastScrollPPercent) {
-        SystemServicesProxy ssp = Recents.getSystemServices();
+        SystemServicesProxy ssp = LegacyRecentsImpl.getSystemServices();
 
         // Clear the progress map
         mTaskIndexMap.clear();
@@ -494,10 +494,10 @@
             int maxBottomOffset = mStackBottomOffset + mTaskRect.height();
             float maxBottomNormX = getNormalizedXFromUnfocusedY(maxBottomOffset, FROM_BOTTOM);
             mUnfocusedRange.offset(0f);
-            mMinScrollP = Recents.getConfiguration().isLowRamDevice
+            mMinScrollP = LegacyRecentsImpl.getConfiguration().isLowRamDevice
                     ? mTaskStackLowRamLayoutAlgorithm.getMinScrollP()
                     : 0;
-            mMaxScrollP = Recents.getConfiguration().isLowRamDevice
+            mMaxScrollP = LegacyRecentsImpl.getConfiguration().isLowRamDevice
                     ? mTaskStackLowRamLayoutAlgorithm.getMaxScrollP(taskCount)
                     : Math.max(mMinScrollP, (mNumStackTasks - 1) -
                     Math.max(0, mUnfocusedRange.getAbsoluteX(maxBottomNormX)));
@@ -508,7 +508,7 @@
                 mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP);
             } else if (0 <= lastScrollPPercent && lastScrollPPercent <= 1) {
                 mInitialScrollP = Utilities.mapRange(lastScrollPPercent, mMinScrollP, mMaxScrollP);
-            } else if (Recents.getConfiguration().isLowRamDevice) {
+            } else if (LegacyRecentsImpl.getConfiguration().isLowRamDevice) {
                 mInitialScrollP = mTaskStackLowRamLayoutAlgorithm.getInitialScrollP(mNumStackTasks,
                         scrollToFront);
             } else if (scrollToFront) {
@@ -527,7 +527,7 @@
      * Creates task overrides to ensure the initial stack layout if necessary.
      */
     public void setTaskOverridesForInitialState(TaskStack stack, boolean ignoreScrollToFront) {
-        RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
+        RecentsActivityLaunchState launchState = LegacyRecentsImpl.getConfiguration().getLaunchState();
 
         mTaskIndexOverrideMap.clear();
 
@@ -620,7 +620,7 @@
      */
     public float updateFocusStateOnScroll(float lastTargetStackScroll, float targetStackScroll,
             float lastStackScroll) {
-        if (targetStackScroll == lastStackScroll || Recents.getConfiguration().isLowRamDevice) {
+        if (targetStackScroll == lastStackScroll || LegacyRecentsImpl.getConfiguration().isLowRamDevice) {
             return targetStackScroll;
         }
 
@@ -665,8 +665,8 @@
      * Returns the default focus state.
      */
     public int getInitialFocusState() {
-        RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
-        RecentsDebugFlags debugFlags = Recents.getDebugFlags();
+        RecentsActivityLaunchState launchState = LegacyRecentsImpl.getConfiguration().getLaunchState();
+        RecentsDebugFlags debugFlags = LegacyRecentsImpl.getDebugFlags();
         if (launchState.launchedWithAltTab) {
             return STATE_FOCUSED;
         } else {
@@ -709,7 +709,7 @@
             return mTaskGridLayoutAlgorithm.computeStackVisibilityReport(tasks);
         }
 
-        if (Recents.getConfiguration().isLowRamDevice) {
+        if (LegacyRecentsImpl.getConfiguration().isLowRamDevice) {
             return mTaskStackLowRamLayoutAlgorithm.computeStackVisibilityReport(tasks);
         }
 
@@ -786,7 +786,7 @@
             int taskCount = mTaskIndexMap.size();
             mTaskGridLayoutAlgorithm.getTransform(taskIndex, taskCount, transformOut, this);
             return transformOut;
-        } else if (Recents.getConfiguration().isLowRamDevice) {
+        } else if (LegacyRecentsImpl.getConfiguration().isLowRamDevice) {
             if (task == null) {
                 transformOut.reset();
                 return transformOut;
@@ -832,7 +832,7 @@
             Rect windowOverrideRect) {
         Rect windowRect = windowOverrideRect != null
                 ? windowOverrideRect
-                : Recents.getSystemServices().getWindowRect();
+                : LegacyRecentsImpl.getSystemServices().getWindowRect();
         transformOut.rect.offset(windowRect.left, windowRect.top);
         if (useGridLayout()) {
             // Draw the thumbnail a little lower to perfectly coincide with the view we are
@@ -853,7 +853,7 @@
     public void getStackTransform(float taskProgress, float nonOverrideTaskProgress,
             float stackScroll, int focusState, TaskViewTransform transformOut,
             TaskViewTransform frontTransform, boolean ignoreSingleTaskCase, boolean forceUpdate) {
-        SystemServicesProxy ssp = Recents.getSystemServices();
+        SystemServicesProxy ssp = LegacyRecentsImpl.getSystemServices();
 
         // Ensure that the task is in range
         mUnfocusedRange.offset(stackScroll);
@@ -932,10 +932,12 @@
                 }
             }
             y = (mStackRect.top - mTaskRect.top) +
-                    (int) Utilities.mapRange(focusState, unfocusedY, focusedY);
+                    (int) com.android.systemui.recents.utilities.Utilities
+                            .mapRange(focusState, unfocusedY, focusedY);
             z = Utilities.mapRange(Utilities.clamp01(boundedScrollUnfocusedNonOverrideRangeX),
                     mMinTranslationZ, mMaxTranslationZ);
-            dimAlpha = Utilities.mapRange(focusState, unfocusedDim, focusedDim);
+            dimAlpha = com.android.systemui.recents.utilities.Utilities
+                    .mapRange(focusState, unfocusedDim, focusedDim);
             viewOutlineAlpha = Utilities.mapRange(Utilities.clamp01(boundedScrollUnfocusedRangeX),
                     OUTLINE_ALPHA_MIN_VALUE, OUTLINE_ALPHA_MAX_VALUE);
         }
@@ -966,7 +968,7 @@
      */
     float getStackScrollForTask(Task t) {
         Float overrideP = mTaskIndexOverrideMap.get(t.key.id, null);
-        if (Recents.getConfiguration().isLowRamDevice || overrideP == null) {
+        if (LegacyRecentsImpl.getConfiguration().isLowRamDevice || overrideP == null) {
             return (float) mTaskIndexMap.get(t.key.id, 0);
         }
         return overrideP;
@@ -985,8 +987,8 @@
      * offset (which is at the task's brightest point).
      */
     float getStackScrollForTaskAtInitialOffset(Task t) {
-        if (Recents.getConfiguration().isLowRamDevice) {
-            RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
+        if (LegacyRecentsImpl.getConfiguration().isLowRamDevice) {
+            RecentsActivityLaunchState launchState = LegacyRecentsImpl.getConfiguration().getLaunchState();
             return mTaskStackLowRamLayoutAlgorithm.getInitialScrollP(mNumStackTasks,
                     launchState.launchedFromHome || launchState.launchedFromPipApp
                             || launchState.launchedWithNextPipApp);
@@ -1003,7 +1005,7 @@
      * screen along the arc-length proportionally (1/arclength).
      */
     public float getDeltaPForY(int downY, int y) {
-        if (Recents.getConfiguration().isLowRamDevice) {
+        if (LegacyRecentsImpl.getConfiguration().isLowRamDevice) {
             return mTaskStackLowRamLayoutAlgorithm.scrollToPercentage(downY - y);
         }
         float deltaP = (float) (y - downY) / mStackRect.height() *
@@ -1016,7 +1018,7 @@
      * of the curve, map back to the screen y.
      */
     public int getYForDeltaP(float downScrollP, float p) {
-        if (Recents.getConfiguration().isLowRamDevice) {
+        if (LegacyRecentsImpl.getConfiguration().isLowRamDevice) {
             return mTaskStackLowRamLayoutAlgorithm.percentageToScroll(downScrollP - p);
         }
         int y = (int) ((p - downScrollP) * mStackRect.height() *
@@ -1068,7 +1070,7 @@
     public static int getDimensionForDevice(Context ctx, int phonePortResId, int phoneLandResId,
             int tabletPortResId, int tabletLandResId, int xlargeTabletPortResId,
             int xlargeTabletLandResId, int gridLayoutResId) {
-        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsConfiguration config = LegacyRecentsImpl.getConfiguration();
         Resources res = ctx.getResources();
         boolean isLandscape = Utilities.getAppConfiguration(ctx).orientation ==
                 Configuration.ORIENTATION_LANDSCAPE;
@@ -1211,7 +1213,7 @@
         if (mStackRect.isEmpty()) {
             return;
         }
-        if (Recents.getConfiguration().isLowRamDevice) {
+        if (LegacyRecentsImpl.getConfiguration().isLowRamDevice) {
             mTaskStackLowRamLayoutAlgorithm.getBackOfStackTransform(mBackOfStackTransform, this);
             mTaskStackLowRamLayoutAlgorithm.getFrontOfStackTransform(mFrontOfStackTransform, this);
             return;
@@ -1233,7 +1235,7 @@
      * Returns the proper task rectangle according to the current grid state.
      */
     public Rect getTaskRect() {
-        if (Recents.getConfiguration().isLowRamDevice) {
+        if (LegacyRecentsImpl.getConfiguration().isLowRamDevice) {
             return mTaskStackLowRamLayoutAlgorithm.getTaskRect();
         }
         return useGridLayout() ? mTaskGridLayoutAlgorithm.getTaskGridRect() : mTaskRect;
@@ -1250,7 +1252,8 @@
         writer.print("insets="); writer.print(Utilities.dumpRect(mSystemInsets));
         writer.print(" stack="); writer.print(Utilities.dumpRect(mStackRect));
         writer.print(" task="); writer.print(Utilities.dumpRect(mTaskRect));
-        writer.print(" actionButton="); writer.print(Utilities.dumpRect(mStackActionButtonRect));
+        writer.print(" actionButton="); writer.print(
+                Utilities.dumpRect(mStackActionButtonRect));
         writer.println();
 
         writer.print(innerPrefix);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskStackView.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskStackView.java
index 89288d8..14fd149 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskStackView.java
@@ -26,7 +26,6 @@
 import android.content.res.Resources;
 import android.graphics.Rect;
 import android.os.Bundle;
-import android.provider.Settings;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.MutableBoolean;
@@ -44,7 +43,7 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.LegacyRecentsImpl;
 import com.android.systemui.recents.RecentsActivity;
 import com.android.systemui.recents.RecentsActivityLaunchState;
 import com.android.systemui.recents.RecentsConfiguration;
@@ -87,10 +86,10 @@
 import com.android.systemui.recents.misc.DozeTrigger;
 import com.android.systemui.recents.misc.ReferenceCountedTrigger;
 import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.shared.recents.utilities.AnimationProps;
-import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.recents.utilities.AnimationProps;
+import com.android.systemui.recents.utilities.Utilities;
 import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.recents.model.TaskStack;
+import com.android.systemui.recents.model.TaskStack;
 import com.android.systemui.recents.views.grid.GridTaskView;
 import com.android.systemui.recents.views.grid.TaskGridLayoutAlgorithm;
 import com.android.systemui.recents.views.grid.TaskViewFocusFrame;
@@ -247,7 +246,7 @@
 
     public TaskStackView(Context context) {
         super(context);
-        SystemServicesProxy ssp = Recents.getSystemServices();
+        SystemServicesProxy ssp = LegacyRecentsImpl.getSystemServices();
         Resources res = context.getResources();
 
         // Set the stack first
@@ -259,7 +258,7 @@
         mStackScroller = new TaskStackViewScroller(context, this, mLayoutAlgorithm);
         mTouchHandler = new TaskStackViewTouchHandler(context, this, mStackScroller);
         mAnimationHelper = new TaskStackAnimationHelper(context, this);
-        mTaskCornerRadiusPx = Recents.getConfiguration().isGridEnabled ?
+        mTaskCornerRadiusPx = LegacyRecentsImpl.getConfiguration().isGridEnabled ?
                 res.getDimensionPixelSize(R.dimen.recents_grid_task_view_rounded_corners_radius) :
                 res.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius);
         mFastFlingVelocity = res.getDimensionPixelSize(R.dimen.recents_fast_fling_velocity);
@@ -269,7 +268,7 @@
         mStackActionButtonVisible = false;
 
         // Create a frame to draw around the focused task view
-        if (Recents.getConfiguration().isGridEnabled) {
+        if (LegacyRecentsImpl.getConfiguration().isGridEnabled) {
             mTaskViewFocusFrame = new TaskViewFocusFrame(mContext, this,
                 mLayoutAlgorithm.mTaskGridLayoutAlgorithm);
             addView(mTaskViewFocusFrame);
@@ -762,7 +761,7 @@
      */
     private void clipTaskViews() {
         // We never clip task views in grid layout
-        if (Recents.getConfiguration().isGridEnabled) {
+        if (LegacyRecentsImpl.getConfiguration().isGridEnabled) {
             return;
         }
 
@@ -816,7 +815,7 @@
     }
 
     public void updateLayoutAlgorithm(boolean boundScrollToNewMinMax) {
-        updateLayoutAlgorithm(boundScrollToNewMinMax, Recents.getConfiguration().getLaunchState());
+        updateLayoutAlgorithm(boundScrollToNewMinMax, LegacyRecentsImpl.getConfiguration().getLaunchState());
     }
 
     /**
@@ -1142,7 +1141,7 @@
         if (mStackScroller.computeScroll()) {
             // Notify accessibility
             sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED);
-            Recents.getTaskLoader().getHighResThumbnailLoader().setFlingingFast(
+            LegacyRecentsImpl.getTaskLoader().getHighResThumbnailLoader().setFlingingFast(
                     mStackScroller.getScrollVelocity() > mFastFlingVelocity);
         }
         if (mDeferredTaskViewLayoutAnimation != null) {
@@ -1327,7 +1326,7 @@
 
         // Set the task focused state without requesting view focus, and leave the focus animations
         // until after the enter-animation
-        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsConfiguration config = LegacyRecentsImpl.getConfiguration();
         RecentsActivityLaunchState launchState = config.getLaunchState();
 
         // We set the initial focused task view iff the following conditions are satisfied:
@@ -1474,7 +1473,7 @@
 
     @Override
     public TaskView createView(Context context) {
-        if (Recents.getConfiguration().isGridEnabled) {
+        if (LegacyRecentsImpl.getConfiguration().isGridEnabled) {
             return (GridTaskView) mInflater.inflate(R.layout.recents_grid_task_view, this, false);
         } else {
             return (TaskView) mInflater.inflate(R.layout.recents_task_view, this, false);
@@ -1565,7 +1564,7 @@
 
         // If the doze trigger has already fired, then update the state for this task view
         if (mUIDozeTrigger.isAsleep() ||
-                useGridLayout() || Recents.getConfiguration().isLowRamDevice) {
+                useGridLayout() || LegacyRecentsImpl.getConfiguration().isLowRamDevice) {
             tv.setNoUserInteractionState();
         }
 
@@ -1573,17 +1572,17 @@
             task.notifyTaskDataLoaded(task.thumbnail, task.icon);
         } else {
             // Load the task data
-            Recents.getTaskLoader().loadTaskData(task);
+            LegacyRecentsImpl.getTaskLoader().loadTaskData(task);
         }
-        Recents.getTaskLoader().getHighResThumbnailLoader().onTaskVisible(task);
+        LegacyRecentsImpl.getTaskLoader().getHighResThumbnailLoader().onTaskVisible(task);
     }
 
     private void unbindTaskView(TaskView tv, Task task) {
         if (task != mPrefetchingTask) {
             // Report that this task's data is no longer being used
-            Recents.getTaskLoader().unloadTaskData(task);
+            LegacyRecentsImpl.getTaskLoader().unloadTaskData(task);
         }
-        Recents.getTaskLoader().getHighResThumbnailLoader().onTaskInvisible(task);
+        LegacyRecentsImpl.getTaskLoader().getHighResThumbnailLoader().onTaskInvisible(task);
     }
 
     private void updatePrefetchingTask(ArrayList<Task> tasks, int frontIndex, int backIndex) {
@@ -1596,19 +1595,19 @@
             if (mPrefetchingTask != null) {
                 int index = tasks.indexOf(mPrefetchingTask);
                 if (index < backIndex || index > frontIndex) {
-                    Recents.getTaskLoader().unloadTaskData(mPrefetchingTask);
+                    LegacyRecentsImpl.getTaskLoader().unloadTaskData(mPrefetchingTask);
                 }
             }
             mPrefetchingTask = t;
             if (t != null) {
-                Recents.getTaskLoader().loadTaskData(t);
+                LegacyRecentsImpl.getTaskLoader().loadTaskData(t);
             }
         }
     }
 
     private void clearPrefetchingTask() {
         if (mPrefetchingTask != null) {
-            Recents.getTaskLoader().unloadTaskData(mPrefetchingTask);
+            LegacyRecentsImpl.getTaskLoader().unloadTaskData(mPrefetchingTask);
         }
         mPrefetchingTask = null;
     }
@@ -1644,7 +1643,7 @@
 
         // In grid layout, the stack action button always remains visible.
         if (mEnterAnimationComplete && !useGridLayout()) {
-            if (Recents.getConfiguration().isLowRamDevice) {
+            if (LegacyRecentsImpl.getConfiguration().isLowRamDevice) {
                 // Show stack button when user drags down to show older tasks on low ram devices
                 if (mStack.getTaskCount() > 0 && !mStackActionButtonVisible
                         && mTouchHandler.mIsScrolling && curScroll - prevScroll < 0) {
@@ -1727,7 +1726,7 @@
             return;
         }
 
-        if (!Recents.getConfiguration().getLaunchState().launchedFromPipApp
+        if (!LegacyRecentsImpl.getConfiguration().getLaunchState().launchedFromPipApp
                 && mStack.isNextLaunchTargetPip(RecentsImpl.getLastPipTime())) {
             // If the launch task is in the pinned stack, then expand the PiP now
             EventBus.getDefault().send(new ExpandPipEvent());
@@ -1831,7 +1830,7 @@
         // Remove the task from the stack
         mStack.removeTask(event.task, event.animation, false /* fromDockGesture */);
         EventBus.getDefault().send(new DeleteTaskDataEvent(event.task));
-        if (mStack.getTaskCount() > 0 && Recents.getConfiguration().isLowRamDevice) {
+        if (mStack.getTaskCount() > 0 && LegacyRecentsImpl.getConfiguration().isLowRamDevice) {
             EventBus.getDefault().send(new ShowStackActionButtonEvent(false /* translate */));
         }
 
@@ -1878,7 +1877,7 @@
         // Poke the doze trigger on user interaction
         mUIDozeTrigger.poke();
 
-        RecentsDebugFlags debugFlags = Recents.getDebugFlags();
+        RecentsDebugFlags debugFlags = LegacyRecentsImpl.getDebugFlags();
         if (mFocusedTask != null) {
             TaskView tv = getChildViewForTask(mFocusedTask);
             if (tv != null) {
@@ -2002,7 +2001,7 @@
                 // animate the focused state if we are alt-tabbing now, after the window enter
                 // animation is completed
                 if (mFocusedTask != null) {
-                    RecentsConfiguration config = Recents.getConfiguration();
+                    RecentsConfiguration config = LegacyRecentsImpl.getConfiguration();
                     RecentsActivityLaunchState launchState = config.getLaunchState();
                     setFocusedTask(mStack.indexOfTask(mFocusedTask),
                             false /* scrollToTask */, launchState.launchedWithAltTab);
@@ -2023,7 +2022,7 @@
             setTasks(event.stack, true /* allowNotifyStackChanges */);
         } else {
             // Reset the launch state before handling the multiwindow change
-            RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
+            RecentsActivityLaunchState launchState = LegacyRecentsImpl.getConfiguration().getLaunchState();
             launchState.reset();
 
             // Defer until the next frame to ensure that we have received all the system insets, and
@@ -2044,7 +2043,7 @@
     public final void onBusEvent(ConfigurationChangedEvent event) {
         if (event.fromDeviceOrientationChange) {
             mDisplayOrientation = Utilities.getAppConfiguration(mContext).orientation;
-            mDisplayRect = Recents.getSystemServices().getDisplayRect();
+            mDisplayRect = LegacyRecentsImpl.getSystemServices().getDisplayRect();
 
             // Always stop the scroller, otherwise, we may continue setting the stack scroll to the
             // wrong bounds in the new layout
@@ -2186,14 +2185,14 @@
      * Reads current system flags related to accessibility and screen pinning.
      */
     private void readSystemFlags() {
-        SystemServicesProxy ssp = Recents.getSystemServices();
+        SystemServicesProxy ssp = LegacyRecentsImpl.getSystemServices();
         mTouchExplorationEnabled = ssp.isTouchExplorationEnabled();
         mScreenPinningEnabled = ActivityManagerWrapper.getInstance().isScreenPinningEnabled()
                 && !ActivityManagerWrapper.getInstance().isLockToAppActive();
     }
 
     private void updateStackActionButtonVisibility() {
-        if (Recents.getConfiguration().isLowRamDevice) {
+        if (LegacyRecentsImpl.getConfiguration().isLowRamDevice) {
             return;
         }
 
@@ -2260,9 +2259,12 @@
         writer.print(" screenPinningOn="); writer.print(mScreenPinningEnabled ? "Y" : "N");
         writer.print(" numIgnoreTasks="); writer.print(mIgnoreTasks.size());
         writer.print(" numViewPool="); writer.print(mViewPool.getViews().size());
-        writer.print(" stableStackBounds="); writer.print(Utilities.dumpRect(mStableStackBounds));
-        writer.print(" stackBounds="); writer.print(Utilities.dumpRect(mStackBounds));
-        writer.print(" stableWindow="); writer.print(Utilities.dumpRect(mStableWindowRect));
+        writer.print(" stableStackBounds="); writer.print(
+                Utilities.dumpRect(mStableStackBounds));
+        writer.print(" stackBounds="); writer.print(
+                Utilities.dumpRect(mStackBounds));
+        writer.print(" stableWindow="); writer.print(
+                Utilities.dumpRect(mStableWindowRect));
         writer.print(" window="); writer.print(Utilities.dumpRect(mWindowRect));
         writer.print(" display="); writer.print(Utilities.dumpRect(mDisplayRect));
         writer.print(" orientation="); writer.print(mDisplayOrientation);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskStackViewScroller.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskStackViewScroller.java
index 6b23977..42efe59 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskStackViewScroller.java
@@ -31,9 +31,9 @@
 
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.recents.Recents;
-import com.android.systemui.shared.recents.utilities.AnimationProps;
-import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.recents.LegacyRecentsImpl;
+import com.android.systemui.recents.utilities.AnimationProps;
+import com.android.systemui.recents.utilities.Utilities;
 import com.android.systemui.recents.views.lowram.TaskStackLowRamLayoutAlgorithm;
 import com.android.systemui.statusbar.FlingAnimationUtils;
 
@@ -89,7 +89,7 @@
         mContext = context;
         mCb = cb;
         mScroller = new OverScroller(context);
-        if (Recents.getConfiguration().isLowRamDevice) {
+        if (LegacyRecentsImpl.getConfiguration().isLowRamDevice) {
             mScroller.setFriction(0.06f);
         }
         mLayoutAlgorithm = layoutAlgorithm;
@@ -206,7 +206,7 @@
         float stackScroll = getStackScroll();
 
         // Skip if not in low ram layout and if the scroll is out of min and max bounds
-        if (!Recents.getConfiguration().isLowRamDevice || stackScroll < mLayoutAlgorithm.mMinScrollP
+        if (!LegacyRecentsImpl.getConfiguration().isLowRamDevice || stackScroll < mLayoutAlgorithm.mMinScrollP
                 || stackScroll > mLayoutAlgorithm.mMaxScrollP) {
             return;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index c91cdfc..dd6926c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -38,14 +38,14 @@
 import com.android.systemui.R;
 import com.android.systemui.SwipeHelper;
 import com.android.systemui.recents.Constants;
-import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.LegacyRecentsImpl;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.HideRecentsEvent;
 import com.android.systemui.recents.events.ui.StackViewScrolledEvent;
 import com.android.systemui.recents.events.ui.TaskViewDismissedEvent;
 import com.android.systemui.recents.misc.FreePathInterpolator;
-import com.android.systemui.shared.recents.utilities.AnimationProps;
-import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.recents.utilities.AnimationProps;
+import com.android.systemui.recents.utilities.Utilities;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.statusbar.FlingAnimationUtils;
 
@@ -296,7 +296,7 @@
                     if (curScrollP < minScrollP || curScrollP > maxScrollP) {
                         float clampedScrollP = Utilities.clamp(curScrollP, minScrollP, maxScrollP);
                         float overscrollP = (curScrollP - clampedScrollP);
-                        float maxOverscroll = Recents.getConfiguration().isLowRamDevice
+                        float maxOverscroll = LegacyRecentsImpl.getConfiguration().isLowRamDevice
                                 ? layoutAlgorithm.mTaskStackLowRamLayoutAlgorithm.getMaxOverscroll()
                                 : MAX_OVERSCROLL;
                         float overscrollX = Math.abs(overscrollP) / maxOverscroll;
@@ -339,7 +339,7 @@
                     if (mScroller.isScrollOutOfBounds()) {
                         mScroller.animateBoundScroll();
                     } else if (Math.abs(velocity) > mMinimumVelocity &&
-                            !Recents.getConfiguration().isLowRamDevice) {
+                            !LegacyRecentsImpl.getConfiguration().isLowRamDevice) {
                         float minY = mDownY + layoutAlgorithm.getYForDeltaP(mDownScrollP,
                                 layoutAlgorithm.mMaxScrollP);
                         float maxY = mDownY + layoutAlgorithm.getYForDeltaP(mDownScrollP,
@@ -352,7 +352,7 @@
                     // Reset the focused task after the user has scrolled, but we have no scrolling
                     // in grid layout and therefore we don't want to reset the focus there.
                     if (!mSv.mTouchExplorationEnabled && !mSv.useGridLayout()) {
-                        if (Recents.getConfiguration().isLowRamDevice) {
+                        if (LegacyRecentsImpl.getConfiguration().isLowRamDevice) {
                             mScroller.scrollToClosestTask(velocity);
                         } else {
                             mSv.resetFocusedTask(mSv.getFocusedTask());
@@ -493,7 +493,7 @@
             float prevAnchorTaskScroll = 0;
             boolean pullStackForward = mCurrentTasks.size() > 0;
             if (pullStackForward) {
-                if (Recents.getConfiguration().isLowRamDevice) {
+                if (LegacyRecentsImpl.getConfiguration().isLowRamDevice) {
                     float index = layoutAlgorithm.getStackScrollForTask(anchorTask);
                     prevAnchorTaskScroll = mSv.getStackAlgorithm().mTaskStackLowRamLayoutAlgorithm
                             .getScrollPForTask((int) index);
@@ -513,14 +513,14 @@
                 // Otherwise, offset the scroll by the movement of the anchor task
                 float anchorTaskScroll =
                         layoutAlgorithm.getStackScrollForTaskIgnoreOverrides(anchorTask);
-                if (Recents.getConfiguration().isLowRamDevice) {
+                if (LegacyRecentsImpl.getConfiguration().isLowRamDevice) {
                     float index = layoutAlgorithm.getStackScrollForTask(anchorTask);
                     anchorTaskScroll = mSv.getStackAlgorithm().mTaskStackLowRamLayoutAlgorithm
                             .getScrollPForTask((int) index);
                 }
                 float stackScrollOffset = (anchorTaskScroll - prevAnchorTaskScroll);
                 if (layoutAlgorithm.getFocusState() != TaskStackLayoutAlgorithm.STATE_FOCUSED
-                        && !Recents.getConfiguration().isLowRamDevice) {
+                        && !LegacyRecentsImpl.getConfiguration().isLowRamDevice) {
                     // If we are focused, we don't want the front task to move, but otherwise, we
                     // allow the back task to move up, and the front task to move back
                     stackScrollOffset *= 0.75f;
@@ -554,7 +554,7 @@
         // Only update the swipe progress for the surrounding tasks if the dismiss animation was not
         // preempted from a call to cancelNonDismissTaskAnimations
         if ((mActiveTaskView == v || mSwipeHelperAnimations.containsKey(v)) &&
-                !Recents.getConfiguration().isLowRamDevice) {
+                !LegacyRecentsImpl.getConfiguration().isLowRamDevice) {
             updateTaskViewTransforms(
                     Interpolators.FAST_OUT_SLOW_IN.getInterpolation(swipeProgress));
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskView.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskView.java
index f0278a6..ab0bf95 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskView.java
@@ -39,7 +39,7 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.LegacyRecentsImpl;
 import com.android.systemui.recents.RecentsActivity;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.events.EventBus;
@@ -51,11 +51,10 @@
 import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
 import com.android.systemui.recents.misc.ReferenceCountedTrigger;
 import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.shared.recents.utilities.AnimationProps;
-import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.recents.utilities.AnimationProps;
+import com.android.systemui.recents.utilities.Utilities;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.ThumbnailData;
-import com.android.systemui.shared.recents.view.AnimateableViewBounds;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -175,7 +174,7 @@
 
     public TaskView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsConfiguration config = LegacyRecentsImpl.getConfiguration();
         Resources res = context.getResources();
         mViewBounds = createOutlineProvider();
         if (config.fakeShadows) {
@@ -283,7 +282,7 @@
 
     void updateViewPropertiesToTaskTransform(TaskViewTransform toTransform,
             AnimationProps toAnimation, ValueAnimator.AnimatorUpdateListener updateCallback) {
-        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsConfiguration config = LegacyRecentsImpl.getConfiguration();
         cancelTransformAnimation();
 
         // Compose the animations for the transform
@@ -412,7 +411,7 @@
      * view.
      */
     boolean shouldClipViewInStack() {
-        if (getVisibility() != View.VISIBLE || Recents.getConfiguration().isLowRamDevice) {
+        if (getVisibility() != View.VISIBLE || LegacyRecentsImpl.getConfiguration().isLowRamDevice) {
             return false;
         }
         return mClipViewInStack;
@@ -601,7 +600,7 @@
 
     public void onTaskBound(Task t, boolean touchExplorationEnabled, int displayOrientation,
             Rect displayRect) {
-        SystemServicesProxy ssp = Recents.getSystemServices();
+        SystemServicesProxy ssp = LegacyRecentsImpl.getSystemServices();
         mTouchExplorationEnabled = touchExplorationEnabled;
         mTask = t;
         mTaskBound = true;
@@ -679,10 +678,10 @@
 
     @Override
     public boolean onLongClick(View v) {
-        if (!Recents.getConfiguration().dragToSplitEnabled) {
+        if (!LegacyRecentsImpl.getConfiguration().dragToSplitEnabled) {
             return false;
         }
-        SystemServicesProxy ssp = Recents.getSystemServices();
+        SystemServicesProxy ssp = LegacyRecentsImpl.getSystemServices();
         boolean inBounds = false;
         Rect clipBounds = new Rect(mViewBounds.getClipBounds());
         if (!clipBounds.isEmpty()) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java
similarity index 94%
rename from packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java
index 5bb5b2d..7bcad75 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java
@@ -25,7 +25,7 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 import com.android.systemui.R;
-import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.LegacyRecentsImpl;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
@@ -56,8 +56,8 @@
     public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfo(host, info);
         if (ActivityTaskManager.supportsSplitScreenMultiWindow(mTaskView.getContext())
-                && !Recents.getSystemServices().hasDockedTask()) {
-            DockState[] dockStates = Recents.getConfiguration()
+                && !LegacyRecentsImpl.getSystemServices().hasDockedTask()) {
+            DockState[] dockStates = LegacyRecentsImpl.getConfiguration()
                     .getDockStatesForCurrentOrientation();
             for (DockState dockState: dockStates) {
                 if (dockState == DockState.TOP) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskViewHeader.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskViewHeader.java
index de42914..21c0234 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -53,14 +53,14 @@
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
-import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.LegacyRecentsImpl;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.LaunchTaskEvent;
 import com.android.systemui.recents.events.ui.ShowApplicationInfoEvent;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.PackageManagerWrapper;
-import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.recents.utilities.Utilities;
 import com.android.systemui.shared.recents.model.Task;
 
 /* The task bar view */
@@ -212,7 +212,7 @@
         Resources res = context.getResources();
         mLightDismissDrawable = context.getDrawable(R.drawable.recents_dismiss_light);
         mDarkDismissDrawable = context.getDrawable(R.drawable.recents_dismiss_dark);
-        mCornerRadius = Recents.getConfiguration().isGridEnabled ?
+        mCornerRadius = LegacyRecentsImpl.getConfiguration().isGridEnabled ?
                 res.getDimensionPixelSize(R.dimen.recents_grid_task_view_rounded_corners_radius) :
                 res.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius);
         mHighlightHeight = res.getDimensionPixelSize(R.dimen.recents_task_view_highlight);
@@ -246,7 +246,7 @@
 
     @Override
     protected void onFinishInflate() {
-        SystemServicesProxy ssp = Recents.getSystemServices();
+        SystemServicesProxy ssp = LegacyRecentsImpl.getSystemServices();
 
         // Initialize the icon and description views
         mIconView = findViewById(R.id.icon);
@@ -605,7 +605,7 @@
      */
     private void showAppOverlay() {
         // Skip early if the task is invalid
-        SystemServicesProxy ssp = Recents.getSystemServices();
+        SystemServicesProxy ssp = LegacyRecentsImpl.getSystemServices();
         ComponentName cn = mTask.key.getComponent();
         int userId = mTask.key.userId;
         ActivityInfo activityInfo = PackageManagerWrapper.getInstance().getActivityInfo(cn, userId);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskViewThumbnail.java
similarity index 99%
rename from packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index 4152b05..68f85a5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -37,7 +37,7 @@
 import com.android.systemui.R;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.ui.TaskSnapshotChangedEvent;
-import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.recents.utilities.Utilities;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 import java.io.PrintWriter;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskViewTransform.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskViewTransform.java
index 9b717e0..48a7336 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskViewTransform.java
@@ -24,8 +24,8 @@
 import android.util.Property;
 import android.view.View;
 
-import com.android.systemui.shared.recents.utilities.AnimationProps;
-import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.recents.utilities.AnimationProps;
+import com.android.systemui.recents.utilities.Utilities;
 
 import java.util.ArrayList;
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/ViewPool.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/ViewPool.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/views/ViewPool.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/ViewPool.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/AnimateableGridViewBounds.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/grid/AnimateableGridViewBounds.java
similarity index 93%
rename from packages/SystemUI/src/com/android/systemui/recents/views/grid/AnimateableGridViewBounds.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/grid/AnimateableGridViewBounds.java
index 3bdad31..a029478 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/grid/AnimateableGridViewBounds.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/grid/AnimateableGridViewBounds.java
@@ -17,7 +17,7 @@
 package com.android.systemui.recents.views.grid;
 
 import android.view.View;
-import com.android.systemui.shared.recents.view.AnimateableViewBounds;
+import com.android.systemui.recents.views.AnimateableViewBounds;
 
 /* An outline provider for grid-based task views. */
 class AnimateableGridViewBounds extends AnimateableViewBounds {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/grid/GridTaskView.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/grid/GridTaskView.java
index 0d51154..8b4700c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/grid/GridTaskView.java
@@ -19,7 +19,7 @@
 import android.content.Context;
 import android.util.AttributeSet;
 import com.android.systemui.R;
-import com.android.systemui.shared.recents.view.AnimateableViewBounds;
+import com.android.systemui.recents.views.AnimateableViewBounds;
 import com.android.systemui.recents.views.TaskView;
 
 public class GridTaskView extends TaskView {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskViewThumbnail.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/grid/GridTaskViewThumbnail.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskViewThumbnail.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/grid/GridTaskViewThumbnail.java
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
similarity index 99%
rename from packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
index ccda4b5..719eaa7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
@@ -26,7 +26,7 @@
 
 import com.android.systemui.R;
 import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent.Direction;
-import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.recents.utilities.Utilities;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
 import com.android.systemui.recents.views.TaskViewTransform;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java
index fe6bafb..1655f6c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java
@@ -23,7 +23,7 @@
 
 import android.view.ViewTreeObserver.OnGlobalFocusChangeListener;
 import com.android.systemui.R;
-import com.android.systemui.shared.recents.model.TaskStack;
+import com.android.systemui.recents.model.TaskStack;
 import com.android.systemui.recents.views.TaskStackView;
 
 public class TaskViewFocusFrame extends View implements OnGlobalFocusChangeListener {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/lowram/TaskStackLowRamLayoutAlgorithm.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/lowram/TaskStackLowRamLayoutAlgorithm.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/recents/views/lowram/TaskStackLowRamLayoutAlgorithm.java
rename to packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/lowram/TaskStackLowRamLayoutAlgorithm.java
index 49cac26..15c7c87 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/lowram/TaskStackLowRamLayoutAlgorithm.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/lowram/TaskStackLowRamLayoutAlgorithm.java
@@ -21,9 +21,9 @@
 import android.view.ViewConfiguration;
 
 import com.android.systemui.R;
-import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.LegacyRecentsImpl;
 import com.android.systemui.recents.RecentsActivityLaunchState;
-import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.recents.utilities.Utilities;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
 import com.android.systemui.recents.views.TaskViewTransform;
@@ -82,7 +82,7 @@
     }
 
     public VisibilityReport computeStackVisibilityReport(ArrayList<Task> tasks) {
-        RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
+        RecentsActivityLaunchState launchState = LegacyRecentsImpl.getConfiguration().getLaunchState();
         int maxVisible = launchState.launchedFromHome || launchState.launchedFromPipApp
                     || launchState.launchedWithNextPipApp
                 ? NUM_TASK_VISIBLE_LAUNCHED_FROM_HOME
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index fa4c8b5..ee94aed 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -10,6 +10,7 @@
   public void setGlowScale(float);
 }
 
+-keep class com.android.systemui.recents.OverviewProxyRecentsImpl
 -keep class com.android.systemui.statusbar.car.CarStatusBar
 -keep class com.android.systemui.statusbar.phone.StatusBar
 -keep class com.android.systemui.statusbar.tv.TvStatusBar
@@ -17,21 +18,6 @@
 -keep class com.android.systemui.SystemUIFactory
 -keep class * extends com.android.systemui.SystemUI
 
--keepclassmembers class ** {
-    public void onBusEvent(**);
-    public void onInterprocessBusEvent(**);
-}
--keepclassmembers class ** extends **.EventBus$InterprocessEvent {
-    public <init>(android.os.Bundle);
-}
-
--keep class com.android.systemui.recents.views.TaskView {
-    public int getDim();
-    public void setDim(int);
-    public float getTaskProgress();
-    public void setTaskProgress(float);
-}
-
 -keepclasseswithmembers class * {
     public <init>(android.content.Context, android.util.AttributeSet);
 }
diff --git a/packages/SystemUI/res/layout/status_bar_no_recent_apps.xml b/packages/SystemUI/res/layout/status_bar_no_recent_apps.xml
deleted file mode 100644
index adfaed13..0000000
--- a/packages/SystemUI/res/layout/status_bar_no_recent_apps.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2011, 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_height="match_parent"
-    android:layout_width="match_parent"
-    >
-
-    <TextView
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:textSize="20dp"
-        android:textColor="@android:color/holo_blue_light"
-        android:text="@string/status_bar_no_recent_apps"
-        android:gravity="center_horizontal"
-        android:layout_gravity="center"
-    />
-</FrameLayout>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index eb5c180..8934183 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -88,7 +88,4 @@
 
     <!-- Keyboard shortcuts helper -->
     <dimen name="ksh_layout_width">488dp</dimen>
-
-    <!-- The offsets the tasks animate from when recents is launched while docking -->
-    <dimen name="recents_task_stack_animation_launched_while_docking_offset">192dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index f50ef82..baaf9d6 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -30,12 +30,6 @@
     <declare-styleable name="NotificationLinearLayout">
         <attr name="insetLeft" format="dimension" />
     </declare-styleable>
-    <declare-styleable name="RecentsPanelView">
-        <attr name="recentItemLayout" format="reference" />
-        <!-- Style for the "Clear all" button. -->
-        <attr name="clearAllStyle" format="reference" />
-        <attr name="clearAllBackgroundColor" format="reference" />
-    </declare-styleable>
     <declare-styleable name="DeadZone">
         <attr name="minSize" format="dimension" />
         <attr name="maxSize" format="dimension" />
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index d1320a3..0027cc6 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -39,32 +39,6 @@
     <!-- Tint color for the content on the notification overflow card. -->
     <color name="keyguard_overflow_content_color">#ff686868</color>
 
-    <!-- The disabled recents task bar background color. -->
-    <color name="recents_task_bar_disabled_background_color">#ff676767</color>
-    <!-- The default recents task bar background color. -->
-    <color name="recents_task_bar_default_background_color">#ffe6e6e6</color>
-    <!-- The default recents task view background color. -->
-    <color name="recents_task_view_default_background_color">#fff3f3f3</color>
-    <!-- The recents task bar light text color to be drawn on top of dark backgrounds. -->
-    <color name="recents_task_bar_light_text_color">#ffeeeeee</color>
-    <!-- The recents task bar dark text color to be drawn on top of light backgrounds. -->
-    <color name="recents_task_bar_dark_text_color">#cc000000</color>
-    <!-- The recents task bar light dismiss icon color to be drawn on top of dark backgrounds. -->
-    <color name="recents_task_bar_light_icon_color">#ccffffff</color>
-    <!-- The recents task bar dark dismiss icon color to be drawn on top of light backgrounds. -->
-    <color name="recents_task_bar_dark_icon_color">#99000000</color>
-    <!-- The lock to task button background color. -->
-    <color name="recents_task_view_lock_to_app_button_background_color">#ffe6e6e6</color>
-    <!-- The lock to task button foreground color. -->
-    <color name="recents_task_view_lock_to_app_button_color">#ff666666</color>
-    <!-- The background color for the freeform workspace. -->
-    <color name="recents_freeform_workspace_bg_color">#33FFFFFF</color>
-
-    <!-- The background color for clear all button on light backgrounds if not transparent. -->
-    <color name="recents_clear_all_button_bg_light_color">#CCFFFFFF</color>
-    <!-- The background color for clear all button on dark backgrounds if not transparent. -->
-    <color name="recents_clear_all_button_bg_dark_color">#CC000000</color>
-
     <color name="keyguard_affordance">#ffffffff</color>
 
     <!-- The color of the legacy notification background -->
@@ -110,12 +84,6 @@
     <!-- The shadow color for light navigation bar icons. -->
     <color name="nav_key_button_shadow_color">#30000000</color>
 
-    <!-- Shadow color for the first pixels around the fake shadow for recents. -->
-    <color name="fake_shadow_start_color">#44000000</color>
-
-    <!-- Shadow color for the furthest pixels around the fake shadow for recents. -->
-    <color name="fake_shadow_end_color">#03000000</color>
-
     <color name="screen_pinning_request_window_bg">#80000000</color>
 
     <color name="segmented_buttons_background">#14FFFFFF</color><!-- 8% white -->
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 6378309..b31dc50 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -20,19 +20,6 @@
 <!-- These resources are around just to allow their values to be customized
      for different hardware and product builds. -->
 <resources>
-    <!-- Whether recents should use hardware layers for its taskviews. This flag can be enabled
-    for devices where the java drawing of round rects may be slow -->
-    <bool name="config_recents_use_hardware_layers">false</bool>
-
-    <!-- The number of app thumbnails we keep in memory -->
-    <integer name="config_recents_max_thumbnail_count">10</integer>
-
-    <!-- The number of app icons we keep in memory -->
-    <integer name="config_recents_max_icon_count">20</integer>
-
-    <!-- Whether to use cheap, less good looking shadows for recents -->
-    <bool name="config_recents_fake_shadows">false</bool>
-
     <!-- Whether to clip notification contents with a rounded rectangle. Might be expensive on
          certain GPU's and thus can be turned off with only minimal visual impact. -->
     <bool name="config_notifications_round_rect_clipping">true</bool>
@@ -45,6 +32,11 @@
      interface.  This name is in the ComponentName flattened format (package/class)  -->
     <string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.phone.StatusBar</string>
 
+    <!-- Component to be used as the recents implementation.  Must implement the
+     RecentsImplementation interface.  This name is in the ComponentName flattened format
+     (package/class)  -->
+    <string name="config_recentsComponent" translatable="false">com.android.systemui.recents.OverviewProxyRecentsImpl</string>
+
     <!-- Whether or not we show the number in the bar. -->
     <bool name="config_statusBarShowNumber">false</bool>
 
@@ -163,30 +155,6 @@
     <!-- The number of milliseconds to extend ambient pulse by when prompted (e.g. on touch) -->
     <integer name="ambient_notification_extension_time">6000</integer>
 
-    <!-- The duration in seconds to wait before the dismiss buttons are shown. -->
-    <integer name="recents_task_bar_dismiss_delay_seconds">1000</integer>
-
-    <!-- The duration for animating the task decorations in after transitioning from an app. -->
-    <integer name="recents_task_enter_from_app_duration">200</integer>
-
-    <!-- The duration for animating the task decorations in after transitioning from an app. -->
-    <integer name="recents_task_enter_from_affiliated_app_duration">125</integer>
-
-    <!-- The duration for animating the task decorations out before transitioning to an app. -->
-    <integer name="recents_task_exit_to_app_duration">125</integer>
-
-    <!-- The min animation duration for animating the nav bar scrim in. -->
-    <integer name="recents_nav_bar_scrim_enter_duration">400</integer>
-
-    <!-- The animation duration for scrolling the stack to a particular item. -->
-    <integer name="recents_animate_task_stack_scroll_duration">200</integer>
-
-    <!-- The delay to enforce between each alt-tab key press. -->
-    <integer name="recents_alt_tab_key_delay">200</integer>
-
-    <!-- Svelte specific logic, see RecentsConfiguration.SVELTE_* constants. -->
-    <integer name="recents_svelte_level">0</integer>
-
     <!-- In multi-window, determines whether the stack where recents lives should grow from
          the smallest position when being launched. -->
     <bool name="recents_grow_in_multiwindow">true</bool>
@@ -194,16 +162,6 @@
     <!-- Animation duration when using long press on recents to dock -->
     <integer name="long_press_dock_anim_duration">250</integer>
 
-    <!-- Recents: The relative range of visible tasks from the current scroll position
-         while the stack is focused. -->
-    <item name="recents_layout_focused_range_min" format="float" type="integer">-3</item>
-    <item name="recents_layout_focused_range_max" format="float" type="integer">2</item>
-
-    <!-- Recents: The relative range of visible tasks from the current scroll position
-         while the stack is not focused. -->
-    <item name="recents_layout_unfocused_range_min" format="float" type="integer">-2</item>
-    <item name="recents_layout_unfocused_range_max" format="float" type="integer">2.5</item>
-
     <!-- Whether to enable KeyguardService or not -->
     <bool name="config_enableKeyguardService">true</bool>
 
@@ -362,7 +320,6 @@
     <string-array name="config_systemUIServiceComponentsPerUser" translatable="false">
         <item>com.android.systemui.Dependency</item>
         <item>com.android.systemui.util.NotificationChannels</item>
-        <item>com.android.systemui.recents.Recents</item>
     </string-array>
 
     <!-- Nav bar button default ordering/layout -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index ab7dec9..9fe7718 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -793,102 +793,11 @@
     <dimen name="ksh_item_padding">4dp</dimen>
     <dimen name="ksh_item_margin_start">4dp</dimen>
 
-<!-- Recents Layout -->
-
-    <!-- The amount to inset the stack, specifically at the top and the other sides.  We also
-         don't want this to change across configurations that Recents can be opened in, so we
-         define them statically for all display sizes. -->
-    <dimen name="recents_layout_min_margin">16dp</dimen>
-    <dimen name="recents_layout_top_margin_phone">16dp</dimen>
-    <dimen name="recents_layout_top_margin_tablet">32dp</dimen>
-    <dimen name="recents_layout_top_margin_tablet_xlarge">40dp</dimen>
-    <dimen name="recents_layout_bottom_margin">16dp</dimen>
-    <dimen name="recents_layout_side_margin_phone">16dp</dimen>
-    <dimen name="recents_layout_side_margin_tablet">48dp</dimen>
-    <dimen name="recents_layout_side_margin_tablet_docked">16dp</dimen>
-    <dimen name="recents_layout_side_margin_tablet_xlarge">64dp</dimen>
-    <dimen name="recents_layout_side_margin_tablet_xlarge_docked">16dp</dimen>
-
-    <!-- The height between the top margin and the top of the focused task. -->
-    <dimen name="recents_layout_top_peek_size">48dp</dimen>
-    <!-- The height between the bottom margin and the top of task in front of the focused task. -->
-    <dimen name="recents_layout_bottom_peek_size">56dp</dimen>
-
-    <!-- The offset from the top and bottom of the stack of the focused task.  The bottom offset
-         will be additionally offset by the bottom system insets since it goes under the nav bar
-         in certain orientations. -->
-    <dimen name="recents_layout_initial_top_offset_phone_port">128dp</dimen>
-    <dimen name="recents_layout_initial_bottom_offset_phone_port">80dp</dimen>
-    <dimen name="recents_layout_initial_top_offset_phone_land">72dp</dimen>
-    <dimen name="recents_layout_initial_bottom_offset_phone_land">72dp</dimen>
-    <dimen name="recents_layout_initial_top_offset_tablet">160dp</dimen>
-    <dimen name="recents_layout_initial_bottom_offset_tablet">112dp</dimen>
-
-    <!-- The min/max translationZ for the tasks in the stack. -->
-    <dimen name="recents_layout_z_min">3dp</dimen>
-    <dimen name="recents_layout_z_max">24dp</dimen>
-
-    <!-- The margin between the freeform and stack.  We also don't want this to change across
-         configurations that Recents can be opened in, so we define them statically for all
-         display sizes. -->
-    <dimen name="recents_freeform_layout_bottom_margin">16dp</dimen>
-
-    <!-- The padding between each freeform task. -->
-    <dimen name="recents_freeform_layout_task_padding">8dp</dimen>
-
-<!-- Recents Views -->
-
-    <!-- The height of a task view bar.  This has to be large enough to cover the action bar
-         height in either orientation at this smallest width. -->
-    <dimen name="recents_task_view_header_height">56dp</dimen>
-    <dimen name="recents_task_view_header_height_tablet_land">64dp</dimen>
-
-    <!-- The padding of a button in the recents task view header. -->
-    <dimen name="recents_task_view_header_button_padding">16dp</dimen>
-    <dimen name="recents_task_view_header_button_padding_tablet_land">20dp</dimen>
-
-    <!-- The radius of the rounded corners on a task view and its shadow (which can be larger
-         to create a softer corner effect. -->
-    <dimen name="recents_task_view_rounded_corners_radius">2dp</dimen>
-    <dimen name="recents_task_view_shadow_rounded_corners_radius">6dp</dimen>
-
-    <!-- The amount of highlight to make on each task view. -->
-    <dimen name="recents_task_view_highlight">1dp</dimen>
-
-    <!-- The size of the lock-to-app button and its icon. -->
-    <dimen name="recents_lock_to_app_size">56dp</dimen>
-    <dimen name="recents_lock_to_app_icon_size">28dp</dimen>
-
-    <!-- The amount of overscroll allowed when flinging to the end of the stack. -->
-    <dimen name="recents_fling_overscroll_distance">24dp</dimen>
-
-    <!-- The size of the drag hint text. -->
-    <dimen name="recents_drag_hint_text_size">14sp</dimen>
-
     <!-- The size of corner radius of the arrow in the onboarding toast. -->
     <dimen name="recents_onboarding_toast_arrow_corner_radius">2dp</dimen>
     <!-- The start margin of quick scrub onboarding toast. -->
     <dimen name="recents_quick_scrub_onboarding_margin_start">8dp</dimen>
 
-    <!-- The min alpha to apply to a task affiliation group color. -->
-    <item name="recents_task_affiliation_color_min_alpha_percentage" format="float" type="dimen">0.6</item>
-
-    <!-- The amount to offset when animating into an affiliate group. -->
-    <dimen name="recents_task_stack_animation_affiliate_enter_offset">32dp</dimen>
-
-    <!-- The offsets the tasks animate from when recents is launched while docking -->
-    <dimen name="recents_task_stack_animation_launched_while_docking_offset">144dp</dimen>
-
-    <!-- The amount to translate when animating the removal of a task. -->
-    <dimen name="recents_task_view_remove_anim_translation_x">100dp</dimen>
-
-    <!-- The alpha to apply to the recents row when it doesn't have focus -->
-    <item name="recents_recents_row_dim_alpha" format="float" type="dimen">0.5</item>
-
-    <!-- The speed in dp/s at which the user needs to be scrolling in recents such that we start
-         loading full resolution screenshots. -->
-    <dimen name="recents_fast_fling_velocity">600dp</dimen>
-
     <!-- The height of the gradient indicating the dismiss edge when moving a PIP. -->
     <dimen name="pip_dismiss_gradient_height">176dp</dimen>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 42e19aa..b92fcc6 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -24,26 +24,6 @@
          all of the currently visible notifications. [CHAR LIMIT=10]-->
     <string name="status_bar_clear_all_button">Clear</string>
 
-    <!-- Title shown in recents popup for removing an application from the list -->
-    <string name="status_bar_recent_remove_item_title">Remove from list</string>
-
-    <!-- Title shown in recents popup for inspecting an application's properties -->
-    <string name="status_bar_recent_inspect_item_title">App info</string>
-
-    <!-- Message shown in the middle of the screen after clicking on the recent apps button
-         when there are no recent apps to show. Also used for accessibility. [CHAR LIMIT=45]-->
-    <string name="status_bar_no_recent_apps">Your recent screens appear here</string>
-
-    <!-- Content description for the button to dismiss Recent Apps (only present on large
-         devices) -->
-    <string name="status_bar_accessibility_dismiss_recents">Dismiss recent apps</string>
-
-    <!-- Message that is read when you enter recent apps in TalkBack -->
-    <plurals name="status_bar_accessibility_recent_apps">
-        <item quantity="one">1 screen in Overview</item>
-        <item quantity="other">%d screens in Overview</item>
-    </plurals>
-
     <!-- The label in the bar at the top of the status bar when there are no notifications
          showing.  [CHAR LIMIT=40]-->
     <string name="status_bar_no_notifications_title">No notifications</string>
@@ -252,8 +232,6 @@
     <string name="voice_assist_label">open voice assist</string>
     <!-- Click action label for accessibility for the phone button. [CHAR LIMIT=NONE] -->
     <string name="camera_label">open camera</string>
-    <!-- Caption for "Recents resize" developer debug feature. [CHAR LIMIT=NONE] -->
-    <string name="recents_caption_resize">Select new task layout</string>
     <!-- Button name for "Cancel". [CHAR LIMIT=NONE] -->
     <string name="cancel">Cancel</string>
 
@@ -477,16 +455,6 @@
     <!-- Content description of the work mode icon in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_work_mode">@string/quick_settings_work_mode_label</string>
 
-    <!-- Content description to tell the user that this button will remove an application from recents -->
-    <string name="accessibility_recents_item_will_be_dismissed">Dismiss <xliff:g id="app" example="Calendar">%s</xliff:g>.</string>
-    <!-- Content description to tell the user an application has been removed from recents -->
-    <string name="accessibility_recents_item_dismissed"><xliff:g id="app" example="Calendar">%s</xliff:g> dismissed.</string>
-    <!-- Content description to tell the user all applications has been removed from recents -->
-    <string name="accessibility_recents_all_items_dismissed">All recent applications dismissed.</string>
-    <!-- Content description to tell the user that this button will open application info for an application in recents -->
-    <string name="accessibility_recents_item_open_app_info">Open <xliff:g id="app" example="Calendar">%s</xliff:g> application info.</string>
-    <!-- Content description to tell the user an application has been launched from recents -->
-    <string name="accessibility_recents_item_launched">Starting <xliff:g id="app" example="Calendar">%s</xliff:g>.</string>
     <!-- Content description to tell the user a notification has been removed from the notification shade -->
     <string name="accessibility_notification_dismissed">Notification dismissed.</string>
 
@@ -836,42 +804,10 @@
     <!-- QuickSettings: NFC (on) [CHAR LIMIT=NONE] -->
     <string name="quick_settings_nfc_on">NFC is enabled</string>
 
-    <!-- Recents: The empty recents string. [CHAR LIMIT=NONE] -->
-    <string name="recents_empty_message">No recent items</string>
-    <!-- Recents: The empty recents string after dismissing all tasks. [CHAR LIMIT=NONE] -->
-    <string name="recents_empty_message_dismissed_all">You\'ve cleared everything</string>
-    <!-- Recents: The info panel app info button string. [CHAR LIMIT=NONE] -->
-    <string name="recents_app_info_button_label">Application Info</string>
-    <!-- Recents: The screen pinning button. [CHAR LIMIT=NONE] -->
-    <string name="recents_lock_to_app_button_label">screen pinning</string>
-    <!-- Recents: Temporary string for the button in the recents search bar. [CHAR LIMIT=NONE] -->
-    <string name="recents_search_bar_label">search</string>
-    <!-- Recents: Launch error string. [CHAR LIMIT=NONE] -->
-    <string name="recents_launch_error_message">Could not start <xliff:g id="app" example="Calendar">%s</xliff:g>.</string>
-    <!-- Recents: Launch disabled string. [CHAR LIMIT=NONE] -->
-    <string name="recents_launch_disabled_message"><xliff:g id="app" example="Calendar">%s</xliff:g> is disabled in safe-mode.</string>
-    <!-- Recents: Stack action button string. [CHAR LIMIT=NONE] -->
-    <string name="recents_stack_action_button_label">Clear all</string>
-    <!-- Recents: Hint text that shows on the drop targets to start multiwindow. [CHAR LIMIT=NONE] -->
-    <string name="recents_drag_hint_message">Drag here to use split screen</string>
     <!-- Recents: Text that shows above the navigation bar after launching a few apps. [CHAR LIMIT=NONE] -->
     <string name="recents_swipe_up_onboarding">Swipe up to switch apps</string>
     <!-- Recents: Text that shows above the navigation bar after launching several apps. [CHAR LIMIT=NONE] -->
     <string name="recents_quick_scrub_onboarding">Drag right to quickly switch apps</string>
-
-    <!-- Recents: MultiStack add stack split horizontal radio button. [CHAR LIMIT=NONE] -->
-    <string name="recents_multistack_add_stack_dialog_split_horizontal">Split Horizontal</string>
-    <!-- Recents: MultiStack add stack split vertical radio button. [CHAR LIMIT=NONE] -->
-    <string name="recents_multistack_add_stack_dialog_split_vertical">Split Vertical</string>
-    <!-- Recents: MultiStack add stack split custom radio button. [CHAR LIMIT=NONE] -->
-    <string name="recents_multistack_add_stack_dialog_split_custom">Split Custom</string>
-    <!-- Recents: Accessibility split to the top -->
-    <string name="recents_accessibility_split_screen_top">Split screen to the top</string>
-    <!-- Recents: Accessibility split to the left -->
-    <string name="recents_accessibility_split_screen_left">Split screen to the left</string>
-    <!-- Recents: Accessibility split to the right -->
-    <string name="recents_accessibility_split_screen_right">Split screen to the right</string>
-
     <!-- QuickStep: Accessibility to toggle overview [CHAR LIMIT=40] -->
     <string name="quick_step_accessibility_toggle_overview">Toggle Overview</string>
 
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 6446367..6bc2a63 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -16,35 +16,6 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <style name="RecentsTheme" parent="@android:style/Theme.Material">
-        <!-- NoTitle -->
-        <item name="android:windowNoTitle">true</item>
-        <!-- Misc -->
-        <item name="android:statusBarColor">@android:color/transparent</item>
-        <item name="android:navigationBarColor">@android:color/transparent</item>
-        <item name="android:windowDrawsSystemBarBackgrounds">true</item>
-        <item name="android:windowAnimationStyle">@null</item>
-        <item name="android:ambientShadowAlpha">0.35</item>
-    </style>
-
-    <!-- Recents theme -->
-    <style name="RecentsTheme.Wallpaper">
-        <item name="android:windowBackground">@*android:color/transparent</item>
-        <item name="android:colorBackgroundCacheHint">@null</item>
-        <item name="android:windowShowWallpaper">true</item>
-        <item name="android:windowDisablePreview">true</item>
-        <item name="clearAllStyle">@style/ClearAllButtonDefaultMargins</item>
-        <item name="clearAllBackgroundColor">@color/recents_clear_all_button_bg_dark_color</item>
-        <item name="wallpaperTextColor">@*android:color/primary_text_material_dark</item>
-        <item name="wallpaperTextColorSecondary">@*android:color/secondary_text_material_dark</item>
-    </style>
-
-    <style name="RecentsTheme.Wallpaper.Light">
-        <item name="clearAllBackgroundColor">@color/recents_clear_all_button_bg_light_color</item>
-        <item name="wallpaperTextColor">@*android:color/primary_text_material_light</item>
-        <item name="wallpaperTextColorSecondary">@*android:color/secondary_text_material_light</item>
-    </style>
-
     <style name="ClearAllButtonDefaultMargins">
         <item name="android:layout_marginStart">0dp</item>
         <item name="android:layout_marginTop">0dp</item>
@@ -52,13 +23,6 @@
         <item name="android:layout_marginBottom">0dp</item>
     </style>
 
-    <!-- Performance optimized Recents theme (no wallpaper) -->
-    <style name="RecentsTheme.NoWallpaper">
-        <item name="android:windowBackground">@android:color/black</item>
-        <item name="wallpaperTextColor">@android:color/white</item>
-        <item name="wallpaperTextColorSecondary">@android:color/white</item>
-    </style>
-
     <!-- Theme used for the activity that shows when the system forced an app to be resizable -->
     <style name="ForcedResizableTheme" parent="@android:style/Theme.Translucent.NoTitleBar">
         <item name="android:windowBackground">@drawable/forced_resizable_background</item>
@@ -293,11 +257,6 @@
         <item name="android:windowExitAnimation">@*android:anim/shrink_fade_out_from_bottom</item>
     </style>
 
-    <style name="Animation.RecentPanel">
-        <item name="android:windowEnterAnimation">@*android:anim/grow_fade_in_from_bottom</item>
-        <item name="android:windowExitAnimation">@*android:anim/shrink_fade_out_from_bottom</item>
-    </style>
-
     <style name="Animation.NavigationBarFadeIn">
         <item name="android:windowEnterAnimation">@anim/navbar_fade_in</item>
         <item name="android:windowExitAnimation">@null</item>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
index 87f2934..82e8b3e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
@@ -246,7 +246,11 @@
                         SystemMessage.NOTE_PLUGIN, nb.build(), UserHandle.ALL);
             }
             if (clearClassLoader(pkg)) {
-                Toast.makeText(mContext, "Reloading " + pkg, Toast.LENGTH_LONG).show();
+                if (Build.IS_ENG) {
+                    Toast.makeText(mContext, "Reloading " + pkg, Toast.LENGTH_LONG).show();
+                } else {
+                    Log.v(TAG, "Reloading " + pkg);
+                }
             }
             if (!Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
                 for (PluginInstanceManager manager : mPluginMap.values()) {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
index 368e503..7558efae 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
@@ -143,7 +143,7 @@
      * The temporary sort index in the stack, used when ordering the stack.
      */
     @Deprecated
-    int temporarySortIndexInStack;
+    public int temporarySortIndexInStack;
 
     /**
      * The icon is the task description icon (if provided), which falls back to the activity icon,
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java
index 0ba2c3b..b2c79a4 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java
@@ -58,7 +58,7 @@
     }
 
     /** Trims the cache to a specific size */
-    final void trimToSize(int cacheSize) {
+    public final void trimToSize(int cacheSize) {
         mCache.trimToSize(cacheSize);
     }
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
index 7d159b7..7dffc26 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 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.
@@ -16,158 +16,19 @@
 
 package com.android.systemui.shared.recents.utilities;
 
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.RectEvaluator;
-import android.annotation.FloatRange;
-import android.annotation.Nullable;
-import android.app.Activity;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
 import android.graphics.Color;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.os.Message;
-import android.os.Trace;
-import android.util.ArraySet;
-import android.util.IntProperty;
-import android.util.Property;
-import android.util.TypedValue;
-import android.view.Surface;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.view.ViewRootImpl;
-import android.view.ViewStub;
-
-import java.util.ArrayList;
-import java.util.Collections;
 
 /* Common code */
 public class Utilities {
 
-    public static final Property<Drawable, Integer> DRAWABLE_ALPHA =
-            new IntProperty<Drawable>("drawableAlpha") {
-                @Override
-                public void setValue(Drawable object, int alpha) {
-                    object.setAlpha(alpha);
-                }
-
-                @Override
-                public Integer get(Drawable object) {
-                    return object.getAlpha();
-                }
-            };
-
-    public static final Property<Drawable, Rect> DRAWABLE_RECT =
-            new Property<Drawable, Rect>(Rect.class, "drawableBounds") {
-                @Override
-                public void set(Drawable object, Rect bounds) {
-                    object.setBounds(bounds);
-                }
-
-                @Override
-                public Rect get(Drawable object) {
-                    return object.getBounds();
-                }
-            };
-
-    public static final RectFEvaluator RECTF_EVALUATOR = new RectFEvaluator();
-    public static final RectEvaluator RECT_EVALUATOR = new RectEvaluator(new Rect());
-
     /**
-     * @return the first parent walking up the view hierarchy that has the given class type.
-     *
-     * @param parentClass must be a class derived from {@link View}
+     * Posts a runnable on a handler at the front of the queue ignoring any sync barriers.
      */
-    public static <T extends View> T findParent(View v, Class<T> parentClass) {
-        ViewParent parent = v.getParent();
-        while (parent != null) {
-            if (parentClass.isAssignableFrom(parent.getClass())) {
-                return (T) parent;
-            }
-            parent = parent.getParent();
-        }
-        return null;
-    }
-
-    /**
-     * Initializes the {@param setOut} with the given object.
-     */
-    public static <T> ArraySet<T> objectToSet(T obj, ArraySet<T> setOut) {
-        setOut.clear();
-        if (obj != null) {
-            setOut.add(obj);
-        }
-        return setOut;
-    }
-
-    /**
-     * Replaces the contents of {@param setOut} with the contents of the {@param array}.
-     */
-    public static <T> ArraySet<T> arrayToSet(T[] array, ArraySet<T> setOut) {
-        setOut.clear();
-        if (array != null) {
-            Collections.addAll(setOut, array);
-        }
-        return setOut;
-    }
-
-    /**
-     * @return the clamped {@param value} between the provided {@param min} and {@param max}.
-     */
-    public static float clamp(float value, float min, float max) {
-        return Math.max(min, Math.min(max, value));
-    }
-
-    /**
-     * @return the clamped {@param value} between the provided {@param min} and {@param max}.
-     */
-    public static int clamp(int value, int min, int max) {
-        return Math.max(min, Math.min(max, value));
-    }
-
-    /**
-     * @return the clamped {@param value} between 0 and 1.
-     */
-    public static float clamp01(float value) {
-        return Math.max(0f, Math.min(1f, value));
-    }
-
-    /**
-     * Scales the {@param value} to be proportionally between the {@param min} and
-     * {@param max} values.
-     *
-     * @param value must be between 0 and 1
-     */
-    public static float mapRange(@FloatRange(from=0.0,to=1.0) float value, float min, float max) {
-        return min + (value * (max - min));
-    }
-
-    /**
-     * Scales the {@param value} proportionally from {@param min} and {@param max} to 0 and 1.
-     *
-     * @param value must be between {@param min} and {@param max}
-     */
-    public static float unmapRange(float value, float min, float max) {
-        return (value - min) / (max - min);
-    }
-
-    /** Scales a rect about its centroid */
-    public static void scaleRectAboutCenter(RectF r, float scale) {
-        if (scale != 1.0f) {
-            float cx = r.centerX();
-            float cy = r.centerY();
-            r.offset(-cx, -cy);
-            r.left *= scale;
-            r.top *= scale;
-            r.right *= scale;
-            r.bottom *= scale;
-            r.offset(cx, cy);
-        }
+    public static void postAtFrontOfQueueAsynchronously(Handler h, Runnable r) {
+        Message msg = h.obtainMessage().setCallback(r);
+        h.sendMessageAtFrontOfQueue(msg);
     }
 
     /** Calculates the constrast between two colors, using the algorithm provided by the WCAG v2. */
@@ -179,7 +40,7 @@
         bgG = (bgG < 0.03928f) ? bgG / 12.92f : (float) Math.pow((bgG + 0.055f) / 1.055f, 2.4f);
         bgB = (bgB < 0.03928f) ? bgB / 12.92f : (float) Math.pow((bgB + 0.055f) / 1.055f, 2.4f);
         float bgL = 0.2126f * bgR + 0.7152f * bgG + 0.0722f * bgB;
-        
+
         float fgR = Color.red(fg) / 255f;
         float fgG = Color.green(fg) / 255f;
         float fgB = Color.blue(fg) / 255f;
@@ -191,147 +52,10 @@
         return Math.abs((fgL + 0.05f) / (bgL + 0.05f));
     }
 
-    /** Returns the base color overlaid with another overlay color with a specified alpha. */
-    public static int getColorWithOverlay(int baseColor, int overlayColor, float overlayAlpha) {
-        return Color.rgb(
-            (int) (overlayAlpha * Color.red(baseColor) +
-                    (1f - overlayAlpha) * Color.red(overlayColor)),
-            (int) (overlayAlpha * Color.green(baseColor) +
-                    (1f - overlayAlpha) * Color.green(overlayColor)),
-            (int) (overlayAlpha * Color.blue(baseColor) +
-                    (1f - overlayAlpha) * Color.blue(overlayColor)));
-    }
-
     /**
-     * Cancels an animation ensuring that if it has listeners, onCancel and onEnd
-     * are not called.
+     * @return the clamped {@param value} between the provided {@param min} and {@param max}.
      */
-    public static void cancelAnimationWithoutCallbacks(Animator animator) {
-        if (animator != null && animator.isStarted()) {
-            removeAnimationListenersRecursive(animator);
-            animator.cancel();
-        }
-    }
-
-    /**
-     * Recursively removes all the listeners of all children of this animator
-     */
-    public static void removeAnimationListenersRecursive(Animator animator) {
-        if (animator instanceof AnimatorSet) {
-            ArrayList<Animator> animators = ((AnimatorSet) animator).getChildAnimations();
-            for (int i = animators.size() - 1; i >= 0; i--) {
-                removeAnimationListenersRecursive(animators.get(i));
-            }
-        }
-        animator.removeAllListeners();
-    }
-
-    /**
-     * Sets the given {@link View}'s frame from its current translation.
-     */
-    public static void setViewFrameFromTranslation(View v) {
-        RectF taskViewRect = new RectF(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
-        taskViewRect.offset(v.getTranslationX(), v.getTranslationY());
-        v.setTranslationX(0);
-        v.setTranslationY(0);
-        v.setLeftTopRightBottom((int) taskViewRect.left, (int) taskViewRect.top,
-                (int) taskViewRect.right, (int) taskViewRect.bottom);
-    }
-
-    /**
-     * Returns a view stub for the given view id.
-     */
-    public static ViewStub findViewStubById(View v, int stubId) {
-        return (ViewStub) v.findViewById(stubId);
-    }
-
-    /**
-     * Returns a view stub for the given view id.
-     */
-    public static ViewStub findViewStubById(Activity a, int stubId) {
-        return (ViewStub) a.findViewById(stubId);
-    }
-
-    /**
-     * Used for debugging, converts DP to PX.
-     */
-    public static float dpToPx(Resources res, float dp) {
-        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, res.getDisplayMetrics());
-    }
-
-    /**
-     * Adds a trace event for debugging.
-     */
-    public static void addTraceEvent(String event) {
-        Trace.traceBegin(Trace.TRACE_TAG_VIEW, event);
-        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
-    }
-
-    /**
-     * Returns whether this view, or one of its descendants have accessibility focus.
-     */
-    public static boolean isDescendentAccessibilityFocused(View v) {
-        if (v.isAccessibilityFocused()) {
-            return true;
-        }
-
-        if (v instanceof ViewGroup) {
-            ViewGroup vg = (ViewGroup) v;
-            int childCount = vg.getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                if (isDescendentAccessibilityFocused(vg.getChildAt(i))) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Returns the application configuration, which is independent of the activity's current
-     * configuration in multiwindow.
-     */
-    public static Configuration getAppConfiguration(Context context) {
-        return context.getApplicationContext().getResources().getConfiguration();
-    }
-
-    /**
-     * @return The next frame name for the specified surface or -1 if the surface is no longer
-     *         valid.
-     */
-    public static long getNextFrameNumber(Surface s) {
-        return s != null && s.isValid()
-                ? s.getNextFrameNumber()
-                : -1;
-
-    }
-
-    /**
-     * @return The surface for the specified view.
-     */
-    public static @Nullable Surface getSurface(View v) {
-        ViewRootImpl viewRoot = v.getViewRootImpl();
-        if (viewRoot == null) {
-            return null;
-        }
-        return viewRoot.mSurface;
-    }
-
-    /**
-     * Returns a lightweight dump of a rect.
-     */
-    public static String dumpRect(Rect r) {
-        if (r == null) {
-            return "N:0,0-0,0";
-        }
-        return r.left + "," + r.top + "-" + r.right + "," + r.bottom;
-    }
-
-    /**
-     * Posts a runnable on a handler at the front of the queue ignoring any sync barriers.
-     */
-    public static void postAtFrontOfQueueAsynchronously(Handler h, Runnable r) {
-        Message msg = h.obtainMessage().setCallback(r);
-        h.sendMessageAtFrontOfQueue(msg);
+    public static float clamp(float value, float min, float max) {
+        return Math.max(min, Math.min(max, value));
     }
 }
diff --git a/packages/SystemUI/shared/tests/Android.mk b/packages/SystemUI/shared/tests/Android.mk
deleted file mode 100644
index 02774c9..0000000
--- a/packages/SystemUI/shared/tests/Android.mk
+++ /dev/null
@@ -1,59 +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.
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_JACK_FLAGS := --multi-dex native
-LOCAL_DX_FLAGS := --multi-dex
-
-LOCAL_PROTOC_OPTIMIZE_TYPE := nano
-LOCAL_PROTOC_FLAGS := -I$(LOCAL_PATH)/..
-LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors
-
-LOCAL_PACKAGE_NAME := SystemUISharedLibTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-# Add local path sources as well as shared lib sources
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-	SystemUISharedLib \
-    metrics-helper-lib \
-    android-support-test \
-    mockito-target-inline-minus-junit4 \
-    SystemUI-proto \
-    SystemUI-tags \
-    testables \
-    truth-prebuilt \
-
-LOCAL_MULTILIB := both
-
-LOCAL_JNI_SHARED_LIBRARIES := \
-    libdexmakerjvmtiagent \
-    libmultiplejvmtiagentsinterferenceagent
-
-LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common
-
-# sign this with platform cert, so this test is allowed to inject key events into
-# UI it doesn't own. This is necessary to allow screenshots to be taken
-LOCAL_CERTIFICATE := platform
-
-ifeq ($(EXCLUDE_SYSTEMUI_TESTS),)
-    include $(BUILD_PACKAGE)
-endif
diff --git a/packages/SystemUI/shared/tests/AndroidManifest.xml b/packages/SystemUI/shared/tests/AndroidManifest.xml
deleted file mode 100644
index 5974b76..0000000
--- a/packages/SystemUI/shared/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,30 +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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.systemui.shared.tests">
-
-    <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
-
-    <application android:debuggable="true">
-        <uses-library android:name="android.test.runner" />
-    </application>
-
-    <instrumentation android:name="android.testing.TestableInstrumentation"
-        android:targetPackage="com.android.systemui.shared.tests"
-        android:label="Tests for SystemUISharedLib">
-    </instrumentation>
-</manifest>
diff --git a/packages/SystemUI/shared/tests/AndroidTest.xml b/packages/SystemUI/shared/tests/AndroidTest.xml
deleted file mode 100644
index b3de836..0000000
--- a/packages/SystemUI/shared/tests/AndroidTest.xml
+++ /dev/null
@@ -1,28 +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.
--->
-<configuration description="Runs Tests for SystemUISharedLib.">
-    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
-        <option name="test-file-name" value="SystemUISharedLibTests.apk" />
-    </target_preparer>
-
-    <option name="test-suite-tag" value="apct" />
-    <option name="test-suite-tag" value="framework-base-presubmit" />
-    <option name="test-tag" value="SystemUISharedLibTests" />
-    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
-        <option name="package" value="com.android.systemui.shared.tests" />
-        <option name="runner" value="android.testing.TestableInstrumentation" />
-    </test>
-</configuration>
diff --git a/packages/SystemUI/shared/tests/src/com/android/systemui/shared/SysuiSharedLibTestCase.java b/packages/SystemUI/shared/tests/src/com/android/systemui/shared/SysuiSharedLibTestCase.java
deleted file mode 100644
index 04b341e..0000000
--- a/packages/SystemUI/shared/tests/src/com/android/systemui/shared/SysuiSharedLibTestCase.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2014 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.systemui.shared;
-
-import android.content.Context;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.MessageQueue;
-import android.support.test.InstrumentationRegistry;
-
-import org.junit.After;
-import org.junit.Before;
-
-/**
- * Base class that does System UI Shared Lib specific setup.
- */
-public abstract class SysuiSharedLibTestCase {
-
-    private static final String TAG = "SysuiSharedLibTestCase";
-
-    private Handler mHandler;
-    private Context mContext = InstrumentationRegistry.getContext();
-
-    @Before
-    public void SysuiSetup() throws Exception {
-        // Enable shared class loader to test package-private classes/methods
-        System.setProperty("dexmaker.share_classloader", "true");
-    }
-
-    @After
-    public void SysuiTeardown() {
-        // Do nothing
-    }
-
-    public Context getContext() {
-        return mContext;
-    }
-
-    protected void waitForIdleSync() {
-        if (mHandler == null) {
-            mHandler = new Handler(Looper.getMainLooper());
-        }
-        waitForIdleSync(mHandler);
-    }
-
-    public static void waitForIdleSync(Handler h) {
-        validateThread(h.getLooper());
-        Idler idler = new Idler(null);
-        h.getLooper().getQueue().addIdleHandler(idler);
-        // Ensure we are non-idle, so the idle handler can run.
-        h.post(new EmptyRunnable());
-        idler.waitForIdle();
-    }
-
-    private static final void validateThread(Looper l) {
-        if (Looper.myLooper() == l) {
-            throw new RuntimeException(
-                "This method can not be called from the looper being synced");
-        }
-    }
-
-    public static final class EmptyRunnable implements Runnable {
-        public void run() {
-        }
-    }
-
-    public static final class Idler implements MessageQueue.IdleHandler {
-        private final Runnable mCallback;
-        private boolean mIdle;
-
-        public Idler(Runnable callback) {
-            mCallback = callback;
-            mIdle = false;
-        }
-
-        @Override
-        public boolean queueIdle() {
-            if (mCallback != null) {
-                mCallback.run();
-            }
-            synchronized (this) {
-                mIdle = true;
-                notifyAll();
-            }
-            return false;
-        }
-
-        public void waitForIdle() {
-            synchronized (this) {
-                while (!mIdle) {
-                    try {
-                        wait();
-                    } catch (InterruptedException e) {
-                    }
-                }
-            }
-        }
-    }
-}
diff --git a/packages/SystemUI/shared/tests/src/com/android/systemui/shared/recents/model/HighResThumbnailLoaderTest.java b/packages/SystemUI/shared/tests/src/com/android/systemui/shared/recents/model/HighResThumbnailLoaderTest.java
deleted file mode 100644
index 3b647c1..0000000
--- a/packages/SystemUI/shared/tests/src/com/android/systemui/shared/recents/model/HighResThumbnailLoaderTest.java
+++ /dev/null
@@ -1,129 +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.systemui.shared.recents.model;
-
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.anyBoolean;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.ComponentName;
-import android.os.Looper;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
-import com.android.systemui.shared.SysuiSharedLibTestCase;
-import com.android.systemui.shared.recents.model.Task.TaskKey;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-/**
- * runtest --path frameworks/base/packages/SystemUI/shared/tests/src/com/android/systemui/shared/recents/model/HighResThumbnailLoaderTest.java
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class HighResThumbnailLoaderTest extends SysuiSharedLibTestCase {
-
-    private HighResThumbnailLoader mLoader;
-
-    @Mock
-    private ActivityManagerWrapper mMockActivityManagerWrapper;
-    @Mock
-    private Task mTask;
-
-    private ThumbnailData mThumbnailData = new ThumbnailData();
-
-    @Before
-    public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        mLoader = new HighResThumbnailLoader(mMockActivityManagerWrapper, Looper.getMainLooper(),
-                false /* reducedResolution */);
-        mTask.key = new TaskKey(0, WINDOWING_MODE_UNDEFINED, null, null, 0, 0);
-        when(mMockActivityManagerWrapper.getTaskThumbnail(anyInt(), anyBoolean()))
-                .thenReturn(mThumbnailData);
-        mLoader.setVisible(true);
-        mLoader.setTaskLoadQueueIdle(true);
-    }
-
-    @Test
-    public void testLoading() throws Exception {
-        mLoader.setVisible(true);
-        assertTrue(mLoader.isLoading());
-        mLoader.setVisible(false);
-        assertFalse(mLoader.isLoading());
-        mLoader.setVisible(true);
-        mLoader.setFlingingFast(true);
-        assertFalse(mLoader.isLoading());
-        mLoader.setFlingingFast(false);
-        assertTrue(mLoader.isLoading());
-        mLoader.setFlingingFast(false);
-        mLoader.setTaskLoadQueueIdle(false);
-        assertFalse(mLoader.isLoading());
-        mLoader.setTaskLoadQueueIdle(true);
-        assertTrue(mLoader.isLoading());
-    }
-
-    @Test
-    public void testLoad() throws Exception {
-        mLoader.onTaskVisible(mTask);
-        mLoader.waitForLoaderIdle();
-        waitForIdleSync();
-        verify(mTask).notifyTaskDataLoaded(mThumbnailData, null);
-    }
-
-    @Test
-    public void testFlinging_notLoaded() throws Exception {
-        mLoader.setFlingingFast(true);
-        mLoader.onTaskVisible(mTask);
-        mLoader.waitForLoaderIdle();
-        waitForIdleSync();
-        verify(mTask, never()).notifyTaskDataLoaded(mThumbnailData, null);
-    }
-
-    /**
-     * Tests whether task is loaded after stopping to fling
-     */
-    @Test
-    public void testAfterFlinging() throws Exception {
-        mLoader.setFlingingFast(true);
-        mLoader.onTaskVisible(mTask);
-        mLoader.setFlingingFast(false);
-        mLoader.waitForLoaderIdle();
-        waitForIdleSync();
-        verify(mTask).notifyTaskDataLoaded(mThumbnailData, null);
-    }
-
-    @Test
-    public void testAlreadyLoaded() throws Exception {
-        mTask.thumbnail = new ThumbnailData();
-        mTask.thumbnail.reducedResolution = false;
-        mLoader.onTaskVisible(mTask);
-        mLoader.waitForLoaderIdle();
-        waitForIdleSync();
-        verify(mTask, never()).notifyTaskDataLoaded(mThumbnailData, null);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index c7685f8..6b0a7a9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -88,6 +88,7 @@
 import com.android.settingslib.WirelessUtils;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.TaskStackChangeListener;
+
 import com.google.android.collect.Lists;
 
 import java.io.FileDescriptor;
@@ -236,6 +237,8 @@
     private boolean mIsDreaming;
     private final DevicePolicyManager mDevicePolicyManager;
     private boolean mLogoutEnabled;
+    private boolean mFingerprintLockedOut;
+    private boolean mFaceLockedOut;
 
     /**
      * Short delay before restarting biometric authentication after a successful try
@@ -624,7 +627,7 @@
         if (msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED
                 && mFingerprintRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING) {
             setFingerprintRunningState(BIOMETRIC_STATE_STOPPED);
-            startListeningForFingerprint();
+            updateFingerprintListeningState();
         } else {
             setFingerprintRunningState(BIOMETRIC_STATE_STOPPED);
         }
@@ -637,6 +640,11 @@
             }
         }
 
+        if (msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT
+                || msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT) {
+            mFingerprintLockedOut = true;
+        }
+
         if (msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT) {
             mLockPatternUtils.requireStrongAuth(
                     LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT,
@@ -652,6 +660,7 @@
     }
 
     private void handleFingerprintLockoutReset() {
+        mFingerprintLockedOut = false;
         updateFingerprintListeningState();
     }
 
@@ -659,7 +668,7 @@
         boolean wasRunning = mFingerprintRunningState == BIOMETRIC_STATE_RUNNING;
         boolean isRunning = fingerprintRunningState == BIOMETRIC_STATE_RUNNING;
         mFingerprintRunningState = fingerprintRunningState;
-
+        if (DEBUG) Log.v(TAG, "Fingerprint State: " + mFingerprintRunningState);
         // Clients of KeyguardUpdateMonitor don't care about the internal state about the
         // asynchronousness of the cancel cycle. So only notify them if the actualy running state
         // has changed.
@@ -774,7 +783,7 @@
         if (msgId == FaceManager.FACE_ERROR_CANCELED
                 && mFaceRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING) {
             setFaceRunningState(BIOMETRIC_STATE_STOPPED);
-            startListeningForFace();
+            updateFaceListeningState();
         } else {
             setFaceRunningState(BIOMETRIC_STATE_STOPPED);
         }
@@ -787,6 +796,11 @@
             }
         }
 
+        if (msgId == FaceManager.FACE_ERROR_LOCKOUT
+                || msgId == FaceManager.FACE_ERROR_LOCKOUT_PERMANENT) {
+            mFaceLockedOut = true;
+        }
+
         if (msgId == FaceManager.FACE_ERROR_LOCKOUT_PERMANENT) {
             mLockPatternUtils.requireStrongAuth(
                     LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT,
@@ -803,6 +817,7 @@
     }
 
     private void handleFaceLockoutReset() {
+        mFaceLockedOut = false;
         updateFaceListeningState();
     }
 
@@ -810,7 +825,7 @@
         boolean wasRunning = mFaceRunningState == BIOMETRIC_STATE_RUNNING;
         boolean isRunning = faceRunningState == BIOMETRIC_STATE_RUNNING;
         mFaceRunningState = faceRunningState;
-
+        if (DEBUG) Log.v(TAG, "Face State: " + mFaceRunningState);
         // Clients of KeyguardUpdateMonitor don't care about the internal state or about the
         // asynchronousness of the cancel cycle. So only notify them if the actualy running state
         // has changed.
@@ -1557,7 +1572,7 @@
                 (mBouncer && !mKeyguardGoingAway) || mGoingToSleep ||
                 shouldListenForFingerprintAssistant() || (mKeyguardOccluded && mIsDreaming))
                 && !mSwitchingUser && !isFingerprintDisabled(getCurrentUser())
-                && !mKeyguardGoingAway;
+                && !mKeyguardGoingAway && !mFingerprintLockedOut;
     }
 
     private boolean shouldListenForFace() {
@@ -1565,7 +1580,7 @@
                 (mBouncer && !mKeyguardGoingAway) || mGoingToSleep ||
                 shouldListenForFaceAssistant() || (mKeyguardOccluded && mIsDreaming))
                 && !mSwitchingUser && !isFaceDisabled(getCurrentUser())
-                && !mKeyguardGoingAway && mFaceSettingEnabledForUser;
+                && !mKeyguardGoingAway && !mFaceLockedOut && mFaceSettingEnabledForUser;
     }
 
 
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 26fb486..b7844bc 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -22,6 +22,7 @@
 import android.os.Looper;
 import android.os.Process;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.DisplayMetrics;
 import android.view.IWindowManager;
@@ -43,13 +44,14 @@
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.PluginDependencyProvider;
 import com.android.systemui.plugins.PluginInitializerImpl;
+import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.shared.plugins.PluginManagerImpl;
 import com.android.systemui.plugins.VolumeDialogController;
 import com.android.systemui.power.EnhancedEstimates;
 import com.android.systemui.power.EnhancedEstimatesImpl;
 import com.android.systemui.power.PowerNotificationWarnings;
 import com.android.systemui.power.PowerUI;
-import com.android.systemui.shared.plugins.PluginManager;
-import com.android.systemui.shared.plugins.PluginManagerImpl;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment;
@@ -302,7 +304,8 @@
                 new PluginDependencyProvider(get(PluginManager.class)));
 
         mProviders.put(LocalBluetoothManager.class, () ->
-                LocalBluetoothManager.create(mContext, getDependency(BG_HANDLER)));
+                LocalBluetoothManager.create(mContext, getDependency(BG_HANDLER),
+                        UserHandle.ALL));
 
         mProviders.put(VolumeDialogController.class, () ->
                 new VolumeDialogControllerImpl(mContext));
diff --git a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
deleted file mode 100644
index fb343f9..0000000
--- a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2013 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.systemui;
-
-import android.graphics.Rect;
-import android.view.Display;
-import android.view.View;
-
-public interface RecentsComponent {
-    void showRecentApps(boolean triggeredFromAltTab);
-
-    /**
-     * Docks the top-most task and opens recents.
-     */
-    boolean splitPrimaryTask(int stackCreateMode, Rect initialBounds,
-            int metricsDockAction);
-}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java b/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java
index 36dbb0f..e0fc31b 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java
@@ -21,9 +21,11 @@
 
 import java.io.PrintWriter;
 
-public interface  BasePipManager {
+public interface BasePipManager {
     void initialize(Context context);
     void showPictureInPictureMenu();
+    default void expandPip() {}
+    default void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) {}
     void onConfigurationChanged(Configuration newConfig);
-    void dump(PrintWriter pw);
+    default void dump(PrintWriter pw) {}
 }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipUI.java b/packages/SystemUI/src/com/android/systemui/pip/PipUI.java
index 864a6f9..70b581a 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipUI.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipUI.java
@@ -24,8 +24,6 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import com.android.systemui.SystemUI;
-import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.component.ExpandPipEvent;
 import com.android.systemui.statusbar.CommandQueue;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -68,7 +66,11 @@
     }
 
     public void expandPip() {
-        EventBus.getDefault().send(new ExpandPipEvent());
+        mPipManager.expandPip();
+    }
+
+    public void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) {
+        mPipManager.hidePipMenu(onStartCallback, onEndCallback);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index 04746c1..08208e5 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -38,8 +38,6 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.UiOffloadThread;
 import com.android.systemui.pip.BasePipManager;
-import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.component.ExpandPipEvent;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.InputConsumerController;
 import com.android.systemui.shared.system.TaskStackChangeListener;
@@ -197,7 +195,6 @@
                 mMenuController, mInputConsumerController);
         mAppOpsListener = new PipAppOpsListener(context, mActivityManager,
                 mTouchHandler.getMotionHelper());
-        EventBus.getDefault().register(this);
     }
 
     /**
@@ -210,11 +207,20 @@
     /**
      * Expands the PIP.
      */
-    public final void onBusEvent(ExpandPipEvent event) {
+    @Override
+    public void expandPip() {
         mTouchHandler.getMotionHelper().expandPip(false /* skipAnimation */);
     }
 
     /**
+     * Hides the PIP menu.
+     */
+    @Override
+    public void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) {
+        mMenuController.hideMenu(onStartCallback, onEndCallback);
+    }
+
+    /**
      * Sent from KEYCODE_WINDOW handler in PhoneWindowManager, to request the menu to be shown.
      */
     public void showPictureInPictureMenu() {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index 2dc531a..b746c19 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -72,8 +72,6 @@
 
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.component.HidePipMenuEvent;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -151,7 +149,7 @@
                     cancelDelayedFinish();
                     break;
                 case MESSAGE_HIDE_MENU:
-                    hideMenu();
+                    hideMenu((Runnable) msg.obj);
                     break;
                 case MESSAGE_UPDATE_ACTIONS: {
                     final Bundle data = (Bundle) msg.obj;
@@ -275,7 +273,6 @@
         super.onStop();
 
         cancelDelayedFinish();
-        EventBus.getDefault().unregister(this);
     }
 
     @Override
@@ -335,19 +332,6 @@
         // Do nothing
     }
 
-    public final void onBusEvent(HidePipMenuEvent event) {
-        if (mMenuState != MENU_STATE_NONE) {
-            // If the menu is visible in either the closed or full state, then hide the menu and
-            // trigger the animation trigger afterwards
-            event.getAnimationTrigger().increment();
-            hideMenu(() -> {
-                mHandler.post(() -> {
-                    event.getAnimationTrigger().decrement();
-                });
-            }, true /* notifyMenuVisibility */, false /* isDismissing */);
-        }
-    }
-
     private void showMenu(int menuState, Rect stackBounds, Rect movementBounds,
             boolean allowMenuTimeout, boolean resizeMenuOnShow) {
         mAllowMenuTimeout = allowMenuTimeout;
@@ -398,8 +382,11 @@
     }
 
     private void hideMenu() {
-        hideMenu(null /* animationFinishedRunnable */, true /* notifyMenuVisibility */,
-                false /* isDismissing */);
+        hideMenu(null);
+    }
+
+    private void hideMenu(Runnable animationEndCallback) {
+        hideMenu(animationEndCallback, true /* notifyMenuVisibility */, false /* isDismissing */);
     }
 
     private void hideMenu(final Runnable animationFinishedRunnable, boolean notifyMenuVisibility,
@@ -450,9 +437,6 @@
         }
         notifyActivityCallback(mMessenger);
 
-        // Register for HidePipMenuEvents once we notify the controller of this activity
-        EventBus.getDefault().register(this);
-
         ParceledListSlice actions = intent.getParcelableExtra(EXTRA_ACTIONS);
         if (actions != null) {
             mActions.clear();
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
index 360fe73..56b8324 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
@@ -19,9 +19,9 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 
-import android.app.ActivityTaskManager;
 import android.app.ActivityManager.StackInfo;
 import android.app.ActivityOptions;
+import android.app.ActivityTaskManager;
 import android.app.IActivityManager;
 import android.app.RemoteAction;
 import android.content.Context;
@@ -37,14 +37,8 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.util.Log;
-import android.view.IWindowManager;
-
 import com.android.systemui.pip.phone.PipMediaController.ActionListener;
-import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.component.HidePipMenuEvent;
-import com.android.systemui.recents.misc.ReferenceCountedTrigger;
 import com.android.systemui.shared.system.InputConsumerController;
-
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
@@ -131,7 +125,7 @@
     // The dismiss fraction update is sent frequently, so use a temporary bundle for the message
     private Bundle mTmpDismissFractionData = new Bundle();
 
-    private ReferenceCountedTrigger mOnAttachDecrementTrigger;
+    private Runnable mOnAnimationEndRunnable;
     private boolean mStartActivityRequested;
     private long mStartActivityRequestedTime;
     private Messenger mToActivityMessenger;
@@ -171,9 +165,9 @@
                 case MESSAGE_UPDATE_ACTIVITY_CALLBACK: {
                     mToActivityMessenger = msg.replyTo;
                     setStartActivityRequested(false);
-                    if (mOnAttachDecrementTrigger != null) {
-                        mOnAttachDecrementTrigger.decrement();
-                        mOnAttachDecrementTrigger = null;
+                    if (mOnAnimationEndRunnable != null) {
+                        mOnAnimationEndRunnable.run();
+                        mOnAnimationEndRunnable = null;
                     }
                     // Mark the menu as invisible once the activity finishes as well
                     if (mToActivityMessenger == null) {
@@ -188,9 +182,9 @@
 
     private Runnable mStartActivityRequestedTimeoutRunnable = () -> {
         setStartActivityRequested(false);
-        if (mOnAttachDecrementTrigger != null) {
-            mOnAttachDecrementTrigger.decrement();
-            mOnAttachDecrementTrigger = null;
+        if (mOnAnimationEndRunnable != null) {
+            mOnAnimationEndRunnable.run();
+            mOnAnimationEndRunnable = null;
         }
         Log.e(TAG, "Expected start menu activity request timed out");
     };
@@ -209,8 +203,6 @@
         mActivityManager = activityManager;
         mMediaController = mediaController;
         mInputConsumerController = inputConsumerController;
-
-        EventBus.getDefault().register(this);
     }
 
     public boolean isMenuActivityVisible() {
@@ -353,6 +345,36 @@
     }
 
     /**
+     * Hides the menu activity.
+     */
+    public void hideMenu(Runnable onStartCallback, Runnable onEndCallback) {
+        if (mStartActivityRequested) {
+            // If the menu has been start-requested, but not actually started, then we defer the
+            // trigger callback until the menu has started and called back to the controller.
+            mOnAnimationEndRunnable = onEndCallback;
+            onStartCallback.run();
+
+            // Fallback for b/63752800, we have started the PipMenuActivity but it has not made any
+            // callbacks. Don't continue to wait for the menu to show past some timeout.
+            mHandler.removeCallbacks(mStartActivityRequestedTimeoutRunnable);
+            mHandler.postDelayed(mStartActivityRequestedTimeoutRunnable,
+                    START_ACTIVITY_REQUEST_TIMEOUT_MS);
+        } else if (mMenuState != MENU_STATE_NONE && mToActivityMessenger != null) {
+            // If the menu is visible in either the closed or full state, then hide the menu and
+            // trigger the animation trigger afterwards
+            onStartCallback.run();
+            Message m = Message.obtain();
+            m.what = PipMenuActivity.MESSAGE_HIDE_MENU;
+            m.obj = onEndCallback;
+            try {
+                mToActivityMessenger.send(m);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Could not notify hide menu", e);
+            }
+        }
+    }
+
+    /**
      * Preemptively mark the menu as invisible, used when we are directly manipulating the pinned
      * stack and don't want to trigger a resize which can animate the stack in a conflicting way
      * (ie. when manually expanding or dismissing).
@@ -496,21 +518,6 @@
         mStartActivityRequestedTime = requested ? SystemClock.uptimeMillis() : 0;
     }
 
-    public final void onBusEvent(HidePipMenuEvent event) {
-        if (mStartActivityRequested) {
-            // If the menu has been start-requested, but not actually started, then we defer the
-            // trigger callback until the menu has started and called back to the controller.
-            mOnAttachDecrementTrigger = event.getAnimationTrigger();
-            mOnAttachDecrementTrigger.increment();
-
-            // Fallback for b/63752800, we have started the PipMenuActivity but it has not made any
-            // callbacks. Don't continue to wait for the menu to show past some timeout.
-            mHandler.removeCallbacks(mStartActivityRequestedTimeoutRunnable);
-            mHandler.postDelayed(mStartActivityRequestedTimeoutRunnable,
-                    START_ACTIVITY_REQUEST_TIMEOUT_MS);
-        }
-    }
-
     public void dump(PrintWriter pw, String prefix) {
         final String innerPrefix = prefix + "  ";
         pw.println(prefix + TAG);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index 43e9db7..e17e0bc 100755
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -758,9 +758,4 @@
             WindowManagerWrapper.getInstance().setPipVisibility(visible);
         });
     }
-
-    @Override
-    public void dump(PrintWriter pw) {
-        // Do nothing
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
new file mode 100644
index 0000000..661b958
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2014 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.systemui.recents;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+
+import android.app.ActivityManager;
+import android.app.trust.TrustManager;
+import android.content.Context;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.hardware.display.DisplayManager;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.Display;
+import android.widget.Toast;
+import com.android.systemui.Dependency;
+import com.android.systemui.R;
+import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.shared.recents.IOverviewProxy;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.statusbar.phone.StatusBar;
+
+/**
+ * An implementation of the Recents interface which proxies to the OverviewProxyService.
+ */
+public class OverviewProxyRecentsImpl implements RecentsImplementation {
+
+    private final static String TAG = "OverviewProxyRecentsImpl";
+
+    private SysUiServiceProvider mSysUiServiceProvider;
+    private Context mContext;
+    private Handler mHandler;
+    private TrustManager mTrustManager;
+    private OverviewProxyService mOverviewProxyService;
+
+    @Override
+    public void onStart(Context context, SysUiServiceProvider sysUiServiceProvider) {
+        mContext = context;
+        mSysUiServiceProvider = sysUiServiceProvider;
+        mHandler = new Handler();
+        mTrustManager = (TrustManager) context.getSystemService(Context.TRUST_SERVICE);
+        mOverviewProxyService = Dependency.get(OverviewProxyService.class);
+    }
+
+    @Override
+    public void showRecentApps(boolean triggeredFromAltTab) {
+        IOverviewProxy overviewProxy = mOverviewProxyService.getProxy();
+        if (overviewProxy != null) {
+            try {
+                overviewProxy.onOverviewShown(triggeredFromAltTab);
+                return;
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to send overview show event to launcher.", e);
+            }
+        } else {
+            // Do nothing
+        }
+    }
+
+    @Override
+    public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
+        IOverviewProxy overviewProxy = mOverviewProxyService.getProxy();
+        if (overviewProxy != null) {
+            try {
+                overviewProxy.onOverviewHidden(triggeredFromAltTab, triggeredFromHomeKey);
+                return;
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to send overview hide event to launcher.", e);
+            }
+        } else {
+            // Do nothing
+        }
+    }
+
+    @Override
+    public void toggleRecentApps() {
+        // If connected to launcher service, let it handle the toggle logic
+        IOverviewProxy overviewProxy = mOverviewProxyService.getProxy();
+        if (overviewProxy != null) {
+            final Runnable toggleRecents = () -> {
+                try {
+                    if (mOverviewProxyService.getProxy() != null) {
+                        mOverviewProxyService.getProxy().onOverviewToggle();
+                    }
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Cannot send toggle recents through proxy service.", e);
+                }
+            };
+            // Preload only if device for current user is unlocked
+            final StatusBar statusBar = mSysUiServiceProvider.getComponent(StatusBar.class);
+            if (statusBar != null && statusBar.isKeyguardShowing()) {
+                statusBar.executeRunnableDismissingKeyguard(() -> {
+                        // Flush trustmanager before checking device locked per user
+                        mTrustManager.reportKeyguardShowingChanged();
+                        mHandler.post(toggleRecents);
+                    }, null,  true /* dismissShade */, false /* afterKeyguardGone */,
+                    true /* deferred */);
+            } else {
+                toggleRecents.run();
+            }
+            return;
+        } else {
+            // Do nothing
+        }
+    }
+
+    @Override
+    public boolean splitPrimaryTask(int stackCreateMode, Rect initialBounds,
+            int metricsDockAction) {
+        Point realSize = new Point();
+        if (initialBounds == null) {
+            mContext.getSystemService(DisplayManager.class).getDisplay(Display.DEFAULT_DISPLAY)
+                    .getRealSize(realSize);
+            initialBounds = new Rect(0, 0, realSize.x, realSize.y);
+        }
+
+        ActivityManager.RunningTaskInfo runningTask =
+                ActivityManagerWrapper.getInstance().getRunningTask();
+        final int activityType = runningTask != null
+                ? runningTask.configuration.windowConfiguration.getActivityType()
+                : ACTIVITY_TYPE_UNDEFINED;
+        boolean screenPinningActive = ActivityManagerWrapper.getInstance().isScreenPinningActive();
+        boolean isRunningTaskInHomeOrRecentsStack =
+                activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS;
+        if (runningTask != null && !isRunningTaskInHomeOrRecentsStack && !screenPinningActive) {
+            if (runningTask.supportsSplitScreenMultiWindow) {
+                if (ActivityManagerWrapper.getInstance().setTaskWindowingModeSplitScreenPrimary(
+                        runningTask.id, stackCreateMode, initialBounds)) {
+                    // The overview service is handling split screen, so just skip the wait for the
+                    // first draw and notify the divider to start animating now
+                    final Divider divider = mSysUiServiceProvider.getComponent(Divider.class);
+                    if (divider != null) {
+                        divider.onRecentsDrawn();
+                    }
+                    return true;
+                }
+            } else {
+                Toast.makeText(mContext, R.string.dock_non_resizeble_failed_to_dock_text,
+                        Toast.LENGTH_SHORT).show();
+            }
+        }
+        return false;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
rename to packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 1bf8750..19f7675 100644
--- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package com.android.systemui;
+package com.android.systemui.recents;
 
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
 import static android.view.MotionEvent.ACTION_DOWN;
@@ -42,7 +42,11 @@
 import android.provider.Settings;
 import android.util.Log;
 import android.view.MotionEvent;
-import com.android.systemui.OverviewProxyService.OverviewProxyListener;
+import com.android.systemui.Dependency;
+import com.android.systemui.Dumpable;
+import com.android.systemui.Prefs;
+import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
 import com.android.systemui.shared.recents.IOverviewProxy;
 import com.android.systemui.shared.recents.ISystemUiProxy;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 74f6c2d..de22d21 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -16,232 +16,29 @@
 
 package com.android.systemui.recents;
 
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS;
-
-import android.app.ActivityManager;
-import android.app.trust.TrustManager;
-import android.content.ComponentName;
 import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.Point;
 import android.graphics.Rect;
-import android.hardware.display.DisplayManager;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.UserHandle;
 import android.provider.Settings;
-import android.util.EventLog;
-import android.util.Log;
-import android.view.Display;
-import android.widget.Toast;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.Dependency;
-import com.android.systemui.EventLogConstants;
-import com.android.systemui.EventLogTags;
-import com.android.systemui.OverviewProxyService;
 import com.android.systemui.R;
-import com.android.systemui.RecentsComponent;
-import com.android.systemui.SystemUIApplication;
-import com.android.systemui.recents.events.ui.RecentsGrowingEvent;
-import com.android.systemui.shared.recents.IOverviewProxy;
 import com.android.systemui.SystemUI;
-import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
-import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent;
-import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
-import com.android.systemui.recents.events.activity.LaunchTaskFailedEvent;
-import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
-import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
-import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
-import com.android.systemui.recents.events.component.SetWaitingForTransitionStartEvent;
-import com.android.systemui.recents.events.component.ShowUserToastEvent;
-import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.shared.recents.model.RecentsTaskLoader;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.statusbar.CommandQueue;
-
-import com.android.systemui.statusbar.phone.StatusBar;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Set;
-
 
 /**
- * An implementation of the SystemUI recents component, which supports both system and secondary
- * users.
+ * A proxy to a Recents implementation.
  */
-public class Recents extends SystemUI
-        implements RecentsComponent, CommandQueue.Callbacks {
+public class Recents extends SystemUI implements CommandQueue.Callbacks {
 
-    private final static String TAG = "Recents";
-
-    public final static int EVENT_BUS_PRIORITY = 1;
-    public final static int BIND_TO_SYSTEM_USER_RETRY_DELAY = 5000;
-
-    public final static Set<String> RECENTS_ACTIVITIES = new HashSet<>();
-    static {
-        RECENTS_ACTIVITIES.add(RecentsImpl.RECENTS_ACTIVITY);
-    }
-
-    private static final String COUNTER_WINDOW_SUPPORTED = "window_enter_supported";
-    private static final String COUNTER_WINDOW_UNSUPPORTED = "window_enter_unsupported";
-    private static final String COUNTER_WINDOW_INCOMPATIBLE = "window_enter_incompatible";
-
-    private static SystemServicesProxy sSystemServicesProxy;
-    private static RecentsDebugFlags sDebugFlags;
-    private static RecentsTaskLoader sTaskLoader;
-    private static RecentsConfiguration sConfiguration;
-
-    private OverviewProxyService mOverviewProxyService;
-
-    private Handler mHandler;
-    private RecentsImpl mImpl;
-    private TrustManager mTrustManager;
-    private int mDraggingInRecentsCurrentUser;
-
-    // Only For system user, this is the callbacks instance we return to each secondary user
-    private RecentsSystemUser mSystemToUserCallbacks;
-
-    // Only for secondary users, this is the callbacks instance provided by the system user to make
-    // calls back
-    private IRecentsSystemUserCallbacks mUserToSystemCallbacks;
-
-    // The set of runnables to run after binding to the system user's service.
-    private final ArrayList<Runnable> mOnConnectRunnables = new ArrayList<>();
-
-    // Only for secondary users, this is the death handler for the binder from the system user
-    private final IBinder.DeathRecipient mUserToSystemCallbacksDeathRcpt = new IBinder.DeathRecipient() {
-        @Override
-        public void binderDied() {
-            mUserToSystemCallbacks = null;
-            EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_CONNECTION,
-                    EventLogConstants.SYSUI_RECENTS_CONNECTION_USER_SYSTEM_UNBOUND,
-                    sSystemServicesProxy.getProcessUser());
-
-            // Retry after a fixed duration
-            mHandler.postDelayed(new Runnable() {
-                @Override
-                public void run() {
-                    registerWithSystemUser();
-                }
-            }, BIND_TO_SYSTEM_USER_RETRY_DELAY);
-        }
-    };
-
-    // Only for secondary users, this is the service connection we use to connect to the system user
-    private final ServiceConnection mUserToSystemServiceConnection = new ServiceConnection() {
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            if (service != null) {
-                mUserToSystemCallbacks = IRecentsSystemUserCallbacks.Stub.asInterface(
-                        service);
-                EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_CONNECTION,
-                        EventLogConstants.SYSUI_RECENTS_CONNECTION_USER_SYSTEM_BOUND,
-                        sSystemServicesProxy.getProcessUser());
-
-                // Listen for system user's death, so that we can reconnect later
-                try {
-                    service.linkToDeath(mUserToSystemCallbacksDeathRcpt, 0);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Lost connection to (System) SystemUI", e);
-                }
-
-                // Run each of the queued runnables
-                runAndFlushOnConnectRunnables();
-            }
-
-            // Unbind ourselves now that we've registered our callbacks.  The
-            // binder to the system user are still valid at this point.
-            mContext.unbindService(this);
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-            // Do nothing
-        }
-    };
-
-    /**
-     * Returns the callbacks interface that non-system users can call.
-     */
-    public IBinder getSystemUserCallbacks() {
-        return mSystemToUserCallbacks;
-    }
-
-    public static RecentsTaskLoader getTaskLoader() {
-        return sTaskLoader;
-    }
-
-
-    public static SystemServicesProxy getSystemServices() {
-        return sSystemServicesProxy;
-    }
-
-    public static RecentsConfiguration getConfiguration() {
-        return sConfiguration;
-    }
-
-    public static RecentsDebugFlags getDebugFlags() {
-        return sDebugFlags;
-    }
+    private RecentsImplementation mImpl;
 
     @Override
     public void start() {
-        final Resources res = mContext.getResources();
-        final int defaultTaskBarBackgroundColor =
-                mContext.getColor(R.color.recents_task_bar_default_background_color);
-        final int defaultTaskViewBackgroundColor =
-                mContext.getColor(R.color.recents_task_view_default_background_color);
-        sDebugFlags = new RecentsDebugFlags();
-        sSystemServicesProxy = SystemServicesProxy.getInstance(mContext);
-        sConfiguration = new RecentsConfiguration(mContext);
-        sTaskLoader = new RecentsTaskLoader(mContext,
-                // TODO: Once we start building the AAR, move these into the loader
-                res.getInteger(R.integer.config_recents_max_thumbnail_count),
-                res.getInteger(R.integer.config_recents_max_icon_count),
-                res.getInteger(R.integer.recents_svelte_level));
-        sTaskLoader.setDefaultColors(defaultTaskBarBackgroundColor, defaultTaskViewBackgroundColor);
-        mHandler = new Handler();
-        mImpl = new RecentsImpl(mContext);
-        mOverviewProxyService = Dependency.get(OverviewProxyService.class);
-
-        // Register with the event bus
-        EventBus.getDefault().register(this, EVENT_BUS_PRIORITY);
-        EventBus.getDefault().register(sSystemServicesProxy, EVENT_BUS_PRIORITY);
-        EventBus.getDefault().register(sTaskLoader, EVENT_BUS_PRIORITY);
-
-        // Due to the fact that RecentsActivity is per-user, we need to establish and interface for
-        // the system user's Recents component to pass events (like show/hide/toggleRecents) to the
-        // secondary user, and vice versa (like visibility change, screen pinning).
-        final int processUser = sSystemServicesProxy.getProcessUser();
-        if (sSystemServicesProxy.isSystemUser(processUser)) {
-            // For the system user, initialize an instance of the interface that we can pass to the
-            // secondary user
-            getComponent(CommandQueue.class).addCallbacks(this);
-            mSystemToUserCallbacks = new RecentsSystemUser(mContext, mImpl);
-        } else {
-            // For the secondary user, bind to the primary user's service to get a persistent
-            // interface to register its implementation and to later update its state
-            registerWithSystemUser();
-        }
+        getComponent(CommandQueue.class).addCallbacks(this);
         putComponent(Recents.class, this);
-
-        mTrustManager = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
+        mImpl = createRecentsImplementationFromConfig();
+        mImpl.onStart(mContext, this);
     }
 
     @Override
@@ -249,13 +46,20 @@
         mImpl.onBootCompleted();
     }
 
-    public void growRecents() {
-        EventBus.getDefault().send(new RecentsGrowingEvent());
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        mImpl.onConfigurationChanged(newConfig);
     }
 
-    /**
-     * Shows the Recents.
-     */
+    @Override
+    public void appTransitionFinished() {
+        mImpl.onAppTransitionFinished();
+    }
+
+    public void growRecents() {
+        mImpl.growRecents();
+    }
+
     @Override
     public void showRecentApps(boolean triggeredFromAltTab) {
         // Ensure the device has been provisioned before allowing the user to interact with
@@ -264,43 +68,9 @@
             return;
         }
 
-        IOverviewProxy overviewProxy = mOverviewProxyService.getProxy();
-        if (overviewProxy != null) {
-            try {
-                overviewProxy.onOverviewShown(triggeredFromAltTab);
-                return;
-            } catch (RemoteException e) {
-                Log.e(TAG, "Failed to send overview show event to launcher.", e);
-            }
-        }
-
-        ActivityManagerWrapper.getInstance().closeSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS);
-        int recentsGrowTarget = getComponent(Divider.class).getView().growsRecents();
-        int currentUser = sSystemServicesProxy.getCurrentUser();
-        if (sSystemServicesProxy.isSystemUser(currentUser)) {
-            mImpl.showRecents(triggeredFromAltTab, false /* draggingInRecents */,
-                    true /* animate */, recentsGrowTarget);
-        } else {
-            if (mSystemToUserCallbacks != null) {
-                IRecentsNonSystemUserCallbacks callbacks =
-                        mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
-                if (callbacks != null) {
-                    try {
-                        callbacks.showRecents(triggeredFromAltTab, false /* draggingInRecents */,
-                                true /* animate */, recentsGrowTarget);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Callback failed", e);
-                    }
-                } else {
-                    Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
-                }
-            }
-        }
+        mImpl.showRecentApps(triggeredFromAltTab);
     }
 
-    /**
-     * Hides the Recents.
-     */
     @Override
     public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
         // Ensure the device has been provisioned before allowing the user to interact with
@@ -309,39 +79,9 @@
             return;
         }
 
-        IOverviewProxy overviewProxy = mOverviewProxyService.getProxy();
-        if (overviewProxy != null) {
-            try {
-                overviewProxy.onOverviewHidden(triggeredFromAltTab, triggeredFromHomeKey);
-                return;
-            } catch (RemoteException e) {
-                Log.e(TAG, "Failed to send overview hide event to launcher.", e);
-            }
-        }
-
-        int currentUser = sSystemServicesProxy.getCurrentUser();
-        if (sSystemServicesProxy.isSystemUser(currentUser)) {
-            mImpl.hideRecents(triggeredFromAltTab, triggeredFromHomeKey);
-        } else {
-            if (mSystemToUserCallbacks != null) {
-                IRecentsNonSystemUserCallbacks callbacks =
-                        mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
-                if (callbacks != null) {
-                    try {
-                        callbacks.hideRecents(triggeredFromAltTab, triggeredFromHomeKey);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Callback failed", e);
-                    }
-                } else {
-                    Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
-                }
-            }
-        }
+        mImpl.hideRecentApps(triggeredFromAltTab, triggeredFromHomeKey);
     }
 
-    /**
-     * Toggles the Recents activity.
-     */
     @Override
     public void toggleRecentApps() {
         // Ensure the device has been provisioned before allowing the user to interact with
@@ -350,57 +90,9 @@
             return;
         }
 
-        // If connected to launcher service, let it handle the toggle logic
-        IOverviewProxy overviewProxy = mOverviewProxyService.getProxy();
-        if (overviewProxy != null) {
-            final Runnable toggleRecents = () -> {
-                try {
-                    if (mOverviewProxyService.getProxy() != null) {
-                        mOverviewProxyService.getProxy().onOverviewToggle();
-                    }
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Cannot send toggle recents through proxy service.", e);
-                }
-            };
-            // Preload only if device for current user is unlocked
-            final StatusBar statusBar = getComponent(StatusBar.class);
-            if (statusBar != null && statusBar.isKeyguardShowing()) {
-                statusBar.executeRunnableDismissingKeyguard(() -> {
-                        // Flush trustmanager before checking device locked per user
-                        mTrustManager.reportKeyguardShowingChanged();
-                        mHandler.post(toggleRecents);
-                    }, null,  true /* dismissShade */, false /* afterKeyguardGone */,
-                    true /* deferred */);
-            } else {
-                toggleRecents.run();
-            }
-            return;
-        }
-
-        int growTarget = getComponent(Divider.class).getView().growsRecents();
-        int currentUser = sSystemServicesProxy.getCurrentUser();
-        if (sSystemServicesProxy.isSystemUser(currentUser)) {
-            mImpl.toggleRecents(growTarget);
-        } else {
-            if (mSystemToUserCallbacks != null) {
-                IRecentsNonSystemUserCallbacks callbacks =
-                        mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
-                if (callbacks != null) {
-                    try {
-                        callbacks.toggleRecents(growTarget);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Callback failed", e);
-                    }
-                } else {
-                    Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
-                }
-            }
-        }
+        mImpl.toggleRecentApps();
     }
 
-    /**
-     * Preloads info for the Recents activity.
-     */
     @Override
     public void preloadRecentApps() {
         // Ensure the device has been provisioned before allowing the user to interact with
@@ -409,29 +101,7 @@
             return;
         }
 
-        if (mOverviewProxyService.getProxy() != null) {
-            // TODO: Proxy to Launcher
-            return;
-        }
-
-        int currentUser = sSystemServicesProxy.getCurrentUser();
-        if (sSystemServicesProxy.isSystemUser(currentUser)) {
-            mImpl.preloadRecents();
-        } else {
-            if (mSystemToUserCallbacks != null) {
-                IRecentsNonSystemUserCallbacks callbacks =
-                        mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
-                if (callbacks != null) {
-                    try {
-                        callbacks.preloadRecents();
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Callback failed", e);
-                    }
-                } else {
-                    Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
-                }
-            }
-        }
+        mImpl.preloadRecentApps();
     }
 
     @Override
@@ -442,32 +112,9 @@
             return;
         }
 
-        if (mOverviewProxyService.getProxy() != null) {
-            // TODO: Proxy to Launcher
-            return;
-        }
-
-        int currentUser = sSystemServicesProxy.getCurrentUser();
-        if (sSystemServicesProxy.isSystemUser(currentUser)) {
-            mImpl.cancelPreloadingRecents();
-        } else {
-            if (mSystemToUserCallbacks != null) {
-                IRecentsNonSystemUserCallbacks callbacks =
-                        mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
-                if (callbacks != null) {
-                    try {
-                        callbacks.cancelPreloadingRecents();
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Callback failed", e);
-                    }
-                } else {
-                    Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
-                }
-            }
-        }
+        mImpl.cancelPreloadRecentApps();
     }
 
-    @Override
     public boolean splitPrimaryTask(int stackCreateMode, Rect initialBounds,
             int metricsDockAction) {
         // Ensure the device has been provisioned before allowing the user to interact with
@@ -476,380 +123,7 @@
             return false;
         }
 
-        Point realSize = new Point();
-        if (initialBounds == null) {
-            mContext.getSystemService(DisplayManager.class).getDisplay(Display.DEFAULT_DISPLAY)
-                    .getRealSize(realSize);
-            initialBounds = new Rect(0, 0, realSize.x, realSize.y);
-        }
-
-        int currentUser = sSystemServicesProxy.getCurrentUser();
-        ActivityManager.RunningTaskInfo runningTask =
-                ActivityManagerWrapper.getInstance().getRunningTask();
-        final int activityType = runningTask != null
-                ? runningTask.configuration.windowConfiguration.getActivityType()
-                : ACTIVITY_TYPE_UNDEFINED;
-        boolean screenPinningActive = ActivityManagerWrapper.getInstance().isScreenPinningActive();
-        boolean isRunningTaskInHomeOrRecentsStack =
-                activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS;
-        if (runningTask != null && !isRunningTaskInHomeOrRecentsStack && !screenPinningActive) {
-            logDockAttempt(mContext, runningTask.topActivity, runningTask.resizeMode);
-            if (runningTask.supportsSplitScreenMultiWindow) {
-                if (metricsDockAction != -1) {
-                    MetricsLogger.action(mContext, metricsDockAction,
-                            runningTask.topActivity.flattenToShortString());
-                }
-                if (sSystemServicesProxy.isSystemUser(currentUser)) {
-                    mImpl.splitPrimaryTask(runningTask.id, stackCreateMode, initialBounds);
-                } else {
-                    if (mSystemToUserCallbacks != null) {
-                        IRecentsNonSystemUserCallbacks callbacks =
-                                mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
-                        if (callbacks != null) {
-                            try {
-                                callbacks.splitPrimaryTask(runningTask.id, stackCreateMode,
-                                        initialBounds);
-                            } catch (RemoteException e) {
-                                Log.e(TAG, "Callback failed", e);
-                            }
-                        } else {
-                            Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
-                        }
-                    }
-                }
-                mDraggingInRecentsCurrentUser = currentUser;
-
-                if (mOverviewProxyService.getProxy() != null) {
-                    // The overview service is handling split screen, so just skip the wait for the
-                    // first draw and notify the divider to start animating now
-                    EventBus.getDefault().post(new RecentsDrawnEvent());
-                }
-
-                return true;
-            } else {
-                EventBus.getDefault().send(new ShowUserToastEvent(
-                        R.string.dock_non_resizeble_failed_to_dock_text, Toast.LENGTH_SHORT));
-                return false;
-            }
-        } else {
-            return false;
-        }
-    }
-
-    public static void logDockAttempt(Context ctx, ComponentName activity, int resizeMode) {
-        if (resizeMode == ActivityInfo.RESIZE_MODE_UNRESIZEABLE) {
-            MetricsLogger.action(ctx, MetricsEvent.ACTION_WINDOW_DOCK_UNRESIZABLE,
-                    activity.flattenToShortString());
-        }
-        MetricsLogger.count(ctx, getMetricsCounterForResizeMode(resizeMode), 1);
-    }
-
-    private static String getMetricsCounterForResizeMode(int resizeMode) {
-        switch (resizeMode) {
-            case ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE:
-                return COUNTER_WINDOW_UNSUPPORTED;
-            case ActivityInfo.RESIZE_MODE_RESIZEABLE:
-            case ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION:
-                return COUNTER_WINDOW_SUPPORTED;
-            default:
-                return COUNTER_WINDOW_INCOMPATIBLE;
-        }
-    }
-
-    public void showNextAffiliatedTask() {
-        // Ensure the device has been provisioned before allowing the user to interact with
-        // recents
-        if (!isUserSetup()) {
-            return;
-        }
-
-        mImpl.showNextAffiliatedTask();
-    }
-
-    public void showPrevAffiliatedTask() {
-        // Ensure the device has been provisioned before allowing the user to interact with
-        // recents
-        if (!isUserSetup()) {
-            return;
-        }
-
-        mImpl.showPrevAffiliatedTask();
-    }
-
-    @Override
-    public void appTransitionFinished() {
-        if (!Recents.getConfiguration().isLowRamDevice) {
-            // Fallback, reset the flag once an app transition ends
-            EventBus.getDefault().send(new SetWaitingForTransitionStartEvent(
-                    false /* waitingForTransitionStart */));
-        }
-    }
-
-    /**
-     * Updates on configuration change.
-     */
-    public void onConfigurationChanged(Configuration newConfig) {
-        int currentUser = sSystemServicesProxy.getCurrentUser();
-        if (sSystemServicesProxy.isSystemUser(currentUser)) {
-            mImpl.onConfigurationChanged();
-        } else {
-            if (mSystemToUserCallbacks != null) {
-                IRecentsNonSystemUserCallbacks callbacks =
-                        mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
-                if (callbacks != null) {
-                    try {
-                        callbacks.onConfigurationChanged();
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Callback failed", e);
-                    }
-                } else {
-                    Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
-                }
-            }
-        }
-    }
-
-    /**
-     * Handle Recents activity visibility changed.
-     */
-    public final void onBusEvent(final RecentsVisibilityChangedEvent event) {
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        int processUser = ssp.getProcessUser();
-        if (ssp.isSystemUser(processUser)) {
-            mImpl.onVisibilityChanged(event.applicationContext, event.visible);
-        } else {
-            postToSystemUser(new Runnable() {
-                @Override
-                public void run() {
-                    try {
-                        mUserToSystemCallbacks.updateRecentsVisibility(event.visible);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Callback failed", e);
-                    }
-                }
-            });
-        }
-
-        // This will catch the cases when a user launches from recents to another app
-        // (and vice versa) that is not in the recents stack (such as home or bugreport) and it
-        // would not reset the wait for transition flag. This will catch it and make sure that the
-        // flag is reset.
-        if (!event.visible) {
-            mImpl.setWaitingForTransitionStart(false);
-        }
-    }
-
-    public final void onBusEvent(DockedFirstAnimationFrameEvent event) {
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        int processUser = ssp.getProcessUser();
-        if (ssp.isSystemUser(processUser)) {
-            final Divider divider = getComponent(Divider.class);
-            if (divider != null) {
-                divider.onDockedFirstAnimationFrame();
-            }
-        } else {
-            postToSystemUser(new Runnable() {
-                @Override
-                public void run() {
-                    try {
-                        mUserToSystemCallbacks.sendDockedFirstAnimationFrameEvent();
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Callback failed", e);
-                    }
-                }
-            });
-        }
-    }
-
-    /**
-     * Handle screen pinning request.
-     */
-    public final void onBusEvent(final ScreenPinningRequestEvent event) {
-        int processUser = sSystemServicesProxy.getProcessUser();
-        if (sSystemServicesProxy.isSystemUser(processUser)) {
-            mImpl.onStartScreenPinning(event.applicationContext, event.taskId);
-        } else {
-            postToSystemUser(new Runnable() {
-                @Override
-                public void run() {
-                    try {
-                        mUserToSystemCallbacks.startScreenPinning(event.taskId);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Callback failed", e);
-                    }
-                }
-            });
-        }
-    }
-
-    public final void onBusEvent(final RecentsDrawnEvent event) {
-        int processUser = sSystemServicesProxy.getProcessUser();
-        if (sSystemServicesProxy.isSystemUser(processUser)) {
-            final Divider divider = getComponent(Divider.class);
-            if (divider != null) {
-                divider.onRecentsDrawn();
-            }
-        } else {
-            postToSystemUser(new Runnable() {
-                @Override
-                public void run() {
-                    try {
-                        mUserToSystemCallbacks.sendRecentsDrawnEvent();
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Callback failed", e);
-                    }
-                }
-            });
-        }
-    }
-
-    public final void onBusEvent(final DockedTopTaskEvent event) {
-        int processUser = sSystemServicesProxy.getProcessUser();
-        if (sSystemServicesProxy.isSystemUser(processUser)) {
-            final Divider divider = getComponent(Divider.class);
-            if (divider != null) {
-                divider.onDockedTopTask();
-            }
-        } else {
-            postToSystemUser(new Runnable() {
-                @Override
-                public void run() {
-                    try {
-                        mUserToSystemCallbacks.sendDockingTopTaskEvent(event.initialRect);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Callback failed", e);
-                    }
-                }
-            });
-        }
-    }
-
-    public final void onBusEvent(final RecentsActivityStartingEvent event) {
-        int processUser = sSystemServicesProxy.getProcessUser();
-        if (sSystemServicesProxy.isSystemUser(processUser)) {
-            final Divider divider = getComponent(Divider.class);
-            if (divider != null) {
-                divider.onRecentsActivityStarting();
-            }
-        } else {
-            postToSystemUser(new Runnable() {
-                @Override
-                public void run() {
-                    try {
-                        mUserToSystemCallbacks.sendLaunchRecentsEvent();
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Callback failed", e);
-                    }
-                }
-            });
-        }
-    }
-
-    public final void onBusEvent(LaunchTaskFailedEvent event) {
-        // Reset the transition when tasks fail to launch
-        mImpl.setWaitingForTransitionStart(false);
-    }
-
-    public final void onBusEvent(ConfigurationChangedEvent event) {
-        // Update the configuration for the Recents component when the activity configuration
-        // changes as well
-        mImpl.onConfigurationChanged();
-    }
-
-    public final void onBusEvent(ShowUserToastEvent event) {
-        int currentUser = sSystemServicesProxy.getCurrentUser();
-        if (sSystemServicesProxy.isSystemUser(currentUser)) {
-            mImpl.onShowCurrentUserToast(event.msgResId, event.msgLength);
-        } else {
-            if (mSystemToUserCallbacks != null) {
-                IRecentsNonSystemUserCallbacks callbacks =
-                        mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
-                if (callbacks != null) {
-                    try {
-                        callbacks.showCurrentUserToast(event.msgResId, event.msgLength);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Callback failed", e);
-                    }
-                } else {
-                    Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
-                }
-            }
-        }
-    }
-
-    public final void onBusEvent(SetWaitingForTransitionStartEvent event) {
-        int processUser = sSystemServicesProxy.getProcessUser();
-        if (sSystemServicesProxy.isSystemUser(processUser)) {
-            mImpl.setWaitingForTransitionStart(event.waitingForTransitionStart);
-        } else {
-            postToSystemUser(new Runnable() {
-                @Override
-                public void run() {
-                    try {
-                        mUserToSystemCallbacks.setWaitingForTransitionStartEvent(
-                                event.waitingForTransitionStart);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Callback failed", e);
-                    }
-                }
-            });
-        }
-    }
-
-    /**
-     * Attempts to register with the system user.
-     */
-    private void registerWithSystemUser() {
-        final int processUser = sSystemServicesProxy.getProcessUser();
-        postToSystemUser(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    mUserToSystemCallbacks.registerNonSystemUserCallbacks(
-                            new RecentsImplProxy(mImpl), processUser);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Failed to register", e);
-                }
-            }
-        });
-    }
-
-    /**
-     * Runs the runnable in the system user's Recents context, connecting to the service if
-     * necessary.
-     */
-    private void postToSystemUser(final Runnable onConnectRunnable) {
-        mOnConnectRunnables.add(onConnectRunnable);
-        if (mUserToSystemCallbacks == null) {
-            Intent systemUserServiceIntent = new Intent();
-            systemUserServiceIntent.setClass(mContext, RecentsSystemUserService.class);
-            boolean bound = mContext.bindServiceAsUser(systemUserServiceIntent,
-                    mUserToSystemServiceConnection, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM);
-            EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_CONNECTION,
-                    EventLogConstants.SYSUI_RECENTS_CONNECTION_USER_BIND_SERVICE,
-                    sSystemServicesProxy.getProcessUser());
-            if (!bound) {
-                // Retry after a fixed duration
-                mHandler.postDelayed(new Runnable() {
-                    @Override
-                    public void run() {
-                        registerWithSystemUser();
-                    }
-                }, BIND_TO_SYSTEM_USER_RETRY_DELAY);
-            }
-        } else {
-            runAndFlushOnConnectRunnables();
-        }
-    }
-
-    /**
-     * Runs all the queued runnables after a service connection is made.
-     */
-    private void runAndFlushOnConnectRunnables() {
-        for (Runnable r : mOnConnectRunnables) {
-            r.run();
-        }
-        mOnConnectRunnables.clear();
+        return mImpl.splitPrimaryTask(stackCreateMode, initialBounds, metricsDockAction);
     }
 
     /**
@@ -861,9 +135,30 @@
                 (Settings.Secure.getInt(cr, Settings.Secure.USER_SETUP_COMPLETE, 0) != 0);
     }
 
+    /**
+     * @return The recents implementation from the config.
+     */
+    private RecentsImplementation createRecentsImplementationFromConfig() {
+        final String clsName = mContext.getString(R.string.config_recentsComponent);
+        if (clsName == null || clsName.length() == 0) {
+            throw new RuntimeException("No recents component configured", null);
+        }
+        Class<?> cls = null;
+        try {
+            cls = mContext.getClassLoader().loadClass(clsName);
+        } catch (Throwable t) {
+            throw new RuntimeException("Error loading recents component: " + clsName, t);
+        }
+        try {
+            RecentsImplementation impl = (RecentsImplementation) cls.newInstance();
+            return impl;
+        } catch (Throwable t) {
+            throw new RuntimeException("Error creating recents component: " + clsName, t);
+        }
+    }
+
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        pw.println("Recents");
-        pw.println("  currentUserId=" + SystemServicesProxy.getInstance(mContext).getCurrentUser());
+        mImpl.dump(pw);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java
new file mode 100644
index 0000000..8a04c11
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java
@@ -0,0 +1,42 @@
+/*
+ * 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.systemui.recents;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import com.android.systemui.SysUiServiceProvider;
+import java.io.PrintWriter;
+
+interface RecentsImplementation {
+    default void onStart(Context context, SysUiServiceProvider sysUiServiceProvider) {}
+    default void onBootCompleted() {}
+    default void onAppTransitionFinished() {}
+    default void onConfigurationChanged(Configuration newConfig) {}
+
+    default void preloadRecentApps() {}
+    default void cancelPreloadRecentApps() {}
+    default void showRecentApps(boolean triggeredFromAltTab) {}
+    default void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {}
+    default void toggleRecentApps() {}
+    default void growRecents() {}
+    default boolean splitPrimaryTask(int stackCreateMode, Rect initialBounds,
+            int metricsDockAction) {
+        return false;
+    }
+
+    default void dump(PrintWriter pw) {}
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
index db2b69f..af0ebdc 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
@@ -59,13 +59,11 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
-import com.android.systemui.OverviewProxyService;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
-import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
 import com.android.systemui.shared.recents.IOverviewProxy;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
-
+import com.android.systemui.shared.system.TaskStackChangeListener;
 import java.io.PrintWriter;
 import java.util.Collections;
 import java.util.HashSet;
@@ -119,7 +117,7 @@
     private int mNumAppsLaunchedSinceSwipeUpTipDismiss;
     private int mOverviewOpenedCountSinceQuickScrubTipDismiss;
 
-    private final SysUiTaskStackChangeListener mTaskListener = new SysUiTaskStackChangeListener() {
+    private final TaskStackChangeListener mTaskListener = new TaskStackChangeListener() {
         private String mLastPackageName;
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index b7eee36..f92c50a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -29,7 +29,6 @@
 import android.os.Binder;
 import android.os.RemoteException;
 import android.util.DisplayMetrics;
-import android.view.ContextThemeWrapper;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
@@ -42,9 +41,9 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
-import com.android.settingslib.Utils;
 import com.android.systemui.R;
 import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.shared.system.WindowManagerWrapper;
 import com.android.systemui.statusbar.phone.NavigationBarView;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.util.leak.RotationUtils;
@@ -220,8 +219,7 @@
             mLayout.findViewById(R.id.screen_pinning_text_area)
                     .setLayoutDirection(View.LAYOUT_DIRECTION_LOCALE);
             View buttons = mLayout.findViewById(R.id.screen_pinning_buttons);
-            if (Recents.getSystemServices() != null &&
-                    Recents.getSystemServices().hasSoftNavigationBar()) {
+            if (WindowManagerWrapper.getInstance().hasSoftNavigationBar()) {
                 buttons.setLayoutDirection(View.LAYOUT_DIRECTION_LOCALE);
                 swapChildrenIfRtlAndVertical(buttons);
             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 178c5c5..38011d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -44,11 +44,10 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
-import com.android.systemui.OverviewProxyService;
+import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.phone.StatusBarRemoteInputCallback;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 59c15f1..329a33d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -19,7 +19,7 @@
 import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
 import static android.app.StatusBarManager.windowStateToString;
 
-import static com.android.systemui.OverviewProxyService.OverviewProxyListener;
+import static com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
 import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
@@ -74,7 +74,7 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.LatencyTracker;
 import com.android.systemui.Dependency;
-import com.android.systemui.OverviewProxyService;
+import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.R;
 import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.assist.AssistManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index 52134d9..22b6ba6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -34,7 +34,7 @@
 import android.widget.Space;
 
 import com.android.systemui.Dependency;
-import com.android.systemui.OverviewProxyService;
+import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.R;
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.shared.plugins.PluginManager;
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 2ab5958..6728f08 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -57,7 +57,7 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.DockedStackExistsListener;
 import com.android.systemui.Interpolators;
-import com.android.systemui.OverviewProxyService;
+import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.R;
 import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.plugins.PluginListener;
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 fd5403f..3980126 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
@@ -20,8 +20,8 @@
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
 import static com.android.systemui.Interpolators.ALPHA_IN;
 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.recents.OverviewProxyService.DEBUG_OVERVIEW_PROXY;
+import static com.android.systemui.recents.OverviewProxyService.TAG_OPS;
 import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_DEAD_ZONE;
 import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_HOME;
 
@@ -56,7 +56,7 @@
 import android.view.WindowManagerGlobal;
 import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
-import com.android.systemui.OverviewProxyService;
+import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.R;
 import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java
index 855592f..c6e98e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java
@@ -44,8 +44,8 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
-import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.statusbar.policy.KeyButtonDrawable;
 import com.android.systemui.statusbar.policy.RotationLockController;
 
@@ -400,7 +400,7 @@
         }
     }
 
-    private class TaskStackListenerImpl extends SysUiTaskStackChangeListener {
+    private class TaskStackListenerImpl extends TaskStackChangeListener {
         // Invalidate any rotation suggestion on task change or activity orientation change
         // Note: all callbacks happen on main thread
 
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 37eccb5..b2a04ad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -135,7 +135,6 @@
 import com.android.systemui.Interpolators;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
-import com.android.systemui.RecentsComponent;
 import com.android.systemui.SystemUI;
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.UiOffloadThread;
@@ -4121,7 +4120,7 @@
 
     protected Display mDisplay;
 
-    protected RecentsComponent mRecents;
+    protected Recents mRecents;
 
     protected NotificationShelf mNotificationShelf;
     protected EmptyShadeView mEmptyShadeView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 298a93e..6fa73ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -34,7 +34,6 @@
 import android.os.SystemClock;
 import android.util.AttributeSet;
 import android.util.TypedValue;
-import android.view.Display;
 import android.view.HapticFeedbackConstants;
 import android.view.InputDevice;
 import android.view.KeyCharacterMap;
@@ -49,7 +48,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.Dependency;
-import com.android.systemui.OverviewProxyService;
+import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.R;
 import com.android.systemui.plugins.statusbar.phone.NavBarButtonProvider.ButtonInterface;
 import com.android.systemui.shared.system.NavigationBarCompat;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl b/packages/SystemUI/tests/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
deleted file mode 120000
index 0ea3e91..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../../src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl b/packages/SystemUI/tests/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
deleted file mode 120000
index b1a0963..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../../src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/RecentsTest.java b/packages/SystemUI/tests/src/com/android/systemui/recents/RecentsTest.java
deleted file mode 100644
index 2160f9a..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/recents/RecentsTest.java
+++ /dev/null
@@ -1,69 +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.systemui.recents;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
-
-import static com.android.systemui.recents.RecentsImpl.RECENTS_ACTIVITY;
-import static com.android.systemui.recents.RecentsImpl.RECENTS_PACKAGE;
-
-import static org.junit.Assert.fail;
-
-import android.app.ActivityManager.RunningTaskInfo;
-import android.app.ActivityTaskManager;
-import android.app.IActivityTaskManager;
-import android.os.SystemClock;
-import android.support.test.filters.MediumTest;
-import android.support.test.runner.AndroidJUnit4;
-
-import com.android.systemui.SysuiTestCase;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-@MediumTest
-public class RecentsTest extends SysuiTestCase {
-
-    @Test
-    public void testRecentsActivityType() throws Exception {
-        // Clear the state
-        final IActivityTaskManager atm = ActivityTaskManager.getService();
-        atm.removeStacksWithActivityTypes(new int[] { ACTIVITY_TYPE_RECENTS });
-
-        // Toggle recents, use a shell command because it is not exported
-        runShellCommand("am start -n " + RECENTS_PACKAGE + "/" + RECENTS_ACTIVITY);
-
-        // Verify that an activity was launched with the right activity type
-        int retryCount = 0;
-        while (retryCount < 10) {
-            List<RunningTaskInfo> tasks = atm.getTasks(Integer.MAX_VALUE);
-            for (RunningTaskInfo info : tasks) {
-                if (info.configuration.windowConfiguration.getActivityType()
-                        == ACTIVITY_TYPE_RECENTS) {
-                    // Found a recents activity with the right activity type
-                    return;
-                }
-            }
-            SystemClock.sleep(50);
-            retryCount++;
-        }
-        fail("Expected Recents activity with ACTIVITY_TYPE_RECENTS");
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
index 17df800..003d058 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
@@ -27,7 +27,7 @@
 
 import com.android.systemui.Dependency;
 
-import com.android.systemui.OverviewProxyService;
+import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.SysuiBaseFragmentTest;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.stackdivider.Divider;
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index d570862..865a651 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -69,6 +69,7 @@
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
 import android.net.UidRange;
+import android.net.UidRangeParcel;
 import android.net.util.NetdService;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiConfiguration.KeyMgmt;
@@ -1743,7 +1744,6 @@
     public void setAllowOnlyVpnForUids(boolean add, UidRange[] uidRanges)
             throws ServiceSpecificException {
         mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG);
-
         try {
             mNetdService.networkRejectNonSecureVpn(add, uidRanges);
         } catch (ServiceSpecificException e) {
@@ -2037,8 +2037,9 @@
                 setFirewallChainState(chain, enable);
             }
 
+            final String chainName = getFirewallChainName(chain);
             if (chain == FIREWALL_CHAIN_NONE) {
-                throw new IllegalArgumentException("Bad child chain: " + chain);
+                throw new IllegalArgumentException("Bad child chain: " + chainName);
             }
 
             try {
@@ -2052,7 +2053,7 @@
             // the connection and race with the iptables commands that enable the firewall. All
             // whitelist and blacklist chains allow RSTs through.
             if (enable) {
-                closeSocketsForFirewallChainLocked(chain, getFirewallChainName(chain));
+                closeSocketsForFirewallChainLocked(chain, chainName);
             }
         }
     }
@@ -2214,19 +2215,11 @@
     }
 
     private int getFirewallRuleType(int chain, int rule) {
-        if (getFirewallType(chain) == FIREWALL_TYPE_WHITELIST) {
-            if (rule == NetworkPolicyManager.FIREWALL_RULE_ALLOW) {
-                return INetd.FIREWALL_RULE_ALLOW;
-            } else {
-                return INetd.FIREWALL_RULE_DENY;
-            }
-        } else { // Blacklist mode
-            if (rule == NetworkPolicyManager.FIREWALL_RULE_DENY) {
-                return INetd.FIREWALL_RULE_DENY;
-            } else {
-                return INetd.FIREWALL_RULE_ALLOW;
-            }
+        if (rule == NetworkPolicyManager.FIREWALL_RULE_DEFAULT) {
+            return getFirewallType(chain) == FIREWALL_TYPE_WHITELIST
+                    ? INetd.FIREWALL_RULE_DENY : INetd.FIREWALL_RULE_ALLOW;
         }
+        return rule;
     }
 
     private static void enforceSystemUid() {
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 858dced..5643a6a 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -112,7 +112,6 @@
 import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.AppFuseMount;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.os.FuseUnavailableMountException;
@@ -323,12 +322,6 @@
     @GuardedBy("mPackagesLock")
     private final SparseArray<ArraySet<String>> mPackages = new SparseArray<>();
 
-    @GuardedBy("mPackagesLock")
-    private final ArrayMap<String, Integer> mAppIds = new ArrayMap<>();
-
-    @GuardedBy("mPackagesLock")
-    private final SparseArray<String> mSandboxIds = new SparseArray<>();
-
     /**
      * List of volumes visible to any user.
      * TODO: may be have a map of userId -> volumes?
@@ -876,13 +869,12 @@
             try {
                 mVold.reset();
 
-                pushPackagesInfo();
                 // Tell vold about all existing and started users
                 for (UserInfo user : users) {
                     mVold.onUserAdded(user.id, user.serialNumber);
                 }
                 for (int userId : systemUnlockedUsers) {
-                    mVold.onUserStarted(userId, getPackagesArrayForUser(userId));
+                    sendUserStartedCallback(userId);
                     mStoraged.onUserStarted(userId);
                 }
                 mVold.onSecureKeyguardStateChanged(mSecureKeyguardShowing);
@@ -899,7 +891,7 @@
         // staging area is ready so it's ready for zygote-forked apps to
         // bind mount against.
         try {
-            mVold.onUserStarted(userId, getPackagesArrayForUser(userId));
+            sendUserStartedCallback(userId);
             mStoraged.onUserStarted(userId);
         } catch (Exception e) {
             Slog.wtf(TAG, e);
@@ -932,11 +924,52 @@
             Slog.wtf(TAG, e);
         }
 
+        synchronized (mPackagesLock) {
+            mPackages.delete(userId);
+        }
+
         synchronized (mLock) {
             mSystemUnlockedUsers = ArrayUtils.removeInt(mSystemUnlockedUsers, userId);
         }
     }
 
+    private void sendUserStartedCallback(int userId) throws Exception {
+        if (!ENABLE_ISOLATED_STORAGE) {
+            mVold.onUserStarted(userId, EmptyArray.STRING, EmptyArray.INT, EmptyArray.STRING);
+        }
+
+        final String[] packages;
+        final int[] appIds;
+        final String[] sandboxIds;
+        final SparseArray<String> sharedUserIds = mPmInternal.getAppsWithSharedUserIds();
+        final List<ApplicationInfo> appInfos =
+                mContext.getPackageManager().getInstalledApplicationsAsUser(
+                        PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
+        synchronized (mPackagesLock) {
+            final ArraySet<String> userPackages = new ArraySet<>();
+            final ArrayMap<String, Integer> packageToAppId = new ArrayMap<>();
+            for (int i = appInfos.size() - 1; i >= 0; --i) {
+                final ApplicationInfo appInfo = appInfos.get(i);
+                if (appInfo.isInstantApp()) {
+                    continue;
+                }
+                userPackages.add(appInfo.packageName);
+                packageToAppId.put(appInfo.packageName, UserHandle.getAppId(appInfo.uid));
+            }
+            mPackages.put(userId, userPackages);
+
+            packages = new String[userPackages.size()];
+            appIds = new int[userPackages.size()];
+            sandboxIds = new String[userPackages.size()];
+            for (int i = userPackages.size() - 1; i >= 0; --i) {
+                packages[i] = userPackages.valueAt(i);
+                appIds[i] = packageToAppId.get(packages[i]);
+                sandboxIds[i] = getSandboxId(packages[i], sharedUserIds.get(appIds[i]));
+            }
+        }
+        mVold.onUserStarted(userId, packages, appIds, sandboxIds);
+    }
+
     @Override
     public void onAwakeStateChanged(boolean isAwake) {
         // Ignored
@@ -1454,111 +1487,12 @@
     }
 
     private void start() {
-        collectPackagesInfo();
         connect();
     }
 
-    @VisibleForTesting
-    void collectPackagesInfo() {
-        if (!ENABLE_ISOLATED_STORAGE) return;
-
-        resetPackageData();
-        final SparseArray<String> sharedUserIds = mPmInternal.getAppsWithSharedUserIds();
-        final int[] userIds = mUmInternal.getUserIds();
-        for (int userId : userIds) {
-            final List<ApplicationInfo> appInfos
-                    = mContext.getPackageManager().getInstalledApplicationsAsUser(
-                            PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
-            synchronized (mPackagesLock) {
-                final ArraySet<String> userPackages = getAvailablePackagesForUserPL(userId);
-                for (int i = appInfos.size() - 1; i >= 0; --i) {
-                    if (appInfos.get(i).isInstantApp()) {
-                        continue;
-                    }
-                    final String packageName = appInfos.get(i).packageName;
-                    userPackages.add(packageName);
-
-                    final int appId = UserHandle.getAppId(appInfos.get(i).uid);
-                    mAppIds.put(packageName, appId);
-                    mSandboxIds.put(appId, getSandboxId(packageName, sharedUserIds.get(appId)));
-                }
-            }
-        }
-    }
-
-    private void resetPackageData() {
-        synchronized (mPackagesLock) {
-            mPackages.clear();
-            mAppIds.clear();
-            mSandboxIds.clear();
-        }
-    }
-
     private static String getSandboxId(String packageName, String sharedUserId) {
         return sharedUserId == null ? packageName : SHARED_SANDBOX_ID_PREFIX + sharedUserId;
     }
-    private void pushPackagesInfo() throws RemoteException {
-        if (!ENABLE_ISOLATED_STORAGE) return;
-
-        // Arrays to fill up from {@link #mAppIds}
-        final String[] allPackageNames;
-        final int[] appIdsForPackages;
-
-        // Arrays to fill up from {@link #mSandboxIds}
-        final int[] allAppIds;
-        final String[] sandboxIdsForApps;
-        synchronized (mPackagesLock) {
-            allPackageNames = new String[mAppIds.size()];
-            appIdsForPackages = new int[mAppIds.size()];
-            for (int i = mAppIds.size() - 1; i >= 0; --i) {
-                allPackageNames[i] = mAppIds.keyAt(i);
-                appIdsForPackages[i] = mAppIds.valueAt(i);
-            }
-
-            allAppIds = new int[mSandboxIds.size()];
-            sandboxIdsForApps = new String[mSandboxIds.size()];
-            for (int i = mSandboxIds.size() - 1; i >= 0; --i) {
-                allAppIds[i] = mSandboxIds.keyAt(i);
-                sandboxIdsForApps[i] = mSandboxIds.valueAt(i);
-            }
-        }
-        mVold.addAppIds(allPackageNames, appIdsForPackages);
-        mVold.addSandboxIds(allAppIds, sandboxIdsForApps);
-    }
-
-    @GuardedBy("mPackagesLock")
-    private ArraySet<String> getAvailablePackagesForUserPL(int userId) {
-        ArraySet<String> userPackages = mPackages.get(userId);
-        if (userPackages == null) {
-            userPackages = new ArraySet<>();
-            mPackages.put(userId, userPackages);
-        }
-        return userPackages;
-    }
-
-    private String[] getPackagesArrayForUser(int userId) {
-        if (!ENABLE_ISOLATED_STORAGE) return EmptyArray.STRING;
-
-        final ArraySet<String> userPackages;
-        synchronized (mPackagesLock) {
-            userPackages = getAvailablePackagesForUserPL(userId);
-            if (!userPackages.isEmpty()) {
-                return userPackages.toArray(new String[0]);
-            }
-        }
-        final List<ApplicationInfo> appInfos =
-                mContext.getPackageManager().getInstalledApplicationsAsUser(
-                        PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
-        synchronized (mPackagesLock) {
-            for (int i = appInfos.size() - 1; i >= 0; --i) {
-                if (appInfos.get(i).isInstantApp()) {
-                    continue;
-                }
-                userPackages.add(appInfos.get(i).packageName);
-            }
-            return userPackages.toArray(new String[0]);
-        }
-    }
 
     private void connect() {
         IBinder binder = ServiceManager.getService("storaged");
@@ -3122,15 +3056,8 @@
             throw new SecurityException("Shady looking path " + path);
         }
 
-        final int uid = mPmInternal.getPackageUid(packageName,
-                PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
-        final String sandboxId;
-        synchronized (mPackagesLock) {
-            sandboxId = mSandboxIds.get(UserHandle.getAppId(uid));
-        }
-        if (uid < 0 || sandboxId == null) {
-            throw new IllegalArgumentException("Unknown package " + packageName);
-        }
+        final String sharedUserId = mPmInternal.getSharedUserIdForPackage(packageName);
+        final String sandboxId = getSandboxId(packageName, sharedUserId);
 
         final Matcher m = PATTERN_TRANSLATE.matcher(path);
         if (m.matches()) {
@@ -3139,7 +3066,9 @@
 
             // Does path belong to any packages belonging to this UID? If so,
             // they get to go straight through to legacy paths.
-            final String[] pkgs = mContext.getPackageManager().getPackagesForUid(uid);
+            final String[] pkgs = (sharedUserId == null)
+                    ? new String[] {packageName}
+                    : mPmInternal.getPackagesForSharedUserId(sharedUserId, userId);
             for (String pkg : pkgs) {
                 if (devicePath.startsWith("Android/data/" + pkg + "/") ||
                         devicePath.startsWith("Android/media/" + pkg + "/") ||
@@ -3758,16 +3687,14 @@
                 int userId) {
             final String sandboxId;
             synchronized (mPackagesLock) {
-                final ArraySet<String> userPackages = getAvailablePackagesForUserPL(userId);
+                final ArraySet<String> userPackages = mPackages.get(userId);
                 // If userPackages is empty, it means the user is not started yet, so no need to
                 // do anything now.
-                if (userPackages.isEmpty() || userPackages.contains(packageName)) {
+                if (userPackages == null || userPackages.contains(packageName)) {
                     return;
                 }
                 userPackages.add(packageName);
-                mAppIds.put(packageName, appId);
                 sandboxId = getSandboxId(packageName, sharedUserId);
-                mSandboxIds.put(appId, sandboxId);
             }
 
             try {
@@ -3778,34 +3705,21 @@
         }
 
         @Override
-        public void destroySandboxForApp(String packageName, int userId) {
+        public void destroySandboxForApp(String packageName, String sharedUserId, int userId) {
             if (!ENABLE_ISOLATED_STORAGE) {
                 return;
             }
-            final int appId;
-            final String sandboxId;
+            final String sandboxId = getSandboxId(packageName, sharedUserId);
             synchronized (mPackagesLock) {
-                final ArraySet<String> userPackages = getAvailablePackagesForUserPL(userId);
-                userPackages.remove(packageName);
-                appId = mAppIds.get(packageName);
-                sandboxId = mSandboxIds.get(appId);
-
-                // If the package is not uninstalled in any other users, remove appId and sandboxId
-                // corresponding to it from the internal state.
-                boolean installedInAnyUser = false;
-                for (int i = mPackages.size() - 1; i >= 0; --i) {
-                    if (mPackages.valueAt(i).contains(packageName)) {
-                        installedInAnyUser = true;
-                        break;
-                    }
-                }
-                if (!installedInAnyUser) {
-                    mAppIds.remove(packageName);
-                    mSandboxIds.remove(appId);
+                final ArraySet<String> userPackages = mPackages.get(userId);
+                // If the userPackages is null, it means the user is not started but we still
+                // need to delete the sandbox data though.
+                if (userPackages != null) {
+                    userPackages.remove(packageName);
                 }
             }
             try {
-                mVold.destroySandboxForApp(packageName, appId, sandboxId, userId);
+                mVold.destroySandboxForApp(packageName, sandboxId, userId);
             } catch (Exception e) {
                 Slog.wtf(TAG, e);
             }
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 9c60b8c..e879efd 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -241,9 +241,6 @@
         private final HashMap<Account, AtomicReference<String>> previousNameCache =
                 new HashMap<Account, AtomicReference<String>>();
 
-        private int debugDbInsertionPoint = -1;
-        private SQLiteStatement statementForLogging; // TODO Move to AccountsDb
-
         UserAccounts(Context context, int userId, File preNDbFile, File deDbFile) {
             this.userId = userId;
             synchronized (dbLock) {
@@ -1299,7 +1296,6 @@
                 File preNDbFile = new File(mInjector.getPreNDatabaseName(userId));
                 File deDbFile = new File(mInjector.getDeDatabaseName(userId));
                 accounts = new UserAccounts(mContext, userId, preNDbFile, deDbFile);
-                initializeDebugDbSizeAndCompileSqlStatementForLogging(accounts);
                 mUsers.append(userId, accounts);
                 purgeOldGrants(accounts);
                 validateAccounts = true;
@@ -1400,7 +1396,7 @@
         if (accounts != null) {
             synchronized (accounts.dbLock) {
                 synchronized (accounts.cacheLock) {
-                    accounts.statementForLogging.close();
+                    accounts.accountsDb.closeDebugStatement();
                     accounts.accountsDb.close();
                 }
             }
@@ -5124,41 +5120,36 @@
 
             @Override
             public void run() {
-                SQLiteStatement logStatement = userAccount.statementForLogging;
-                logStatement.bindLong(1, accountId);
-                logStatement.bindString(2, action);
-                logStatement.bindString(3, mDateFormat.format(new Date()));
-                logStatement.bindLong(4, callingUid);
-                logStatement.bindString(5, tableName);
-                logStatement.bindLong(6, userDebugDbInsertionPoint);
-                try {
-                    logStatement.execute();
-                } catch (IllegalStateException e) {
-                    // Guard against crash, DB can already be closed
-                    // since this statement is executed on a handler thread
-                    Slog.w(TAG, "Failed to insert a log record. accountId=" + accountId
-                            + " action=" + action + " tableName=" + tableName + " Error: " + e);
-                } finally {
-                    logStatement.clearBindings();
+                synchronized (userAccount.accountsDb.mDebugStatementLock) {
+                    SQLiteStatement logStatement = userAccount.accountsDb.getStatementForLogging();
+                    if (logStatement == null) {
+                        return; // Can't log.
+                    }
+                    logStatement.bindLong(1, accountId);
+                    logStatement.bindString(2, action);
+                    logStatement.bindString(3, mDateFormat.format(new Date()));
+                    logStatement.bindLong(4, callingUid);
+                    logStatement.bindString(5, tableName);
+                    logStatement.bindLong(6, userDebugDbInsertionPoint);
+                    try {
+                        logStatement.execute();
+                    } catch (IllegalStateException e) {
+                        // Guard against crash, DB can already be closed
+                        // since this statement is executed on a handler thread
+                        Slog.w(TAG, "Failed to insert a log record. accountId=" + accountId
+                                + " action=" + action + " tableName=" + tableName + " Error: " + e);
+                    } finally {
+                        logStatement.clearBindings();
+                    }
                 }
             }
         }
-
-        LogRecordTask logTask = new LogRecordTask(action, tableName, accountId, userAccount,
-                callingUid, userAccount.debugDbInsertionPoint);
-        userAccount.debugDbInsertionPoint = (userAccount.debugDbInsertionPoint + 1)
-                % AccountsDb.MAX_DEBUG_DB_SIZE;
-        mHandler.post(logTask);
-    }
-
-    /*
-     * This should only be called once to compile the sql statement for logging
-     * and to find the insertion point.
-     */
-    private void initializeDebugDbSizeAndCompileSqlStatementForLogging(UserAccounts userAccount) {
-        userAccount.debugDbInsertionPoint = userAccount.accountsDb
-                .calculateDebugTableInsertionPoint();
-        userAccount.statementForLogging = userAccount.accountsDb.compileSqlStatementForLogging();
+        long insertionPoint = userAccount.accountsDb.reserveDebugDbInsertionPoint();
+        if (insertionPoint != -1) {
+            LogRecordTask logTask = new LogRecordTask(action, tableName, accountId, userAccount,
+                    callingUid, insertionPoint);
+            mHandler.post(logTask);
+        }
     }
 
     public IBinder onBind(@SuppressWarnings("unused") Intent intent) {
diff --git a/services/core/java/com/android/server/accounts/AccountsDb.java b/services/core/java/com/android/server/accounts/AccountsDb.java
index 0c3d268..712edcc 100644
--- a/services/core/java/com/android/server/accounts/AccountsDb.java
+++ b/services/core/java/com/android/server/accounts/AccountsDb.java
@@ -17,11 +17,13 @@
 package com.android.server.accounts;
 
 import android.accounts.Account;
+import android.annotation.Nullable;
 import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
 import android.database.DatabaseUtils;
 import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteException;
 import android.database.sqlite.SQLiteOpenHelper;
 import android.database.sqlite.SQLiteStatement;
 import android.os.FileUtils;
@@ -183,6 +185,10 @@
     private final Context mContext;
     private final File mPreNDatabaseFile;
 
+    final Object mDebugStatementLock = new Object();
+    private volatile long mDebugDbInsertionPoint = -1;
+    private volatile SQLiteStatement mDebugStatementForLogging; // not thread safe.
+
     AccountsDb(DeDatabaseHelper deDatabase, Context context, File preNDatabaseFile) {
         mDeDatabase = deDatabase;
         mContext = context;
@@ -1278,31 +1284,72 @@
      * Finds the row key where the next insertion should take place. Returns number of rows
      * if it is less {@link #MAX_DEBUG_DB_SIZE}, otherwise finds the lowest number available.
      */
-    int calculateDebugTableInsertionPoint() {
-        SQLiteDatabase db = mDeDatabase.getReadableDatabase();
-        String queryCountDebugDbRows = "SELECT COUNT(*) FROM " + TABLE_DEBUG;
-        int size = (int) DatabaseUtils.longForQuery(db, queryCountDebugDbRows, null);
-        if (size < MAX_DEBUG_DB_SIZE) {
-            return size;
-        }
+    long calculateDebugTableInsertionPoint() {
+        try {
+            SQLiteDatabase db = mDeDatabase.getReadableDatabase();
+            String queryCountDebugDbRows = "SELECT COUNT(*) FROM " + TABLE_DEBUG;
+            int size = (int) DatabaseUtils.longForQuery(db, queryCountDebugDbRows, null);
+            if (size < MAX_DEBUG_DB_SIZE) {
+                return size;
+            }
 
-        // This query finds the smallest timestamp value (and if 2 records have
-        // same timestamp, the choose the lower id).
-        queryCountDebugDbRows = "SELECT " + DEBUG_TABLE_KEY +
-                " FROM " + TABLE_DEBUG +
-                " ORDER BY "  + DEBUG_TABLE_TIMESTAMP + "," + DEBUG_TABLE_KEY +
-                " LIMIT 1";
-        return (int) DatabaseUtils.longForQuery(db, queryCountDebugDbRows, null);
+            // This query finds the smallest timestamp value (and if 2 records have
+            // same timestamp, the choose the lower id).
+            queryCountDebugDbRows =
+                    "SELECT " + DEBUG_TABLE_KEY
+                    + " FROM " + TABLE_DEBUG
+                    + " ORDER BY "  + DEBUG_TABLE_TIMESTAMP + ","
+                    + DEBUG_TABLE_KEY
+                    + " LIMIT 1";
+            return DatabaseUtils.longForQuery(db, queryCountDebugDbRows, null);
+        } catch (SQLiteException e) {
+            Log.e(TAG, "Failed to open debug table" + e);
+            return -1;
+        }
     }
 
     SQLiteStatement compileSqlStatementForLogging() {
-        // TODO b/31708085 Fix debug logging - it eagerly opens database for write without a need
         SQLiteDatabase db = mDeDatabase.getWritableDatabase();
         String sql = "INSERT OR REPLACE INTO " + AccountsDb.TABLE_DEBUG
                 + " VALUES (?,?,?,?,?,?)";
         return db.compileStatement(sql);
     }
 
+    /**
+     * Returns statement for logging or {@code null} on database open failure.
+     * Returned value must be guarded by {link #debugStatementLock}
+     */
+    @Nullable SQLiteStatement getStatementForLogging() {
+        if (mDebugStatementForLogging != null) {
+            return mDebugStatementForLogging;
+        }
+        try {
+            mDebugStatementForLogging =  compileSqlStatementForLogging();
+            return mDebugStatementForLogging;
+        } catch (SQLiteException e) {
+            Log.e(TAG, "Failed to open debug table" + e);
+            return null;
+        }
+    }
+
+    void closeDebugStatement() {
+        synchronized (mDebugStatementLock) {
+            if (mDebugStatementForLogging != null) {
+                mDebugStatementForLogging.close();
+                mDebugStatementForLogging = null;
+            }
+        }
+    }
+
+    long reserveDebugDbInsertionPoint() {
+        if (mDebugDbInsertionPoint == -1) {
+            mDebugDbInsertionPoint = calculateDebugTableInsertionPoint();
+            return mDebugDbInsertionPoint;
+        }
+        mDebugDbInsertionPoint = (mDebugDbInsertionPoint + 1) % MAX_DEBUG_DB_SIZE;
+        return mDebugDbInsertionPoint;
+    }
+
     void dumpDebugTable(PrintWriter pw) {
         SQLiteDatabase db = mDeDatabase.getReadableDatabase();
         Cursor cursor = db.query(TABLE_DEBUG, null,
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4179cf3..e8c6365 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -538,14 +538,23 @@
 
     BroadcastQueue mFgBroadcastQueue;
     BroadcastQueue mBgBroadcastQueue;
+    BroadcastQueue mOffloadBroadcastQueue;
     // Convenient for easy iteration over the queues. Foreground is first
     // so that dispatch of foreground broadcasts gets precedence.
-    final BroadcastQueue[] mBroadcastQueues = new BroadcastQueue[2];
+    final BroadcastQueue[] mBroadcastQueues = new BroadcastQueue[3];
 
     BroadcastStats mLastBroadcastStats;
     BroadcastStats mCurBroadcastStats;
 
     BroadcastQueue broadcastQueueForIntent(Intent intent) {
+        if (isOnOffloadQueue(intent.getFlags())) {
+            if (DEBUG_BROADCAST_BACKGROUND) {
+                Slog.i(TAG_BROADCAST,
+                        "Broadcast intent " + intent + " on offload queue");
+            }
+            return mOffloadBroadcastQueue;
+        }
+
         final boolean isFg = (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0;
         if (DEBUG_BROADCAST_BACKGROUND) Slog.i(TAG_BROADCAST,
                 "Broadcast intent " + intent + " on "
@@ -1361,14 +1370,6 @@
 
     private static String sTheRealBuildSerial = Build.UNKNOWN;
 
-    /**
-     * Current global configuration information. Contains general settings for the entire system,
-     * also corresponds to the merged configuration of the default display.
-     */
-    Configuration getGlobalConfiguration() {
-        return mActivityTaskManager.getGlobalConfiguration();
-    }
-
     final class UiHandler extends Handler {
         public UiHandler() {
             super(com.android.server.UiThread.get().getLooper(), null, true);
@@ -2174,8 +2175,11 @@
                 "foreground", BROADCAST_FG_TIMEOUT, false);
         mBgBroadcastQueue = new BroadcastQueue(this, mHandler,
                 "background", BROADCAST_BG_TIMEOUT, true);
+        mOffloadBroadcastQueue = new BroadcastQueue(this, mHandler,
+                "offload", BROADCAST_BG_TIMEOUT, true);
         mBroadcastQueues[0] = mFgBroadcastQueue;
         mBroadcastQueues[1] = mBgBroadcastQueue;
+        mBroadcastQueues[2] = mOffloadBroadcastQueue;
 
         mServices = new ActiveServices(this);
         mProviderMap = new ProviderMap(this);
@@ -3552,7 +3556,7 @@
 
                 if (appInfo != null) {
                     forceStopPackageLocked(packageName, appInfo.uid, "clear data");
-                    mActivityTaskManager.getRecentTasks().removeTasksByPackageName(packageName, resolvedUserId);
+                    mAtmInternal.removeRecentTasksByPackageName(packageName, resolvedUserId);
                 }
             }
 
@@ -5815,16 +5819,7 @@
 
     @Override
     public void updateLockTaskPackages(int userId, String[] packages) {
-        final int callingUid = Binder.getCallingUid();
-        if (callingUid != 0 && callingUid != SYSTEM_UID) {
-            enforceCallingPermission(android.Manifest.permission.UPDATE_LOCK_TASK_PACKAGES,
-                    "updateLockTaskPackages()");
-        }
-        synchronized (this) {
-            if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Whitelisting " + userId + ":" +
-                    Arrays.toString(packages));
-            mActivityTaskManager.getLockTaskController().updateLockTaskPackages(userId, packages);
-        }
+        mActivityTaskManager.updateLockTaskPackages(userId, packages);
     }
 
     @Override
@@ -7284,7 +7279,6 @@
         mBatteryStatsService.shutdown();
         synchronized (this) {
             mProcessStats.shutdownLocked();
-            mActivityTaskManager.notifyTaskPersisterLocked(null, true);
         }
 
         return timedout;
@@ -9165,6 +9159,11 @@
                 pw.println("-------------------------------------------------------------------------------");
             }
             dumpBinderProxies(pw);
+            pw.println();
+            if (dumpAll) {
+                pw.println("-------------------------------------------------------------------------------");
+            }
+            dumpLmkLocked(pw);
         }
     }
 
@@ -9355,6 +9354,10 @@
                 synchronized (this) {
                     dumpOomLocked(fd, pw, args, opti, true);
                 }
+            } else if ("lmk".equals(cmd)) {
+                synchronized (this) {
+                    dumpLmkLocked(pw);
+                }
             } else if ("permissions".equals(cmd) || "perm".equals(cmd)) {
                 synchronized (this) {
                     dumpPermissionsLocked(fd, pw, args, opti, true, null);
@@ -10384,15 +10387,42 @@
         dumpProcessesToGc(pw, needSep, null);
 
         pw.println();
-        pw.println("  mHomeProcess: " + mActivityTaskManager.mHomeProcess);
-        pw.println("  mPreviousProcess: " + mActivityTaskManager.mPreviousProcess);
-        if (mActivityTaskManager.mHeavyWeightProcess != null) {
-            pw.println("  mHeavyWeightProcess: " + mActivityTaskManager.mHeavyWeightProcess);
-        }
+        mAtmInternal.dumpForOom(pw);
 
         return true;
     }
 
+    private boolean reportLmkKillAtOrBelow(PrintWriter pw, int oom_adj) {
+        Integer cnt = ProcessList.getLmkdKillCount(0, oom_adj);
+        if (cnt != null) {
+            pw.println("    kills at or below oom_adj " + oom_adj + ": " + cnt);
+            return true;
+        }
+        return false;
+    }
+
+    boolean dumpLmkLocked(PrintWriter pw) {
+        pw.println("ACTIVITY MANAGER LMK KILLS (dumpsys activity lmk)");
+        Integer cnt = ProcessList.getLmkdKillCount(ProcessList.UNKNOWN_ADJ,
+                ProcessList.UNKNOWN_ADJ);
+        if (cnt == null) {
+            return false;
+        }
+        pw.println("  Total number of kills: " + cnt);
+
+        return reportLmkKillAtOrBelow(pw, ProcessList.CACHED_APP_MAX_ADJ) &&
+            reportLmkKillAtOrBelow(pw, ProcessList.CACHED_APP_MIN_ADJ) &&
+            reportLmkKillAtOrBelow(pw, ProcessList.SERVICE_B_ADJ) &&
+            reportLmkKillAtOrBelow(pw, ProcessList.PREVIOUS_APP_ADJ) &&
+            reportLmkKillAtOrBelow(pw, ProcessList.HOME_APP_ADJ) &&
+            reportLmkKillAtOrBelow(pw, ProcessList.SERVICE_ADJ) &&
+            reportLmkKillAtOrBelow(pw, ProcessList.HEAVY_WEIGHT_APP_ADJ) &&
+            reportLmkKillAtOrBelow(pw, ProcessList.BACKUP_APP_ADJ) &&
+            reportLmkKillAtOrBelow(pw, ProcessList.PERCEPTIBLE_APP_ADJ) &&
+            reportLmkKillAtOrBelow(pw, ProcessList.VISIBLE_APP_ADJ) &&
+            reportLmkKillAtOrBelow(pw, ProcessList.FOREGROUND_APP_ADJ);
+    }
+
     /**
      * There are three ways to call this:
      *  - no provider specified: dump all the providers
@@ -10415,7 +10445,7 @@
         return mProviderMap.dumpProviderProto(fd, pw, name, args);
     }
 
-    static class ItemMatcher {
+    public static class ItemMatcher {
         ArrayList<ComponentName> components;
         ArrayList<String> strings;
         ArrayList<Integer> objects;
@@ -13367,7 +13397,8 @@
 
     boolean isPendingBroadcastProcessLocked(int pid) {
         return mFgBroadcastQueue.isPendingBroadcastProcessLocked(pid)
-                || mBgBroadcastQueue.isPendingBroadcastProcessLocked(pid);
+                || mBgBroadcastQueue.isPendingBroadcastProcessLocked(pid)
+                || mOffloadBroadcastQueue.isPendingBroadcastProcessLocked(pid);
     }
 
     void skipPendingBroadcastLocked(int pid) {
@@ -13971,16 +14002,14 @@
                                     forceStopPackageLocked(list[i], -1, false, true, true,
                                             false, false, userId, "storage unmount");
                                 }
-                                mActivityTaskManager.getRecentTasks().cleanupLocked(
-                                        UserHandle.USER_ALL);
+                                mAtmInternal.cleanupRecentTasksForUser(UserHandle.USER_ALL);
                                 sendPackageBroadcastLocked(
                                         ApplicationThreadConstants.EXTERNAL_STORAGE_UNAVAILABLE,
                                         list, userId);
                             }
                             break;
                         case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:
-                            mActivityTaskManager.getRecentTasks().cleanupLocked(
-                                    UserHandle.USER_ALL);
+                            mAtmInternal.cleanupRecentTasksForUser(UserHandle.USER_ALL);
                             break;
                         case Intent.ACTION_PACKAGE_REMOVED:
                         case Intent.ACTION_PACKAGE_CHANGED:
@@ -14013,7 +14042,7 @@
                                         mUgmInternal.removeUriPermissionsForPackage(ssp, userId,
                                                 true, false);
 
-                                        mActivityTaskManager.getRecentTasks().removeTasksByPackageName(ssp, userId);
+                                        mAtmInternal.removeRecentTasksByPackageName(ssp, userId);
 
                                         mServices.forceStopPackageLocked(ssp, userId);
                                         mAtmInternal.onPackageUninstalled(ssp);
@@ -14043,10 +14072,8 @@
                             final int userHandle = intent.getIntExtra(
                                     Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
 
-                            synchronized(ActivityManagerService.this) {
-                                mActivityTaskManager.getRecentTasks().onPackagesSuspendedChanged(
-                                        packageNames, suspended, userHandle);
-                            }
+                            mAtmInternal.onPackagesSuspendedChanged(packageNames, suspended,
+                                    userHandle);
                             break;
                     }
                     break;
@@ -14613,10 +14640,16 @@
         try {
             boolean doNext = false;
             BroadcastRecord r;
+            BroadcastQueue queue;
 
             synchronized(this) {
-                BroadcastQueue queue = (flags & Intent.FLAG_RECEIVER_FOREGROUND) != 0
-                        ? mFgBroadcastQueue : mBgBroadcastQueue;
+                if (isOnOffloadQueue(flags)) {
+                    queue = mOffloadBroadcastQueue;
+                } else {
+                    queue = (flags & Intent.FLAG_RECEIVER_FOREGROUND) != 0
+                            ? mFgBroadcastQueue : mBgBroadcastQueue;
+                }
+
                 r = queue.getMatchingOrderedReceiver(who);
                 if (r != null) {
                     doNext = r.queue.finishReceiverLocked(r, resultCode,
@@ -15446,7 +15479,7 @@
             }
         }
 
-        if (wpc == mActivityTaskManager.mHomeProcess) {
+        if (wpc.isHomeProcess()) {
             if (adj > ProcessList.HOME_APP_ADJ) {
                 // This process is hosting what we currently consider to be the
                 // home app, so we don't want to let it go into the background.
@@ -15467,7 +15500,7 @@
             }
         }
 
-        if (wpc == mActivityTaskManager.mPreviousProcess && app.hasActivities()) {
+        if (wpc.isPreviousProcess() && app.hasActivities()) {
             if (adj > ProcessList.PREVIOUS_APP_ADJ) {
                 // This was the previous process that showed UI to the user.
                 // We want to try to keep it around more aggressively, to give
@@ -15544,7 +15577,7 @@
                                 "Raise procstate to started service: " + app);
                     }
                 }
-                if (app.hasShownUi && wpc != mActivityTaskManager.mHomeProcess) {
+                if (app.hasShownUi && !wpc.isHomeProcess()) {
                     // If this process has shown some UI, let it immediately
                     // go to the LRU list because it may be pretty heavy with
                     // UI stuff.  We'll tag it with a label just to help
@@ -15623,7 +15656,7 @@
                         if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {
                             // Not doing bind OOM management, so treat
                             // this guy more like a started service.
-                            if (app.hasShownUi && wpc != mActivityTaskManager.mHomeProcess) {
+                            if (app.hasShownUi && !wpc.isHomeProcess()) {
                                 // If this process has shown some UI, let it immediately
                                 // go to the LRU list because it may be pretty heavy with
                                 // UI stuff.  We'll tag it with a label just to help
@@ -15656,7 +15689,7 @@
                             // about letting this process get into the LRU
                             // list to be killed and restarted if needed for
                             // memory.
-                            if (app.hasShownUi && wpc != mActivityTaskManager.mHomeProcess
+                            if (app.hasShownUi && !wpc.isHomeProcess()
                                     && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
                                 if (adj >= ProcessList.CACHED_APP_MIN_ADJ) {
                                     adjType = "cch-bound-ui-services";
@@ -15862,7 +15895,7 @@
                 }
                 String adjType = null;
                 if (adj > clientAdj) {
-                    if (app.hasShownUi && wpc != mActivityTaskManager.mHomeProcess
+                    if (app.hasShownUi && !wpc.isHomeProcess()
                             && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
                         adjType = "cch-ui-provider";
                     } else {
@@ -16544,8 +16577,7 @@
                     if (curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
                         // do nothing if we already switched to RT
                         if (oldSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
-                            mActivityTaskManager.onTopProcChangedLocked(
-                                    app.getWindowProcessController());
+                            app.getWindowProcessController().onTopProcChanged();
                             if (mUseFifoUiScheduling) {
                                 // Switch UI pipeline for app to SCHED_FIFO
                                 app.savedPriority = Process.getThreadPriority(app.pid);
@@ -16577,8 +16609,7 @@
                         }
                     } else if (oldSchedGroup == ProcessList.SCHED_GROUP_TOP_APP &&
                             curSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
-                        mActivityTaskManager.onTopProcChangedLocked(
-                                app.getWindowProcessController());
+                        app.getWindowProcessController().onTopProcChanged();
                         if (mUseFifoUiScheduling) {
                             try {
                                 // Reset UI pipeline to SCHED_OTHER
@@ -17355,8 +17386,8 @@
             }
             int factor = numTrimming/3;
             int minFactor = 2;
-            if (mActivityTaskManager.mHomeProcess != null) minFactor++;
-            if (mActivityTaskManager.mPreviousProcess != null) minFactor++;
+            if (mAtmInternal.getHomeProcess() != null) minFactor++;
+            if (mAtmInternal.getPreviousProcess() != null) minFactor++;
             if (factor < minFactor) factor = minFactor;
             int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
             for (int i=N-1; i>=0; i--) {
@@ -18648,7 +18679,8 @@
                                     memoryStat.rssInBytes,
                                     memoryStat.cacheInBytes,
                                     memoryStat.swapInBytes,
-                                    memoryStat.rssHighWatermarkInBytes);
+                                    memoryStat.rssHighWatermarkInBytes,
+                                    memoryStat.startTimeNanos);
                     processMemoryStates.add(processMemoryState);
                 }
             }
@@ -18671,7 +18703,7 @@
                 ProcessMemoryState processMemoryState = new ProcessMemoryState(uid, processName,
                         oomScore, memoryStat.pgfault, memoryStat.pgmajfault,
                         memoryStat.rssInBytes, memoryStat.cacheInBytes, memoryStat.swapInBytes,
-                        memoryStat.rssHighWatermarkInBytes);
+                        memoryStat.rssHighWatermarkInBytes, memoryStat.startTimeNanos);
                 processMemoryStates.add(processMemoryState);
             }
             return processMemoryStates;
@@ -19512,4 +19544,8 @@
             }
         }
     }
+
+    private boolean isOnOffloadQueue(int flags) {
+        return ((flags & Intent.FLAG_RECEIVER_OFFLOAD) != 0);
+    }
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 96601a2..fe402ea 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -2736,7 +2736,7 @@
     int runWrite(PrintWriter pw) {
         mInternal.enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
                 "registerUidObserver()");
-        mInternal.mActivityTaskManager.getRecentTasks().flush();
+        mInternal.mAtmInternal.flushRecentTasks();
         pw.println("All tasks persisted.");
         return 0;
     }
diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityTaskManagerDebugConfig.java
index cf72738..4f2a254 100644
--- a/services/core/java/com/android/server/am/ActivityTaskManagerDebugConfig.java
+++ b/services/core/java/com/android/server/am/ActivityTaskManagerDebugConfig.java
@@ -69,6 +69,7 @@
     static final boolean DEBUG_METRICS = DEBUG_ALL || false;
 
     static final String POSTFIX_APP = APPEND_CATEGORY_NAME ? "_App" : "";
+    static final String POSTFIX_CLEANUP = (APPEND_CATEGORY_NAME) ? "_Cleanup" : "";
     static final String POSTFIX_IDLE = APPEND_CATEGORY_NAME ? "_Idle" : "";
     static final String POSTFIX_RELEASE = APPEND_CATEGORY_NAME ? "_Release" : "";
     static final String POSTFIX_USER_LEAVING = APPEND_CATEGORY_NAME ? "_UserLeaving" : "";
diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
index 02707fb..5b0a4a9 100644
--- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
@@ -273,6 +273,7 @@
 import java.lang.ref.WeakReference;
 import java.text.DateFormat;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Date;
 import java.util.HashSet;
 import java.util.List;
@@ -397,7 +398,7 @@
     // VoiceInteractionManagerService
     ComponentName mActiveVoiceInteractionServiceComponent;
 
-    private VrController mVrController;
+    VrController mVrController;
     KeyguardController mKeyguardController;
     private final ClientLifecycleManager mLifecycleManager;
     private TaskChangeNotificationController mTaskChangeNotificationController;
@@ -611,23 +612,27 @@
         GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version", GL_ES_VERSION_UNDEFINED);
     }
 
-    void onSystemReady() {
-        mHasHeavyWeightFeature = mContext.getPackageManager().hasSystemFeature(
-                PackageManager.FEATURE_CANT_SAVE_STATE);
-        mAssistUtils = new AssistUtils(mContext);
-        mVrController.onSystemReady();
-        mRecentTasks.onSystemReadyLocked();
+    public void onSystemReady() {
+        synchronized (mGlobalLock) {
+            mHasHeavyWeightFeature = mContext.getPackageManager().hasSystemFeature(
+                    PackageManager.FEATURE_CANT_SAVE_STATE);
+            mAssistUtils = new AssistUtils(mContext);
+            mVrController.onSystemReady();
+            mRecentTasks.onSystemReadyLocked();
+        }
     }
 
-    void onInitPowerManagement() {
-        mStackSupervisor.initPowerManagement();
-        final PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
-        mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
-        mVoiceWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*voice*");
-        mVoiceWakeLock.setReferenceCounted(false);
+    public void onInitPowerManagement() {
+        synchronized (mGlobalLock) {
+            mStackSupervisor.initPowerManagement();
+            final PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+            mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
+            mVoiceWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*voice*");
+            mVoiceWakeLock.setReferenceCounted(false);
+        }
     }
 
-    void installSystemProviders() {
+    public void installSystemProviders() {
         mFontScaleSettingObserver = new FontScaleSettingObserver();
     }
 
@@ -736,9 +741,11 @@
         mKeyguardController = mStackSupervisor.getKeyguardController();
     }
 
-    void onActivityManagerInternalAdded() {
-        mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
-        mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
+    public void onActivityManagerInternalAdded() {
+        synchronized (mGlobalLock) {
+            mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
+            mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
+        }
     }
 
     int increaseConfigurationSeqLocked() {
@@ -752,14 +759,18 @@
         return supervisor;
     }
 
-    void setWindowManager(WindowManagerService wm) {
-        mWindowManager = wm;
-        mLockTaskController.setWindowManager(wm);
-        mStackSupervisor.setWindowManager(wm);
+    public void setWindowManager(WindowManagerService wm) {
+        synchronized (mGlobalLock) {
+            mWindowManager = wm;
+            mLockTaskController.setWindowManager(wm);
+            mStackSupervisor.setWindowManager(wm);
+        }
     }
 
-    void setUsageStatsManager(UsageStatsManagerInternal usageStatsManager) {
-        mUsageStatsInternal = usageStatsManager;
+    public void setUsageStatsManager(UsageStatsManagerInternal usageStatsManager) {
+        synchronized (mGlobalLock) {
+            mUsageStatsInternal = usageStatsManager;
+        }
     }
 
     UserManagerService getUserManager() {
@@ -2135,7 +2146,7 @@
         }
     }
 
-    boolean isControllerAMonkey() {
+    public boolean isControllerAMonkey() {
         synchronized (mGlobalLock) {
             return mController != null && mControllerIsAMonkey;
         }
@@ -2512,6 +2523,20 @@
     }
 
     @Override
+    public void updateLockTaskPackages(int userId, String[] packages) {
+        final int callingUid = Binder.getCallingUid();
+        if (callingUid != 0 && callingUid != SYSTEM_UID) {
+            mAmInternal.enforceCallingPermission(Manifest.permission.UPDATE_LOCK_TASK_PACKAGES,
+                    "updateLockTaskPackages()");
+        }
+        synchronized (this) {
+            if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Whitelisting " + userId + ":"
+                    + Arrays.toString(packages));
+            getLockTaskController().updateLockTaskPackages(userId, packages);
+        }
+    }
+
+    @Override
     public boolean isInLockTaskMode() {
         return getLockTaskModeState() != LOCK_TASK_MODE_NONE;
     }
@@ -2880,7 +2905,7 @@
         });
     }
 
-    void onScreenAwakeChanged(boolean isAwake) {
+    public void onScreenAwakeChanged(boolean isAwake) {
         mH.post(() -> {
             for (int i = mScreenObservers.size() - 1; i >= 0; i--) {
                 mScreenObservers.get(i).onAwakeStateChanged(isAwake);
@@ -4355,10 +4380,6 @@
         mRecentTasks.notifyTaskPersisterLocked(task, flush);
     }
 
-    void onTopProcChangedLocked(WindowProcessController proc) {
-        mVrController.onTopProcChangedLocked(proc);
-    }
-
     boolean isKeyguardLocked() {
         return mKeyguardController.isKeyguardLocked();
     }
@@ -4617,17 +4638,6 @@
         }
     }
 
-    void updateUserConfiguration() {
-        synchronized (mGlobalLock) {
-            final Configuration configuration = new Configuration(getGlobalConfiguration());
-            final int currentUserId = mAmInternal.getCurrentUserId();
-            Settings.System.adjustConfigurationForUser(mContext.getContentResolver(), configuration,
-                    currentUserId, Settings.System.canWrite(mContext));
-            updateConfigurationLocked(configuration, null /* starting */, false /* initLocale */,
-                    false /* persistent */, currentUserId, false /* deferResume */);
-        }
-    }
-
     private boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
             boolean initLocale, boolean persistent, int userId, boolean deferResume) {
         return updateConfigurationLocked(values, starting, initLocale, persistent, userId,
@@ -4905,15 +4915,6 @@
         }
     }
 
-    boolean canShowErrorDialogs() {
-        return mShowDialogs && !mSleeping && !mShuttingDown
-                && !mKeyguardController.isKeyguardOrAodShowing(DEFAULT_DISPLAY)
-                && !hasUserRestriction(UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS,
-                mAmInternal.getCurrentUserId())
-                && !(UserManager.isDeviceInDemoMode(mContext)
-                && mAmInternal.getCurrentUser().isDemo());
-    }
-
     static long getInputDispatchingTimeoutLocked(ActivityRecord r) {
         if (r == null || !r.hasProcess()) {
             return KEY_DISPATCHING_TIMEOUT_MS;
@@ -5908,6 +5909,7 @@
                 mShuttingDown = true;
                 mStackSupervisor.prepareForShutdownLocked();
                 updateEventDispatchingLocked(booted);
+                notifyTaskPersisterLocked(null, true);
                 return mStackSupervisor.shutdownLocked(timeout);
             }
         }
@@ -6588,6 +6590,17 @@
         }
 
         @Override
+        public void dumpForOom(PrintWriter pw) {
+            synchronized (mGlobalLock) {
+                pw.println("  mHomeProcess: " + mHomeProcess);
+                pw.println("  mPreviousProcess: " + mPreviousProcess);
+                if (mHeavyWeightProcess != null) {
+                    pw.println("  mHeavyWeightProcess: " + mHeavyWeightProcess);
+                }
+            }
+        }
+
+        @Override
         public boolean canGcNow() {
             synchronized (mGlobalLock) {
                 return isSleeping() || mStackSupervisor.allResumedActivitiesIdle();
@@ -6689,5 +6702,107 @@
                 mPendingTempWhitelist.remove(uid);
             }
         }
+
+        @Override
+        public boolean handleAppCrashInActivityController(String processName, int pid,
+                String shortMsg, String longMsg, long timeMillis, String stackTrace,
+                Runnable killCrashingAppCallback) {
+            synchronized (mGlobalLock) {
+                if (mController == null) {
+                    return false;
+                }
+
+                try {
+                    if (!mController.appCrashed(processName, pid, shortMsg, longMsg, timeMillis,
+                            stackTrace)) {
+                        killCrashingAppCallback.run();
+                        return true;
+                    }
+                } catch (RemoteException e) {
+                    mController = null;
+                    Watchdog.getInstance().setActivityController(null);
+                }
+                return false;
+            }
+        }
+
+        @Override
+        public void removeRecentTasksByPackageName(String packageName, int userId) {
+            synchronized (mGlobalLock) {
+                mRecentTasks.removeTasksByPackageName(packageName, userId);
+            }
+        }
+
+        @Override
+        public void cleanupRecentTasksForUser(int userId) {
+            synchronized (mGlobalLock) {
+                mRecentTasks.cleanupLocked(userId);
+            }
+        }
+
+        @Override
+        public void loadRecentTasksForUser(int userId) {
+            synchronized (mGlobalLock) {
+                mRecentTasks.loadUserRecentsLocked(userId);
+            }
+        }
+
+        @Override
+        public void onPackagesSuspendedChanged(String[] packages, boolean suspended, int userId) {
+            synchronized (mGlobalLock) {
+                mRecentTasks.onPackagesSuspendedChanged(packages, suspended, userId);
+            }
+        }
+
+        @Override
+        public void flushRecentTasks() {
+            mRecentTasks.flush();
+        }
+
+        @Override
+        public WindowProcessController getHomeProcess() {
+            synchronized (mGlobalLock) {
+                return mHomeProcess;
+            }
+        }
+
+        @Override
+        public WindowProcessController getPreviousProcess() {
+            synchronized (mGlobalLock) {
+                return mPreviousProcess;
+            }
+        }
+
+        @Override
+        public void clearLockedTasks(String reason) {
+            synchronized (mGlobalLock) {
+                getLockTaskController().clearLockedTasks(reason);
+            }
+        }
+
+        @Override
+        public void updateUserConfiguration() {
+            synchronized (mGlobalLock) {
+                final Configuration configuration = new Configuration(getGlobalConfiguration());
+                final int currentUserId = mAmInternal.getCurrentUserId();
+                Settings.System.adjustConfigurationForUser(mContext.getContentResolver(),
+                        configuration, currentUserId, Settings.System.canWrite(mContext));
+                updateConfigurationLocked(configuration, null /* starting */,
+                        false /* initLocale */, false /* persistent */, currentUserId,
+                        false /* deferResume */);
+            }
+        }
+
+        @Override
+        public boolean canShowErrorDialogs() {
+            synchronized (mGlobalLock) {
+                return mShowDialogs && !mSleeping && !mShuttingDown
+                        && !mKeyguardController.isKeyguardOrAodShowing(DEFAULT_DISPLAY)
+                        && !hasUserRestriction(UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS,
+                        mAmInternal.getCurrentUserId())
+                        && !(UserManager.isDeviceInDemoMode(mContext)
+                        && mAmInternal.getCurrentUser().isDemo());
+            }
+        }
     }
 }
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index e8ec057..44f69b1 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -474,7 +474,7 @@
                 mService.mProcessList.removeProcessLocked(r, false, true, "crash");
                 if (taskId != INVALID_TASK_ID) {
                     try {
-                        mService.mActivityTaskManager.startActivityFromRecents(taskId,
+                        mService.startActivityFromRecents(taskId,
                                 ActivityOptions.makeBasic().toBundle());
                     } catch (IllegalArgumentException e) {
                         // Hmm...that didn't work. Task should either be in recents or associated
@@ -526,41 +526,29 @@
                                                        String shortMsg, String longMsg,
                                                        String stackTrace, long timeMillis,
                                                        int callingPid, int callingUid) {
-        if (mService.mActivityTaskManager.mController == null) {
-            return false;
-        }
+        String name = r != null ? r.processName : null;
+        int pid = r != null ? r.pid : callingPid;
+        int uid = r != null ? r.info.uid : callingUid;
 
-        try {
-            String name = r != null ? r.processName : null;
-            int pid = r != null ? r.pid : callingPid;
-            int uid = r != null ? r.info.uid : callingUid;
-            if (!mService.mActivityTaskManager.mController.appCrashed(name, pid,
-                    shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) {
-                if ("1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"))
-                        && "Native crash".equals(crashInfo.exceptionClassName)) {
-                    Slog.w(TAG, "Skip killing native crashed app " + name
-                            + "(" + pid + ") during testing");
-                } else {
-                    Slog.w(TAG, "Force-killing crashed app " + name
-                            + " at watcher's request");
-                    if (r != null) {
-                        if (!makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace, null))
-                        {
-                            r.kill("crash", true);
-                        }
-                    } else {
-                        // Huh.
-                        Process.killProcess(pid);
-                        ProcessList.killProcessGroup(uid, pid);
+        return mService.mAtmInternal.handleAppCrashInActivityController(
+                name, pid, shortMsg, longMsg, timeMillis, crashInfo.stackTrace, () -> {
+            if ("1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"))
+                    && "Native crash".equals(crashInfo.exceptionClassName)) {
+                Slog.w(TAG, "Skip killing native crashed app " + name
+                        + "(" + pid + ") during testing");
+            } else {
+                Slog.w(TAG, "Force-killing crashed app " + name + " at watcher's request");
+                if (r != null) {
+                    if (!makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace, null)) {
+                        r.kill("crash", true);
                     }
+                } else {
+                    // Huh.
+                    Process.killProcess(pid);
+                    ProcessList.killProcessGroup(uid, pid);
                 }
-                return true;
             }
-        } catch (RemoteException e) {
-            mService.mActivityTaskManager.mController = null;
-            Watchdog.getInstance().setActivityController(null);
-        }
-        return false;
+        });
     }
 
     private boolean makeAppCrashingLocked(ProcessRecord app,
@@ -742,7 +730,7 @@
         // with a home activity running in the process to prevent a repeatedly crashing app
         // from blocking the user to manually clear the list.
         final WindowProcessController proc = app.getWindowProcessController();
-        final WindowProcessController homeProc = mService.mActivityTaskManager.mHomeProcess;
+        final WindowProcessController homeProc = mService.mAtmInternal.getHomeProcess();
         if (proc == homeProc && proc.hasActivities()
                 && (homeProc.mInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
             proc.clearPackagePreferredForHomeActivities();
@@ -806,7 +794,7 @@
                     mService.mUserController.getCurrentUserId()) != 0;
             final boolean crashSilenced = mAppsNotReportingCrashes != null &&
                     mAppsNotReportingCrashes.contains(proc.info.packageName);
-            if ((mService.mActivityTaskManager.canShowErrorDialogs() || showBackground)
+            if ((mService.mAtmInternal.canShowErrorDialogs() || showBackground)
                     && !crashSilenced
                     && (showFirstCrash || showFirstCrashDevOption || data.repeating)) {
                 proc.crashDialog = dialogToShow = new AppErrorDialog(mContext, mService, data);
@@ -859,7 +847,7 @@
 
             boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
                     Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
-            if (mService.mActivityTaskManager.canShowErrorDialogs() || showBackground) {
+            if (mService.mAtmInternal.canShowErrorDialogs() || showBackground) {
                 dialogToShow = new AppNotRespondingDialog(mService, mContext, data);
                 proc.anrDialog = dialogToShow;
             } else {
diff --git a/services/core/java/com/android/server/am/LockTaskController.java b/services/core/java/com/android/server/am/LockTaskController.java
index 5b31d5f..d5f2d34 100644
--- a/services/core/java/com/android/server/am/LockTaskController.java
+++ b/services/core/java/com/android/server/am/LockTaskController.java
@@ -78,7 +78,8 @@
  * mode that can be launched via System UI as well as the fully locked mode that can be achieved
  * on fully managed devices.
  *
- * Note: All methods in this class should only be called with the ActivityManagerService lock held.
+ * Note: All methods in this class should only be called with the ActivityTaskManagerService lock
+ * held.
  *
  * @see Activity#startLockTask()
  * @see Activity#stopLockTask()
diff --git a/services/core/java/com/android/server/am/MemoryStatUtil.java b/services/core/java/com/android/server/am/MemoryStatUtil.java
index 85ee7e6..f77be5b 100644
--- a/services/core/java/com/android/server/am/MemoryStatUtil.java
+++ b/services/core/java/com/android/server/am/MemoryStatUtil.java
@@ -23,6 +23,8 @@
 import android.annotation.Nullable;
 import android.os.FileUtils;
 import android.os.SystemProperties;
+import android.system.Os;
+import android.system.OsConstants;
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -36,7 +38,7 @@
 /**
  * Static utility methods related to {@link MemoryStat}.
  */
-final class MemoryStatUtil {
+public final class MemoryStatUtil {
     /**
      * Which native processes to create {@link MemoryStat} for.
      *
@@ -71,6 +73,7 @@
 
     static final int BYTES_IN_KILOBYTE = 1024;
     static final int PAGE_SIZE = 4096;
+    static final long JIFFY_NANOS = 1_000_000_000 / Os.sysconf(OsConstants._SC_CLK_TCK);
 
     private static final String TAG = TAG_WITH_CLASS_NAME ? "MemoryStatUtil" : TAG_AM;
 
@@ -103,6 +106,7 @@
 
     private static final int PGFAULT_INDEX = 9;
     private static final int PGMAJFAULT_INDEX = 11;
+    private static final int START_TIME_INDEX = 21;
     private static final int RSS_IN_PAGES_INDEX = 23;
 
     private MemoryStatUtil() {}
@@ -114,7 +118,7 @@
      * Returns null if no stats can be read.
      */
     @Nullable
-    static MemoryStat readMemoryStatFromFilesystem(int uid, int pid) {
+    public static MemoryStat readMemoryStatFromFilesystem(int uid, int pid) {
         return hasMemcg() ? readMemoryStatFromMemcg(uid, pid) : readMemoryStatFromProcfs(pid);
     }
 
@@ -238,6 +242,7 @@
             memoryStat.pgfault = Long.parseLong(splits[PGFAULT_INDEX]);
             memoryStat.pgmajfault = Long.parseLong(splits[PGMAJFAULT_INDEX]);
             memoryStat.rssInBytes = Long.parseLong(splits[RSS_IN_PAGES_INDEX]) * PAGE_SIZE;
+            memoryStat.startTimeNanos = Long.parseLong(splits[START_TIME_INDEX]) * JIFFY_NANOS;
             return memoryStat;
         } catch (NumberFormatException e) {
             Slog.e(TAG, "Failed to parse value", e);
@@ -266,7 +271,7 @@
         return DEVICE_HAS_PER_APP_MEMCG;
     }
 
-    static final class MemoryStat {
+    public static final class MemoryStat {
         /** Number of page faults */
         long pgfault;
         /** Number of major page faults */
@@ -279,5 +284,7 @@
         long swapInBytes;
         /** Number of bytes of peak anonymous and swap cache memory */
         long rssHighWatermarkInBytes;
+        /** Device time when the processes started. */
+        long startTimeNanos;
     }
 }
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 805b979b..6741dc0 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -99,14 +99,22 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.io.InputStream;
 import java.io.PrintWriter;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
+import libcore.io.IoUtils;
+
 /**
  * Activity manager code dealing with processes.
+ *
+ * Method naming convention:
+ * <ul>
+ * <li> Methods suffixed with "LS" should be called within the {@link #sLmkdSocketLock} lock.
+ * </ul>
  */
 public final class ProcessList {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ProcessList" : TAG_AM;
@@ -229,10 +237,12 @@
     // LMK_PROCPRIO <pid> <uid> <prio>
     // LMK_PROCREMOVE <pid>
     // LMK_PROCPURGE
+    // LMK_GETKILLCNT
     static final byte LMK_TARGET = 0;
     static final byte LMK_PROCPRIO = 1;
     static final byte LMK_PROCREMOVE = 2;
     static final byte LMK_PROCPURGE = 3;
+    static final byte LMK_GETKILLCNT = 4;
 
     ActivityManagerService mService = null;
 
@@ -268,9 +278,17 @@
 
     private boolean mHaveDisplaySize;
 
+    private static Object sLmkdSocketLock = new Object();
+
+    @GuardedBy("sLmkdSocketLock")
     private static LocalSocket sLmkdSocket;
+
+    @GuardedBy("sLmkdSocketLock")
     private static OutputStream sLmkdOutputStream;
 
+    @GuardedBy("sLmkdSocketLock")
+    private static InputStream sLmkdInputStream;
+
     /**
      * Temporary to avoid allocations.  Protected by main lock.
      */
@@ -505,7 +523,7 @@
                 buf.putInt(mOomAdj[i]);
             }
 
-            writeLmkd(buf);
+            writeLmkd(buf, null);
             SystemProperties.set("sys.sysctl.extra_free_kbytes", Integer.toString(reserve));
         }
         // GB: 2048,3072,4096,6144,7168,8192
@@ -978,7 +996,7 @@
         buf.putInt(pid);
         buf.putInt(uid);
         buf.putInt(amt);
-        writeLmkd(buf);
+        writeLmkd(buf, null);
         long now = SystemClock.elapsedRealtime();
         if ((now-start) > 250) {
             Slog.w("ActivityManager", "SLOW OOM ADJ: " + (now-start) + "ms for pid " + pid
@@ -997,16 +1015,38 @@
         ByteBuffer buf = ByteBuffer.allocate(4 * 2);
         buf.putInt(LMK_PROCREMOVE);
         buf.putInt(pid);
-        writeLmkd(buf);
+        writeLmkd(buf, null);
     }
 
-    private static boolean openLmkdSocket() {
+    /*
+     * {@hide}
+     */
+    public static final Integer getLmkdKillCount(int min_oom_adj, int max_oom_adj) {
+        ByteBuffer buf = ByteBuffer.allocate(4 * 3);
+        ByteBuffer repl = ByteBuffer.allocate(4 * 2);
+        buf.putInt(LMK_GETKILLCNT);
+        buf.putInt(min_oom_adj);
+        buf.putInt(max_oom_adj);
+        if (writeLmkd(buf, repl)) {
+            int i = repl.getInt();
+            if (i != LMK_GETKILLCNT) {
+                Slog.e("ActivityManager", "Failed to get kill count, code mismatch");
+                return null;
+            }
+            return new Integer(repl.getInt());
+        }
+        return null;
+    }
+
+    @GuardedBy("sLmkdSocketLock")
+    private static boolean openLmkdSocketLS() {
         try {
             sLmkdSocket = new LocalSocket(LocalSocket.SOCKET_SEQPACKET);
             sLmkdSocket.connect(
                 new LocalSocketAddress("lmkd",
                         LocalSocketAddress.Namespace.RESERVED));
             sLmkdOutputStream = sLmkdSocket.getOutputStream();
+            sLmkdInputStream = sLmkdSocket.getInputStream();
         } catch (IOException ex) {
             Slog.w(TAG, "lowmemorykiller daemon socket open failed");
             sLmkdSocket = null;
@@ -1017,47 +1057,63 @@
     }
 
     // Never call directly, use writeLmkd() instead
-    private static boolean writeLmkdCommand(ByteBuffer buf) {
+    @GuardedBy("sLmkdSocketLock")
+    private static boolean writeLmkdCommandLS(ByteBuffer buf) {
         try {
             sLmkdOutputStream.write(buf.array(), 0, buf.position());
         } catch (IOException ex) {
             Slog.w(TAG, "Error writing to lowmemorykiller socket");
-
-            try {
-                sLmkdSocket.close();
-            } catch (IOException ex2) {
-            }
-
+            IoUtils.closeQuietly(sLmkdSocket);
             sLmkdSocket = null;
             return false;
         }
         return true;
     }
 
-    private static void writeLmkd(ByteBuffer buf) {
-
-        for (int i = 0; i < 3; i++) {
-            if (sLmkdSocket == null) {
-                if (openLmkdSocket() == false) {
-                    try {
-                        Thread.sleep(1000);
-                    } catch (InterruptedException ie) {
-                    }
-                    continue;
-                }
-
-                // Purge any previously registered pids
-                ByteBuffer purge_buf = ByteBuffer.allocate(4);
-                purge_buf.putInt(LMK_PROCPURGE);
-                if (writeLmkdCommand(purge_buf) == false) {
-                    // Write failed, skip the rest and retry
-                    continue;
-                }
+    // Never call directly, use writeLmkd() instead
+    @GuardedBy("sLmkdSocketLock")
+    private static boolean readLmkdReplyLS(ByteBuffer buf) {
+        int len;
+        try {
+            len = sLmkdInputStream.read(buf.array(), 0, buf.array().length);
+            if (len == buf.array().length) {
+                return true;
             }
-            if (writeLmkdCommand(buf)) {
-                return;
+        } catch (IOException ex) {
+            Slog.w(TAG, "Error reading from lowmemorykiller socket");
+        }
+
+        IoUtils.closeQuietly(sLmkdSocket);
+        sLmkdSocket = null;
+        return false;
+    }
+
+    private static boolean writeLmkd(ByteBuffer buf, ByteBuffer repl) {
+        synchronized (sLmkdSocketLock) {
+            for (int i = 0; i < 3; i++) {
+                if (sLmkdSocket == null) {
+                    if (openLmkdSocketLS() == false) {
+                        try {
+                            Thread.sleep(1000);
+                        } catch (InterruptedException ie) {
+                        }
+                        continue;
+                    }
+
+                    // Purge any previously registered pids
+                    ByteBuffer purge_buf = ByteBuffer.allocate(4);
+                    purge_buf.putInt(LMK_PROCPURGE);
+                    if (writeLmkdCommandLS(purge_buf) == false) {
+                        // Write failed, skip the rest and retry
+                        continue;
+                    }
+                }
+                if (writeLmkdCommandLS(buf) && (repl == null || readLmkdReplyLS(repl))) {
+                    return true;
+                }
             }
         }
+        return false;
     }
 
     static void killProcessGroup(int uid, int pid) {
@@ -1982,8 +2038,7 @@
             StatsLog.write(StatsLog.ISOLATED_UID_CHANGED, info.uid, uid,
                     StatsLog.ISOLATED_UID_CHANGED__EVENT__CREATED);
         }
-        final ProcessRecord r = new ProcessRecord(mService, info, proc, uid,
-                mService.getGlobalConfiguration());
+        final ProcessRecord r = new ProcessRecord(mService, info, proc, uid);
 
         if (!mService.mBooted && !mService.mBooting
                 && userId == UserHandle.USER_SYSTEM
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index fa7a08b..683754c 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -535,7 +535,7 @@
     }
 
     ProcessRecord(ActivityManagerService _service, ApplicationInfo _info, String _processName,
-            int _uid, Configuration config) {
+            int _uid) {
         mService = _service;
         info = _info;
         isolated = _info.uid != _uid;
@@ -549,7 +549,7 @@
         removed = false;
         lastStateTime = lastPssTime = nextPssTime = SystemClock.uptimeMillis();
         mWindowProcessController = new WindowProcessController(
-                mService.mActivityTaskManager, info, processName, uid, userId, this, this, config);
+                mService.mActivityTaskManager, info, processName, uid, userId, this, this);
         pkgList.put(_info.packageName, new ProcessStats.ProcessStateHolder(_info.longVersionCode));
     }
 
@@ -1244,19 +1244,7 @@
         ArrayList<Integer> firstPids = new ArrayList<>(5);
         SparseArray<Boolean> lastPids = new SparseArray<>(20);
 
-        if (mService.mActivityTaskManager.mController != null) {
-            try {
-                // 0 == continue, -1 = kill process immediately
-                int res = mService.mActivityTaskManager.mController.appEarlyNotResponding(
-                        processName, pid, annotation);
-                if (res < 0 && pid != MY_PID) {
-                    kill("anr", true);
-                }
-            } catch (RemoteException e) {
-                mService.mActivityTaskManager.mController = null;
-                Watchdog.getInstance().setActivityController(null);
-            }
-        }
+        mWindowProcessController.appEarlyNotResponding(annotation, () -> kill("anr", true));
 
         long anrTime = SystemClock.uptimeMillis();
         if (ActivityManagerService.MONITOR_CPU_USAGE) {
@@ -1271,7 +1259,7 @@
 
         synchronized (mService) {
             // PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down.
-            if (mService.mActivityTaskManager.mShuttingDown) {
+            if (mService.mAtmInternal.isShuttingDown()) {
                 Slog.i(TAG, "During shutdown skipping ANR: " + this + " " + annotation);
                 return;
             } else if (isNotResponding()) {
@@ -1412,25 +1400,13 @@
         mService.addErrorToDropBox("anr", this, processName, activityShortComponentName,
                 parentShortComponentName, parentPr, annotation, cpuInfo, tracesFile, null);
 
-        if (mService.mActivityTaskManager.mController != null) {
-            try {
-                // 0 == show dialog, 1 = keep waiting, -1 = kill process immediately
-                int res = mService.mActivityTaskManager.mController.appNotResponding(
-                        processName, pid, info.toString());
-                if (res != 0) {
-                    if (res < 0 && pid != MY_PID) {
-                        kill("anr", true);
-                    } else {
-                        synchronized (mService) {
-                            mService.mServices.scheduleServiceTimeoutLocked(this);
-                        }
+        if (mWindowProcessController.appNotResponding(info.toString(), () -> kill("anr", true),
+                () -> {
+                    synchronized (mService) {
+                        mService.mServices.scheduleServiceTimeoutLocked(this);
                     }
-                    return;
-                }
-            } catch (RemoteException e) {
-                mService.mActivityTaskManager.mController = null;
-                Watchdog.getInstance().setActivityController(null);
-            }
+                })) {
+            return;
         }
 
         synchronized (mService) {
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index d2dd3db..353f787 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -22,14 +22,15 @@
 import static android.app.ActivityManager.USER_OP_ERROR_RELATED_USERS_CANNOT_STOP;
 import static android.app.ActivityManager.USER_OP_IS_CURRENT;
 import static android.app.ActivityManager.USER_OP_SUCCESS;
-import static android.os.Process.SHELL_UID;
-import static android.os.Process.SYSTEM_UID;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
 import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
 import static android.app.ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
+import static android.os.Process.SHELL_UID;
+import static android.os.Process.SYSTEM_UID;
+
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.ActivityManagerService.MY_PID;
 import static com.android.server.am.UserState.STATE_BOOTING;
 import static com.android.server.am.UserState.STATE_RUNNING_LOCKED;
@@ -40,7 +41,6 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
-import com.android.server.wm.ActivityTaskManagerInternal;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
 import android.app.Dialog;
@@ -99,6 +99,7 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemServiceManager;
 import com.android.server.pm.UserManagerService;
+import com.android.server.wm.ActivityTaskManagerInternal;
 import com.android.server.wm.WindowManagerService;
 
 import java.io.PrintWriter;
@@ -549,7 +550,8 @@
         final Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
         bootIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
         bootIntent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
-                | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+                | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
+                | Intent.FLAG_RECEIVER_OFFLOAD);
         mInjector.broadcastIntent(bootIntent, null, new IIntentReceiver.Stub() {
                     @Override
                     public void performReceive(Intent intent, int resultCode, String data,
@@ -2189,7 +2191,7 @@
         }
 
         void updateUserConfiguration() {
-            mService.mActivityTaskManager.updateUserConfiguration();
+            mService.mAtmInternal.updateUserConfiguration();
         }
 
         void clearBroadcastQueueForUser(int userId) {
@@ -2199,9 +2201,7 @@
         }
 
         void loadUserRecents(int userId) {
-            synchronized (mService) {
-                mService.mActivityTaskManager.getRecentTasks().loadUserRecentsLocked(userId);
-            }
+            mService.mAtmInternal.loadRecentTasksForUser(userId);
         }
 
         void startPersistentApps(int matchFlags) {
@@ -2254,13 +2254,11 @@
         }
 
         protected void clearAllLockedTasks(String reason) {
-            synchronized (mService) {
-                mService.mActivityTaskManager.getLockTaskController().clearLockedTasks(reason);
-            }
+            mService.mAtmInternal.clearLockedTasks(reason);
         }
 
         protected boolean isCallerRecents(int callingUid) {
-            return mService.mActivityTaskManager.getRecentTasks().isCallerRecents(callingUid);
+            return mService.mAtmInternal.isCallerRecents(callingUid);
         }
     }
 }
diff --git a/services/core/java/com/android/server/am/WindowProcessController.java b/services/core/java/com/android/server/am/WindowProcessController.java
index 94f1002..1dd8c52 100644
--- a/services/core/java/com/android/server/am/WindowProcessController.java
+++ b/services/core/java/com/android/server/am/WindowProcessController.java
@@ -19,6 +19,7 @@
 import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
 import static android.view.Display.INVALID_DISPLAY;
 
+import static com.android.server.am.ActivityManagerService.MY_PID;
 import static com.android.server.am.ActivityStack.ActivityState.DESTROYED;
 import static com.android.server.am.ActivityStack.ActivityState.DESTROYING;
 import static com.android.server.am.ActivityStack.ActivityState.PAUSED;
@@ -53,6 +54,7 @@
 
 import com.android.internal.app.HeavyWeightSwitcherActivity;
 import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.server.Watchdog;
 import com.android.server.wm.ConfigurationContainer;
 import com.android.server.wm.ConfigurationContainerListener;
 
@@ -155,8 +157,7 @@
     private int mDisplayId;
 
     WindowProcessController(ActivityTaskManagerService atm, ApplicationInfo info, String name,
-            int uid, int userId, Object owner, WindowProcessListener listener,
-            Configuration config) {
+            int uid, int userId, Object owner, WindowProcessListener listener) {
         mInfo = info;
         mName = name;
         mUid = uid;
@@ -166,8 +167,8 @@
         mAtm = atm;
         mLastReportedConfiguration = new Configuration();
         mDisplayId = INVALID_DISPLAY;
-        if (config != null) {
-            onConfigurationChanged(config);
+        if (atm != null) {
+            onConfigurationChanged(atm.getGlobalConfiguration());
         }
     }
 
@@ -807,6 +808,69 @@
         }
     }
 
+    public void appEarlyNotResponding(String annotation, Runnable killAppCallback) {
+        synchronized (mAtm.mGlobalLock) {
+            if (mAtm.mController == null) {
+                return;
+            }
+
+            try {
+                // 0 == continue, -1 = kill process immediately
+                int res = mAtm.mController.appEarlyNotResponding(mName, mPid, annotation);
+                if (res < 0 && mPid != MY_PID) {
+                    killAppCallback.run();
+                }
+            } catch (RemoteException e) {
+                mAtm.mController = null;
+                Watchdog.getInstance().setActivityController(null);
+            }
+        }
+    }
+
+    public boolean appNotResponding(String info, Runnable killAppCallback,
+            Runnable serviceTimeoutCallback) {
+        synchronized (mAtm.mGlobalLock) {
+            if (mAtm.mController == null) {
+                return false;
+            }
+
+            try {
+                // 0 == show dialog, 1 = keep waiting, -1 = kill process immediately
+                int res = mAtm.mController.appNotResponding(mName, mPid, info);
+                if (res != 0) {
+                    if (res < 0 && mPid != MY_PID) {
+                        killAppCallback.run();
+                    } else {
+                        serviceTimeoutCallback.run();
+                    }
+                    return true;
+                }
+            } catch (RemoteException e) {
+                mAtm.mController = null;
+                Watchdog.getInstance().setActivityController(null);
+            }
+            return false;
+        }
+    }
+
+    public void onTopProcChanged() {
+        synchronized (mAtm.mGlobalLock) {
+            mAtm.mVrController.onTopProcChangedLocked(this);
+        }
+    }
+
+    public boolean isHomeProcess() {
+        synchronized (mAtm.mGlobalLock) {
+            return this == mAtm.mHomeProcess;
+        }
+    }
+
+    public boolean isPreviousProcess() {
+        synchronized (mAtm.mGlobalLock) {
+            return this == mAtm.mPreviousProcess;
+        }
+    }
+
     public void dump(PrintWriter pw, String prefix) {
         synchronized (mAtm.mGlobalLock) {
             if (mActivities.size() > 0) {
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index b80dca6..278c55f 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -272,7 +272,7 @@
                 final int error = result.second;
 
                 // Check for errors, notify callback, and return
-                if (error != BiometricConstants.BIOMETRIC_ERROR_NONE) {
+                if (error != BiometricConstants.BIOMETRIC_SUCCESS) {
                     try {
                         final String hardwareUnavailable =
                                 getContext().getString(R.string.biometric_error_hw_unavailable);
@@ -540,7 +540,7 @@
             return new Pair<>(BIOMETRIC_NONE, BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE);
         }
 
-        return new Pair<>(modality, BiometricConstants.BIOMETRIC_ERROR_NONE);
+        return new Pair<>(modality, BiometricConstants.BIOMETRIC_SUCCESS);
     }
 
     private boolean isEnabledForApp(int modality) {
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 3a0ab77..8fce5e3 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -515,8 +515,20 @@
         if (oldGroup != null) {
             group.setChannels(oldGroup.getChannels());
 
+            // apps can't update the blocked status or app overlay permission
             if (fromTargetApp) {
                 group.setBlocked(oldGroup.isBlocked());
+                group.setAllowAppOverlay(oldGroup.canOverlayApps());
+                group.unlockFields(group.getUserLockedFields());
+                group.lockFields(oldGroup.getUserLockedFields());
+            } else {
+                // but the system can
+                if (group.isBlocked() != oldGroup.isBlocked()) {
+                    group.lockFields(NotificationChannelGroup.USER_LOCKED_BLOCKED_STATE);
+                }
+                if (group.canOverlayApps() != oldGroup.canOverlayApps()) {
+                    group.lockFields(NotificationChannelGroup.USER_LOCKED_ALLOW_APP_OVERLAY);
+                }
             }
         }
         r.groups.put(group.getId(), group);
@@ -1071,6 +1083,9 @@
         if (original.canShowBadge() != update.canShowBadge()) {
             update.lockFields(NotificationChannel.USER_LOCKED_SHOW_BADGE);
         }
+        if (original.isAppOverlayAllowed() != update.isAppOverlayAllowed()) {
+            update.lockFields(NotificationChannel.USER_LOCKED_ALLOW_APP_OVERLAY);
+        }
     }
 
     public void dump(PrintWriter pw, String prefix,
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f5a18b0..b988c6a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -322,6 +322,7 @@
 import dalvik.system.VMRuntime;
 
 import libcore.io.IoUtils;
+import libcore.util.EmptyArray;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -9530,7 +9531,8 @@
                     }
                 }
                 if (deleteSandboxData && getStorageManagerInternal() != null) {
-                    getStorageManagerInternal().destroySandboxForApp(pkg.packageName, realUserId);
+                    getStorageManagerInternal().destroySandboxForApp(pkg.packageName,
+                            pkg.mSharedUserId, realUserId);
                 }
             } catch (PackageManagerException e) {
                 // Should not happen
@@ -22942,6 +22944,20 @@
         }
 
         @Override
+        public String getSharedUserIdForPackage(String packageName) {
+            synchronized (mPackages) {
+                return getSharedUserIdForPackageLocked(packageName);
+            }
+        }
+
+        @Override
+        public String[] getPackagesForSharedUserId(String sharedUserId, int userId) {
+            synchronized (mPackages) {
+                return getPackagesForSharedUserIdLocked(sharedUserId, userId);
+            }
+        }
+
+        @Override
         public boolean isOnlyCoreApps() {
             return PackageManagerService.this.isOnlyCoreApps();
         }
@@ -22953,6 +22969,7 @@
         }
     }
 
+    @GuardedBy("mPackages")
     private SparseArray<String> getAppsWithSharedUserIdsLocked() {
         final SparseArray<String> sharedUserIds = new SparseArray<>();
         synchronized (mPackages) {
@@ -22963,6 +22980,38 @@
         return sharedUserIds;
     }
 
+    @GuardedBy("mPackages")
+    private String getSharedUserIdForPackageLocked(String packageName) {
+        final PackageSetting ps = mSettings.mPackages.get(packageName);
+        return (ps != null && ps.isSharedUser()) ? ps.sharedUser.name : null;
+    }
+
+    @GuardedBy("mPackages")
+    private String[] getPackagesForSharedUserIdLocked(String sharedUserId, int userId) {
+        try {
+            final SharedUserSetting sus = mSettings.getSharedUserLPw(
+                    sharedUserId, 0, 0, false);
+            if (sus == null) {
+                return EmptyArray.STRING;
+            }
+            String[] res = new String[sus.packages.size()];
+            final Iterator<PackageSetting> it = sus.packages.iterator();
+            int i = 0;
+            while (it.hasNext()) {
+                PackageSetting ps = it.next();
+                if (ps.getInstalled(userId)) {
+                    res[i++] = ps.name;
+                } else {
+                    res = ArrayUtils.removeElement(String.class, res, res[i]);
+                }
+            }
+            return res;
+        } catch (PackageManagerException e) {
+            // Should not happen
+        }
+        return EmptyArray.STRING;
+    }
+
     @Override
     public void grantDefaultPermissionsToEnabledCarrierApps(String[] packageNames, int userId) {
         enforceSystemOrPhoneCaller("grantPermissionsToEnabledCarrierApps");
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 5600749..1948706 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -1017,6 +1017,7 @@
             e.writeLong(processMemoryState.pgmajfault);
             e.writeLong(processMemoryState.rssInBytes);
             e.writeLong(processMemoryState.rssHighWatermarkInBytes);
+            e.writeLong(processMemoryState.startTimeNanos);
             pulledData.add(e);
         }
     }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 443d6fe..b011da6 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -410,6 +410,9 @@
             String[] args, int opti, boolean dumpAll, boolean dumpVisibleStacksOnly,
             boolean dumpFocusedStackOnly);
 
+    /** Dump the current state for inclusion in oom dump. */
+    public abstract void dumpForOom(PrintWriter pw);
+
     /** @return true if it the activity management system is okay with GC running now. */
     public abstract boolean canGcNow();
 
@@ -447,4 +450,24 @@
 
     public abstract void onUidAddedToPendingTempWhitelist(int uid, String tag);
     public abstract void onUidRemovedFromPendingTempWhitelist(int uid);
+
+    /** Handle app crash event in {@link android.app.IActivityController} if there is one. */
+    public abstract boolean handleAppCrashInActivityController(String processName, int pid,
+            String shortMsg, String longMsg, long timeMillis, String stackTrace,
+            Runnable killCrashingAppCallback);
+
+    public abstract void removeRecentTasksByPackageName(String packageName, int userId);
+    public abstract void cleanupRecentTasksForUser(int userId);
+    public abstract void loadRecentTasksForUser(int userId);
+    public abstract void onPackagesSuspendedChanged(String[] packages, boolean suspended,
+            int userId);
+    /** Flush recent tasks to disk. */
+    public abstract void flushRecentTasks();
+
+    public abstract WindowProcessController getHomeProcess();
+    public abstract WindowProcessController getPreviousProcess();
+
+    public abstract void clearLockedTasks(String reason);
+    public abstract void updateUserConfiguration();
+    public abstract boolean canShowErrorDialogs();
 }
diff --git a/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java
index 8022532..e53518c 100644
--- a/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java
@@ -30,7 +30,6 @@
 import android.os.storage.StorageManagerInternal;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
-import android.util.SparseArray;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -38,9 +37,6 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-import java.util.ArrayList;
-import java.util.List;
-
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class StorageManagerServiceTest {
@@ -83,29 +79,14 @@
 
         when(mUmi.getUserIds()).thenReturn(new int[] { 0 });
 
-        {
-            final SparseArray<String> res = new SparseArray<>();
-            res.put(UID_COLORS, NAME_COLORS);
-            when(mPmi.getAppsWithSharedUserIds()).thenReturn(res);
-        }
+        when(mPmi.getSharedUserIdForPackage(eq(PKG_GREY))).thenReturn(null);
+        when(mPmi.getSharedUserIdForPackage(eq(PKG_RED))).thenReturn(NAME_COLORS);
+        when(mPmi.getSharedUserIdForPackage(eq(PKG_BLUE))).thenReturn(NAME_COLORS);
 
-        {
-            final List<ApplicationInfo> res = new ArrayList<>();
-            res.add(buildApplicationInfo(PKG_GREY, UID_GREY));
-            res.add(buildApplicationInfo(PKG_RED, UID_COLORS));
-            res.add(buildApplicationInfo(PKG_BLUE, UID_COLORS));
-            when(mPm.getInstalledApplicationsAsUser(anyInt(), anyInt())).thenReturn(res);
-        }
-
-        when(mPmi.getPackageUid(eq(PKG_GREY), anyInt(), anyInt())).thenReturn(UID_GREY);
-        when(mPmi.getPackageUid(eq(PKG_RED), anyInt(), anyInt())).thenReturn(UID_COLORS);
-        when(mPmi.getPackageUid(eq(PKG_BLUE), anyInt(), anyInt())).thenReturn(UID_COLORS);
-
-        when(mPm.getPackagesForUid(eq(UID_GREY))).thenReturn(new String[] { PKG_GREY });
-        when(mPm.getPackagesForUid(eq(UID_COLORS))).thenReturn(new String[] { PKG_RED, PKG_BLUE });
+        when(mPmi.getPackagesForSharedUserId(eq(NAME_COLORS), anyInt()))
+                .thenReturn(new String[] { PKG_RED, PKG_BLUE });
 
         mService = new StorageManagerService(mContext);
-        mService.collectPackagesInfo();
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountsDbTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountsDbTest.java
index 72c22fd..29a920a 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountsDbTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountsDbTest.java
@@ -22,9 +22,14 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
 import android.accounts.Account;
 import android.content.Context;
 import android.database.Cursor;
+import android.database.sqlite.SQLiteStatement;
 import android.os.Build;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Pair;
@@ -37,7 +42,11 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
 import java.io.File;
+import java.io.PrintWriter;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
@@ -64,8 +73,11 @@
     private File deDb;
     private File ceDb;
 
+    @Mock private PrintWriter mockWriter;
+
     @Before
     public void setUp() {
+        MockitoAnnotations.initMocks(this);
         Context context = InstrumentationRegistry.getContext();
         preNDb = new File(context.getCacheDir(), PREN_DB);
         ceDb = new File(context.getCacheDir(), CE_DB);
@@ -444,4 +456,33 @@
         assertTrue(mAccountsDb.deleteDeAccount(accId)); // Trigger should remove visibility.
         assertNull(mAccountsDb.findAccountVisibility(account, packageName1));
     }
+
+    @Test
+    public void testDumpDebugTable() {
+        long accId = 10;
+        long insertionPoint = mAccountsDb.reserveDebugDbInsertionPoint();
+
+        SQLiteStatement logStatement = mAccountsDb.getStatementForLogging();
+
+        logStatement.bindLong(1, accId);
+        logStatement.bindString(2, "action");
+        logStatement.bindString(3, "date");
+        logStatement.bindLong(4, 10);
+        logStatement.bindString(5, "table");
+        logStatement.bindLong(6, insertionPoint);
+        logStatement.execute();
+
+        mAccountsDb.dumpDebugTable(mockWriter);
+
+        verify(mockWriter, times(3)).println(anyString());
+    }
+
+    @Test
+    public void testReserveDebugDbInsertionPoint() {
+        long insertionPoint = mAccountsDb.reserveDebugDbInsertionPoint();
+        long insertionPoint2 = mAccountsDb.reserveDebugDbInsertionPoint();
+
+        assertEquals(0, insertionPoint);
+        assertEquals(1, insertionPoint2);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
index 349c0a37..060c55d 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -260,7 +260,7 @@
         uidRec.hasInternetPermission = true;
         mAms.mActiveUids.put(uid, uidRec);
 
-        final ProcessRecord appRec = new ProcessRecord(mAms, new ApplicationInfo(), TAG, uid, null);
+        final ProcessRecord appRec = new ProcessRecord(mAms, new ApplicationInfo(), TAG, uid);
         appRec.thread = Mockito.mock(IApplicationThread.class);
         mAms.mProcessList.mLruProcesses.add(appRec);
 
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java
index 9192d6b..e1ebbcf 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java
@@ -83,7 +83,7 @@
         final WindowProcessController wpc = new WindowProcessController(mService,
                 mService.mContext.getApplicationInfo(), "name", 12345,
                 UserHandle.getUserId(12345), mock(Object.class),
-                mock(WindowProcessListener.class), null);
+                mock(WindowProcessListener.class));
         wpc.setThread(mock(IApplicationThread.class));
 
         mController.addPendingActivityLaunch(
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
index ba64b51..fb11a04 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
@@ -211,7 +211,7 @@
         final WindowProcessController wpc =
                 containsConditions(preconditions, PRECONDITION_NO_CALLER_APP)
                 ? null : new WindowProcessController(
-                        service, mock(ApplicationInfo.class),null, 0, -1, null, null, null);
+                        service, mock(ApplicationInfo.class),null, 0, -1, null, null);
         doReturn(wpc).when(service).getProcessController(anyObject());
 
         final Intent intent = new Intent();
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index 01d51e4..094241e 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -286,7 +286,7 @@
             final WindowProcessController wpc = new WindowProcessController(mService,
                     mService.mContext.getApplicationInfo(), "name", 12345,
                     UserHandle.getUserId(12345), mock(Object.class),
-                    mock(WindowProcessListener.class), null);
+                    mock(WindowProcessListener.class));
             wpc.setThread(mock(IApplicationThread.class));
             activity.setProcess(wpc);
             return activity;
@@ -536,11 +536,6 @@
             mUgmInternal = mock(UriGrantsManagerInternal.class);
         }
 
-        @Override
-        Configuration getGlobalConfiguration() {
-            return mContext.getResources().getConfiguration();
-        }
-
         ActivityManagerInternal getLocalService() {
             if (mInternal == null) {
                 mInternal = new LocalService();
diff --git a/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java b/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
index 06d41f1..3a7a24d 100644
--- a/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
@@ -69,7 +69,7 @@
     @UiThreadTest
     public void testCreateWorks() throws Exception {
         AppErrorDialog.Data data = new AppErrorDialog.Data();
-        data.proc = new ProcessRecord(null, mContext.getApplicationInfo(), "name", 12345, null);
+        data.proc = new ProcessRecord(null, mContext.getApplicationInfo(), "name", 12345);
         data.result = new AppErrorResult();
 
         AppErrorDialog dialog = new AppErrorDialog(mContext, mService, data);
diff --git a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
index 9a283fe..72c5b10 100644
--- a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
@@ -17,6 +17,7 @@
 package com.android.server.am;
 
 import static com.android.server.am.MemoryStatUtil.BYTES_IN_KILOBYTE;
+import static com.android.server.am.MemoryStatUtil.JIFFY_NANOS;
 import static com.android.server.am.MemoryStatUtil.MemoryStat;
 import static com.android.server.am.MemoryStatUtil.PAGE_SIZE;
 import static com.android.server.am.MemoryStatUtil.parseMemoryMaxUsageFromMemCg;
@@ -96,7 +97,7 @@
             "-2",
             "117",
             "0",
-            "2206",
+            "2222", // this in start time (in ticks per second)
             "1257177088",
             "3", // this is RSS (number of pages)
             "4294967295",
@@ -219,6 +220,7 @@
         assertEquals(3 * PAGE_SIZE, stat.rssInBytes);
         assertEquals(0, stat.cacheInBytes);
         assertEquals(0, stat.swapInBytes);
+        assertEquals(2222 * JIFFY_NANOS, stat.startTimeNanos);
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/am/PendingRemoteAnimationRegistryTest.java b/services/tests/servicestests/src/com/android/server/am/PendingRemoteAnimationRegistryTest.java
index 1c4e0f6..4beebc4 100644
--- a/services/tests/servicestests/src/com/android/server/am/PendingRemoteAnimationRegistryTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/PendingRemoteAnimationRegistryTest.java
@@ -50,17 +50,17 @@
     private PendingRemoteAnimationRegistry mRegistry;
     private final OffsettableClock mClock = new OffsettableClock.Stopped();
     private TestHandler mHandler;
-    private ActivityManagerService mService;
+    private ActivityTaskManagerService mService;
 
     @Before
     public void setUp() throws Exception {
         super.setUp();
         MockitoAnnotations.initMocks(this);
-        mService = createActivityManagerService();
-        mService.mHandlerThread.getThreadHandler().runWithScissors(() -> {
+        mService = createActivityTaskManagerService();
+        mService.mH.runWithScissors(() -> {
             mHandler = new TestHandler(null, mClock);
         }, 0);
-        mRegistry = new PendingRemoteAnimationRegistry(mService.mActivityTaskManager, mHandler);
+        mRegistry = new PendingRemoteAnimationRegistry(mService, mHandler);
     }
 
     @Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 79998a5..3fe381b 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -280,7 +280,8 @@
 
         assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
         assertTrue(mHelper.getIsAppImportanceLocked(PKG_N_MR1, UID_N_MR1));
-        assertEquals(channel1, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), false));
+        assertEquals(channel1,
+                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), false));
         compareChannels(channel2,
                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false));
 
@@ -348,7 +349,8 @@
 
         assertEquals(IMPORTANCE_NONE, mHelper.getImportance(PKG_O, UID_O));
         assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
-        assertEquals(channel1, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), false));
+        assertEquals(channel1,
+                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), false));
         compareChannels(channel2,
                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false));
         compareChannels(channel3,
@@ -487,7 +489,7 @@
         NotificationChannel channel1 =
                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
         NotificationChannel channel2 =
-                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
+                new NotificationChannel("id2", "name2", IMPORTANCE_HIGH);
         NotificationChannel channel3 =
                 new NotificationChannel("id3", "name3", IMPORTANCE_LOW);
         channel3.setGroup(ncg.getId());
@@ -500,7 +502,8 @@
 
         mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId());
         mHelper.deleteNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg.getId());
-        assertEquals(channel2, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false));
+        assertEquals(channel2,
+                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false));
 
         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true, channel1.getId(),
                 channel2.getId(), channel3.getId(), NotificationChannel.DEFAULT_CHANNEL_ID);
@@ -516,8 +519,8 @@
         assertNull(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), false));
         assertNull(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3.getId(), false));
         assertNull(mHelper.getNotificationChannelGroup(ncg.getId(), PKG_N_MR1, UID_N_MR1));
-        //assertEquals(ncg2, mHelper.getNotificationChannelGroup(ncg2.getId(), PKG_N_MR1, UID_N_MR1));
-        assertEquals(channel2, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false));
+        assertEquals(channel2,
+                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false));
     }
 
     @Test
@@ -799,14 +802,15 @@
     }
 
     @Test
-    public void testCreateChannel_CannotChangeHiddenFields() throws Exception {
+    public void testCreateChannel_CannotChangeHiddenFields() {
         final NotificationChannel channel =
-                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
+                new NotificationChannel("id2", "name2", IMPORTANCE_HIGH);
         channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
         channel.enableLights(true);
         channel.setBypassDnd(true);
         channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
         channel.setShowBadge(true);
+        channel.setAllowAppOverlay(false);
         int lockMask = 0;
         for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) {
             lockMask |= NotificationChannel.LOCKABLE_FIELDS[i];
@@ -823,19 +827,21 @@
         assertFalse(savedChannel.canBypassDnd());
         assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility());
         assertEquals(channel.canShowBadge(), savedChannel.canShowBadge());
+        assertEquals(channel.canOverlayApps(), savedChannel.canOverlayApps());
 
         verify(mHandler, never()).requestSort();
     }
 
     @Test
-    public void testCreateChannel_CannotChangeHiddenFieldsAssistant() throws Exception {
+    public void testCreateChannel_CannotChangeHiddenFieldsAssistant() {
         final NotificationChannel channel =
-                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
+                new NotificationChannel("id2", "name2", IMPORTANCE_HIGH);
         channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
         channel.enableLights(true);
         channel.setBypassDnd(true);
         channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
         channel.setShowBadge(true);
+        channel.setAllowAppOverlay(false);
         int lockMask = 0;
         for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) {
             lockMask |= NotificationChannel.LOCKABLE_FIELDS[i];
@@ -852,10 +858,11 @@
         assertFalse(savedChannel.canBypassDnd());
         assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility());
         assertEquals(channel.canShowBadge(), savedChannel.canShowBadge());
+        assertEquals(channel.canOverlayApps(), savedChannel.canOverlayApps());
     }
 
     @Test
-    public void testClearLockedFields() throws Exception {
+    public void testClearLockedFields() {
         final NotificationChannel channel = getChannel();
         mHelper.clearLockedFields(channel);
         assertEquals(0, channel.getUserLockedFields());
@@ -867,7 +874,7 @@
     }
 
     @Test
-    public void testLockFields_soundAndVibration() throws Exception {
+    public void testLockFields_soundAndVibration() {
         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false);
 
         final NotificationChannel update1 = getChannel();
@@ -891,7 +898,7 @@
     }
 
     @Test
-    public void testLockFields_vibrationAndLights() throws Exception {
+    public void testLockFields_vibrationAndLights() {
         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false);
 
         final NotificationChannel update1 = getChannel();
@@ -911,7 +918,7 @@
     }
 
     @Test
-    public void testLockFields_lightsAndImportance() throws Exception {
+    public void testLockFields_lightsAndImportance() {
         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false);
 
         final NotificationChannel update1 = getChannel();
@@ -931,7 +938,7 @@
     }
 
     @Test
-    public void testLockFields_visibilityAndDndAndBadge() throws Exception {
+    public void testLockFields_visibilityAndDndAndBadge() {
         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false);
         assertEquals(0,
                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel().getId(), false)
@@ -963,6 +970,21 @@
     }
 
     @Test
+    public void testLockFields_appOverlay() {
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false);
+        assertEquals(0,
+                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel().getId(), false)
+                        .getUserLockedFields());
+
+        final NotificationChannel update = getChannel();
+        update.setAllowAppOverlay(false);
+        mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update, true);
+        assertEquals(NotificationChannel.USER_LOCKED_ALLOW_APP_OVERLAY,
+                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update.getId(), false)
+                        .getUserLockedFields());
+    }
+
+    @Test
     public void testDeleteNonExistentChannel() throws Exception {
         mHelper.deleteNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, "does not exist");
     }
@@ -1255,21 +1277,24 @@
 
         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, notDeleted, true);
         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, deleted, true);
-        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nonGroupedNonDeletedChannel, true, false);
+        mHelper.createNotificationChannel(
+                PKG_N_MR1, UID_N_MR1, nonGroupedNonDeletedChannel, true, false);
         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, groupedAndDeleted, true, false);
         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, groupedButNotDeleted, true, false);
 
         mHelper.deleteNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, deleted.getId());
 
         assertNull(mHelper.getNotificationChannelGroup(deleted.getId(), PKG_N_MR1, UID_N_MR1));
-        assertNotNull(mHelper.getNotificationChannelGroup(notDeleted.getId(), PKG_N_MR1, UID_N_MR1));
+        assertNotNull(
+                mHelper.getNotificationChannelGroup(notDeleted.getId(), PKG_N_MR1, UID_N_MR1));
 
-        assertNull(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, groupedAndDeleted.getId(), false));
-        compareChannels(groupedAndDeleted,
-                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, groupedAndDeleted.getId(), true));
+        assertNull(mHelper.getNotificationChannel(
+                PKG_N_MR1, UID_N_MR1, groupedAndDeleted.getId(), false));
+        compareChannels(groupedAndDeleted, mHelper.getNotificationChannel(
+                PKG_N_MR1, UID_N_MR1, groupedAndDeleted.getId(), true));
 
-        compareChannels(groupedButNotDeleted,
-                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, groupedButNotDeleted.getId(), false));
+        compareChannels(groupedButNotDeleted, mHelper.getNotificationChannel(
+                PKG_N_MR1, UID_N_MR1, groupedButNotDeleted.getId(), false));
         compareChannels(nonGroupedNonDeletedChannel, mHelper.getNotificationChannel(
                 PKG_N_MR1, UID_N_MR1, nonGroupedNonDeletedChannel.getId(), false));
 
@@ -1381,15 +1406,49 @@
     }
 
     @Test
-    public void testCreateGroup() throws Exception {
+    public void testCreateGroup() {
         NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
-        assertEquals(ncg, mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1).iterator().next());
+        assertEquals(ncg,
+                mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1).iterator().next());
         verify(mHandler, never()).requestSort();
     }
 
     @Test
-    public void testCannotCreateChannel_badGroup() throws Exception {
+    public void testUpdateGroup_fromSystem_appOverlay() {
+        NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
+
+        // from system, allowed
+        NotificationChannelGroup update = ncg.clone();
+        update.setAllowAppOverlay(false);
+
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, update, false);
+        NotificationChannelGroup updated =
+                mHelper.getNotificationChannelGroup("group1", PKG_N_MR1, UID_N_MR1);
+        assertFalse(updated.canOverlayApps());
+        assertEquals(NotificationChannelGroup.USER_LOCKED_ALLOW_APP_OVERLAY,
+                updated.getUserLockedFields());
+    }
+
+    @Test
+    public void testUpdateGroup_fromApp_appOverlay() {
+        NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
+
+        // from app, not allowed
+        NotificationChannelGroup update = new NotificationChannelGroup("group1", "name1");
+        update.setAllowAppOverlay(false);
+
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
+        NotificationChannelGroup updated =
+                mHelper.getNotificationChannelGroup("group1", PKG_N_MR1, UID_N_MR1);
+        assertTrue(updated.canOverlayApps());
+        assertEquals(0, updated.getUserLockedFields());
+    }
+
+    @Test
+    public void testCannotCreateChannel_badGroup() {
         NotificationChannel channel1 =
                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
         channel1.setGroup("garbage");
@@ -1401,7 +1460,7 @@
     }
 
     @Test
-    public void testCannotCreateChannel_goodGroup() throws Exception {
+    public void testCannotCreateChannel_goodGroup() {
         NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
         NotificationChannel channel1 =
@@ -1409,12 +1468,12 @@
         channel1.setGroup(ncg.getId());
         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false);
 
-        assertEquals(ncg.getId(),
-                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), false).getGroup());
+        assertEquals(ncg.getId(), mHelper.getNotificationChannel(
+                PKG_N_MR1, UID_N_MR1, channel1.getId(), false).getGroup());
     }
 
     @Test
-    public void testGetChannelGroups() throws Exception {
+    public void testGetChannelGroups() {
         NotificationChannelGroup unused = new NotificationChannelGroup("unused", "s");
         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, unused, true);
         NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
@@ -1465,7 +1524,7 @@
     }
 
     @Test
-    public void testGetChannelGroups_noSideEffects() throws Exception {
+    public void testGetChannelGroups_noSideEffects() {
         NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
 
@@ -1516,10 +1575,11 @@
     }
 
     @Test
-    public void testCreateChannel_updateName() throws Exception {
+    public void testCreateChannel_updateName() {
         NotificationChannel nc = new NotificationChannel("id", "hello", IMPORTANCE_DEFAULT);
         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nc, true, false);
-        NotificationChannel actual = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "id", false);
+        NotificationChannel actual =
+                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "id", false);
         assertEquals("hello", actual.getName());
 
         nc = new NotificationChannel("id", "goodbye", IMPORTANCE_HIGH);
@@ -1533,12 +1593,13 @@
     }
 
     @Test
-    public void testCreateChannel_addToGroup() throws Exception {
+    public void testCreateChannel_addToGroup() {
         NotificationChannelGroup group = new NotificationChannelGroup("group", "");
         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true);
         NotificationChannel nc = new NotificationChannel("id", "hello", IMPORTANCE_DEFAULT);
         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nc, true, false);
-        NotificationChannel actual = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "id", false);
+        NotificationChannel actual =
+                mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "id", false);
         assertNull(actual.getGroup());
 
         nc = new NotificationChannel("id", "hello", IMPORTANCE_HIGH);
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index d33a537..3127b35 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -676,7 +676,7 @@
     /**
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public static TelecomManager from(Context context) {
         return (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);
     }
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 6c9c01c..52ac32d 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -3086,6 +3086,13 @@
         @SystemApi
         public static final int NO_SET_SET = 0;
 
+        /**
+         * A unique carrier id associated with this APN
+         * {@see TelephonyManager#getSimCarrierId()}
+         * <p>Type: STRING</p>
+         */
+        public static final String CARRIER_ID = "carrier_id";
+
     }
 
     /**
diff --git a/telephony/java/android/telephony/RadioAccessFamily.java b/telephony/java/android/telephony/RadioAccessFamily.java
index 1d79988..da3acc2 100644
--- a/telephony/java/android/telephony/RadioAccessFamily.java
+++ b/telephony/java/android/telephony/RadioAccessFamily.java
@@ -29,29 +29,32 @@
  */
 public class RadioAccessFamily implements Parcelable {
 
-    // Radio Access Family
+    /**
+     * TODO: get rid of RAF definition in RadioAccessFamily and
+     * use {@link TelephonyManager.NetworkTypeBitMask}
+     */
     // 2G
-    public static final int RAF_UNKNOWN = (1 <<  ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN);
-    public static final int RAF_GSM = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_GSM);
-    public static final int RAF_GPRS = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_GPRS);
-    public static final int RAF_EDGE = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_EDGE);
-    public static final int RAF_IS95A = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_IS95A);
-    public static final int RAF_IS95B = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_IS95B);
-    public static final int RAF_1xRTT = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT);
+    public static final int RAF_UNKNOWN = TelephonyManager.NETWORK_TYPE_BITMASK_UNKNOWN;
+    public static final int RAF_GSM = TelephonyManager.NETWORK_TYPE_BITMASK_GSM;
+    public static final int RAF_GPRS = TelephonyManager.NETWORK_TYPE_BITMASK_GPRS;
+    public static final int RAF_EDGE = TelephonyManager.NETWORK_TYPE_BITMASK_EDGE;
+    public static final int RAF_IS95A = TelephonyManager.NETWORK_TYPE_BITMASK_CDMA;
+    public static final int RAF_IS95B = TelephonyManager.NETWORK_TYPE_BITMASK_CDMA;
+    public static final int RAF_1xRTT = TelephonyManager.NETWORK_TYPE_BITMASK_1xRTT;
     // 3G
-    public static final int RAF_EVDO_0 = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0);
-    public static final int RAF_EVDO_A = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A);
-    public static final int RAF_EVDO_B = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_B);
-    public static final int RAF_EHRPD = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD);
-    public static final int RAF_HSUPA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSUPA);
-    public static final int RAF_HSDPA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSDPA);
-    public static final int RAF_HSPA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSPA);
-    public static final int RAF_HSPAP = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSPAP);
-    public static final int RAF_UMTS = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
-    public static final int RAF_TD_SCDMA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_TD_SCDMA);
+    public static final int RAF_EVDO_0 = TelephonyManager.NETWORK_TYPE_BITMASK_EVDO_0;
+    public static final int RAF_EVDO_A = TelephonyManager.NETWORK_TYPE_BITMASK_EVDO_A;
+    public static final int RAF_EVDO_B = TelephonyManager.NETWORK_TYPE_BITMASK_EVDO_B;
+    public static final int RAF_EHRPD = TelephonyManager.NETWORK_TYPE_BITMASK_EHRPD;
+    public static final int RAF_HSUPA = TelephonyManager.NETWORK_TYPE_BITMASK_HSUPA;
+    public static final int RAF_HSDPA = TelephonyManager.NETWORK_TYPE_BITMASK_HSDPA;
+    public static final int RAF_HSPA = TelephonyManager.NETWORK_TYPE_BITMASK_HSPA;
+    public static final int RAF_HSPAP = TelephonyManager.NETWORK_TYPE_BITMASK_HSPAP;
+    public static final int RAF_UMTS = TelephonyManager.NETWORK_TYPE_BITMASK_UMTS;
+    public static final int RAF_TD_SCDMA = TelephonyManager.NETWORK_TYPE_BITMASK_TD_SCDMA;
     // 4G
-    public static final int RAF_LTE = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_LTE);
-    public static final int RAF_LTE_CA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA);
+    public static final int RAF_LTE = TelephonyManager.NETWORK_TYPE_BITMASK_LTE;
+    public static final int RAF_LTE_CA = TelephonyManager.NETWORK_TYPE_BITMASK_LTE_CA;
 
     // Grouping of RAFs
     // 2G
@@ -74,9 +77,9 @@
      * Constructor.
      *
      * @param phoneId the phone ID
-     * @param radioAccessFamily the phone radio access family defined
-     *        in RadioAccessFamily. It's a bit mask value to represent
-     *        the support type.
+     * @param radioAccessFamily the phone radio access family bitmask based on
+     * {@link TelephonyManager.NetworkTypeBitMask}. It's a bit mask value to represent the support
+     *                          type.
      */
     @UnsupportedAppUsage
     public RadioAccessFamily(int phoneId, int radioAccessFamily) {
@@ -100,7 +103,7 @@
      * @return radio access family
      */
     @UnsupportedAppUsage
-    public int getRadioAccessFamily() {
+    public @TelephonyManager.NetworkTypeBitMask int getRadioAccessFamily() {
         return mRadioAccessFamily;
     }
 
@@ -388,4 +391,76 @@
         }
         return result;
     }
+
+    /**
+     * convert RAF from {@link ServiceState.RilRadioTechnology} bitmask to
+     * {@link TelephonyManager.NetworkTypeBitMask}, the bitmask represented by
+     * {@link TelephonyManager.NetworkType}. Reasons are {@link TelephonyManager.NetworkType} are
+     * public while {@link ServiceState.RilRadioTechnology} are hidden. We
+     * don't want to expose two sets of definition to public.
+     *
+     * @param raf bitmask represented by {@link ServiceState.RilRadioTechnology}
+     * @return {@link TelephonyManager.NetworkTypeBitMask}
+     */
+    public static int convertToNetworkTypeBitMask(int raf) {
+        int networkTypeRaf = 0;
+
+        if ((raf & (1 << ServiceState.RIL_RADIO_TECHNOLOGY_GSM)) != 0) {
+            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_GSM;
+        }
+        if ((raf & (1 << ServiceState.RIL_RADIO_TECHNOLOGY_GPRS)) != 0) {
+            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_GPRS;
+        }
+        if ((raf & (1 << ServiceState.RIL_RADIO_TECHNOLOGY_EDGE)) != 0) {
+            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_EDGE;
+        }
+        // convert both IS95A/IS95B to CDMA as network mode doesn't support CDMA
+        if ((raf & (1 << ServiceState.RIL_RADIO_TECHNOLOGY_IS95A)) != 0) {
+            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_CDMA;
+        }
+        if ((raf & (1 << ServiceState.RIL_RADIO_TECHNOLOGY_IS95B)) != 0) {
+            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_CDMA;
+        }
+        if ((raf & (1 << ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT)) != 0) {
+            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_1xRTT;
+        }
+        if ((raf & (1 << ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0)) != 0) {
+            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_EVDO_0;
+        }
+        if ((raf & (1 << ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A)) != 0) {
+            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_EVDO_A;
+        }
+        if ((raf & (1 << ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_B)) != 0) {
+            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_EVDO_B;
+        }
+        if ((raf & (1 << ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD)) != 0) {
+            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_EHRPD;
+        }
+        if ((raf & (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSUPA)) != 0) {
+            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_HSUPA;
+        }
+        if ((raf & (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSDPA)) != 0) {
+            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_HSDPA;
+        }
+        if ((raf & (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSPA)) != 0) {
+            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_HSPA;
+        }
+        if ((raf & (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSPAP)) != 0) {
+            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_HSPAP;
+        }
+        if ((raf & (1 << ServiceState.RIL_RADIO_TECHNOLOGY_UMTS)) != 0) {
+            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_UMTS;
+        }
+        if ((raf & (1 << ServiceState.RIL_RADIO_TECHNOLOGY_TD_SCDMA)) != 0) {
+            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_TD_SCDMA;
+        }
+        if ((raf & (1 << ServiceState.RIL_RADIO_TECHNOLOGY_LTE)) != 0) {
+            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_LTE;
+        }
+        if ((raf & (1 << ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA)) != 0) {
+            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_LTE_CA;
+        }
+
+        return (networkTypeRaf == 0) ? TelephonyManager.NETWORK_TYPE_UNKNOWN : networkTypeRaf;
+    }
 }
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 7f87ef3..c407681 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -247,7 +247,7 @@
     private String mDataOperatorAlphaLong;
     private String mDataOperatorAlphaShort;
     private String mDataOperatorNumeric;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private boolean mIsManualNetworkSelection;
 
     private boolean mIsEmergencyOnly;
@@ -266,9 +266,9 @@
 
     @UnsupportedAppUsage
     private boolean mCssIndicator;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private int mNetworkId;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private int mSystemId;
     @UnsupportedAppUsage
     private int mCdmaRoamingIndicator;
@@ -466,7 +466,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public int getVoiceRegState() {
         return mVoiceRegState;
     }
@@ -481,7 +481,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public int getDataRegState() {
         return mDataRegState;
     }
@@ -542,7 +542,7 @@
      * @return roaming status
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public boolean getVoiceRoaming() {
         return getVoiceRoamingType() != ROAMING_TYPE_NOT_ROAMING;
     }
@@ -566,7 +566,7 @@
      * @return roaming type
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public boolean getDataRoaming() {
         return getDataRoamingType() != ROAMING_TYPE_NOT_ROAMING;
     }
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 002d813..0459667 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1369,7 +1369,7 @@
     }
 
     /** @hide */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public static int getPhoneId(int subId) {
         if (!isValidSubscriptionId(subId)) {
             if (DBG) {
@@ -1665,7 +1665,7 @@
      * usable subId means its neither a INVALID_SUBSCRIPTION_ID nor a DEFAULT_SUB_ID.
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public static boolean isUsableSubIdValue(int subId) {
         return subId >= MIN_SUBSCRIPTION_ID_VALUE && subId <= MAX_SUBSCRIPTION_ID_VALUE;
     }
@@ -1683,7 +1683,7 @@
     }
 
     /** @hide */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId) {
         int[] subIds = SubscriptionManager.getSubId(phoneId);
         if (subIds != null && subIds.length > 0) {
@@ -2229,22 +2229,27 @@
     }
 
     /**
-     * Get opportunistic data Profiles.
+     * Return opportunistic subscriptions that can be visible to the caller.
+     * Opportunistic subscriptions are for opportunistic networks, which are cellular
+     * networks with limited capabilities and coverage, for example, CBRS.
      *
-     *  Provide all available user downloaded profiles on phone which are used only for
-     *  opportunistic data.
-     *  @param slotIndex slot on which the profiles are queried from.
-     *  @return the list of opportunistic subscription info. If none exists, an empty list. 
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * or that the calling app has carrier privileges (see
+     * {@link TelephonyManager#hasCarrierPrivileges}).
+     *
+     * @return the list of opportunistic subscription info. If none exists, an empty list.
      */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
-    public @NonNull List<SubscriptionInfo> getOpportunisticSubscriptions(int slotIndex) {
+    public @NonNull List<SubscriptionInfo> getOpportunisticSubscriptions() {
         String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
         List<SubscriptionInfo> subInfoList = null;
 
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
             if (iSub != null) {
-                subInfoList = iSub.getOpportunisticSubscriptions(slotIndex, pkgForDebug);
+                subInfoList = iSub.getOpportunisticSubscriptions(pkgForDebug);
             }
         } catch (RemoteException ex) {
             // ignore it
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 35f2c16..f484d1f 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -232,7 +232,8 @@
 
     /** @hide
     /* @deprecated - use getSystemService as described above */
-    @UnsupportedAppUsage
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public static TelephonyManager getDefault() {
         return sInstance;
     }
@@ -321,7 +322,7 @@
     }
 
     /** {@hide} */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public static TelephonyManager from(Context context) {
         return (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
     }
@@ -1949,7 +1950,7 @@
      * @param subId
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public String getNetworkOperatorName(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
         return getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_OPERATOR_ALPHA, "");
@@ -1977,7 +1978,7 @@
      * @param subId
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public String getNetworkOperator(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
         return getNetworkOperatorForPhone(phoneId);
@@ -2301,7 +2302,7 @@
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public int getDataNetworkType(int subId) {
         try{
             ITelephony telephony = getITelephony();
@@ -2337,7 +2338,7 @@
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public int getVoiceNetworkType(int subId) {
         try{
             ITelephony telephony = getITelephony();
@@ -2820,7 +2821,7 @@
      * @param subId for which SimOperator is returned
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public String getSimOperator(int subId) {
         return getSimOperatorNumeric(subId);
     }
@@ -2834,7 +2835,7 @@
      * @see #getSimState
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public String getSimOperatorNumeric() {
         int subId = mSubId;
         if (!SubscriptionManager.isUsableSubIdValue(subId)) {
@@ -2863,7 +2864,7 @@
      * @param subId for which SimOperator is returned
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public String getSimOperatorNumeric(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
         return getSimOperatorNumericForPhone(phoneId);
@@ -2877,7 +2878,7 @@
      * @param phoneId for which SimOperator is returned
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public String getSimOperatorNumericForPhone(int phoneId) {
         return getTelephonyProperty(phoneId,
                 TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, "");
@@ -2904,7 +2905,7 @@
      * @param subId for which SimOperatorName is returned
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public String getSimOperatorName(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
         return getSimOperatorNameForPhone(phoneId);
@@ -2934,7 +2935,7 @@
      * @param subId for which SimCountryIso is returned
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public String getSimCountryIso(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
         return getSimCountryIsoForPhone(phoneId);
@@ -3146,7 +3147,7 @@
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public String getSubscriberId(int subId) {
         try {
             IPhoneSubInfo info = getSubscriberInfo();
@@ -3531,7 +3532,7 @@
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public String getMsisdn(int subId) {
         try {
             IPhoneSubInfo info = getSubscriberInfo();
@@ -4464,7 +4465,7 @@
    /**
     * @hide
     */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private ITelephony getITelephony() {
         return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
     }
@@ -8047,7 +8048,7 @@
      * either READ_PRIVILEGED_PHONE_STATE or READ_PHONE_STATE to retrieve the information.
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public ServiceState getServiceStateForSubscriber(int subId) {
         try {
             ITelephony service = getITelephony();
@@ -8819,4 +8820,168 @@
 
         return isEnabled;
     }
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, prefix = {"NETWORK_TYPE_BITMASK_"},
+            value = {NETWORK_TYPE_BITMASK_UNKNOWN,
+                    NETWORK_TYPE_BITMASK_GSM,
+                    NETWORK_TYPE_BITMASK_GPRS,
+                    NETWORK_TYPE_BITMASK_EDGE,
+                    NETWORK_TYPE_BITMASK_CDMA,
+                    NETWORK_TYPE_BITMASK_1xRTT,
+                    NETWORK_TYPE_BITMASK_EVDO_0,
+                    NETWORK_TYPE_BITMASK_EVDO_A,
+                    NETWORK_TYPE_BITMASK_EVDO_B,
+                    NETWORK_TYPE_BITMASK_EHRPD,
+                    NETWORK_TYPE_BITMASK_HSUPA,
+                    NETWORK_TYPE_BITMASK_HSDPA,
+                    NETWORK_TYPE_BITMASK_HSPA,
+                    NETWORK_TYPE_BITMASK_HSPAP,
+                    NETWORK_TYPE_BITMASK_UMTS,
+                    NETWORK_TYPE_BITMASK_TD_SCDMA,
+                    NETWORK_TYPE_BITMASK_LTE,
+                    NETWORK_TYPE_BITMASK_LTE_CA,
+            })
+    public @interface NetworkTypeBitMask {}
+
+    // 2G
+    /**
+     * network type bitmask unknown.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_TYPE_BITMASK_UNKNOWN = (1 << NETWORK_TYPE_UNKNOWN);
+    /**
+     * network type bitmask indicating the support of radio tech GSM.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_TYPE_BITMASK_GSM = (1 << NETWORK_TYPE_GSM);
+    /**
+     * network type bitmask indicating the support of radio tech GPRS.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_TYPE_BITMASK_GPRS = (1 << NETWORK_TYPE_GPRS);
+    /**
+     * network type bitmask indicating the support of radio tech EDGE.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_TYPE_BITMASK_EDGE = (1 << NETWORK_TYPE_EDGE);
+    /**
+     * network type bitmask indicating the support of radio tech CDMA(IS95A/IS95B).
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_TYPE_BITMASK_CDMA = (1 << NETWORK_TYPE_CDMA);
+    /**
+     * network type bitmask indicating the support of radio tech 1xRTT.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_TYPE_BITMASK_1xRTT = (1 << NETWORK_TYPE_1xRTT);
+    // 3G
+    /**
+     * network type bitmask indicating the support of radio tech EVDO 0.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_TYPE_BITMASK_EVDO_0 = (1 << NETWORK_TYPE_EVDO_0);
+    /**
+     * network type bitmask indicating the support of radio tech EVDO A.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_TYPE_BITMASK_EVDO_A = (1 << NETWORK_TYPE_EVDO_A);
+    /**
+     * network type bitmask indicating the support of radio tech EVDO B.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_TYPE_BITMASK_EVDO_B = (1 << NETWORK_TYPE_EVDO_B);
+    /**
+     * network type bitmask indicating the support of radio tech EHRPD.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_TYPE_BITMASK_EHRPD = (1 << NETWORK_TYPE_EHRPD);
+    /**
+     * network type bitmask indicating the support of radio tech HSUPA.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_TYPE_BITMASK_HSUPA = (1 << NETWORK_TYPE_HSUPA);
+    /**
+     * network type bitmask indicating the support of radio tech HSDPA.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_TYPE_BITMASK_HSDPA = (1 << NETWORK_TYPE_HSDPA);
+    /**
+     * network type bitmask indicating the support of radio tech HSPA.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_TYPE_BITMASK_HSPA = (1 << NETWORK_TYPE_HSPA);
+    /**
+     * network type bitmask indicating the support of radio tech HSPAP.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_TYPE_BITMASK_HSPAP = (1 << NETWORK_TYPE_HSPAP);
+    /**
+     * network type bitmask indicating the support of radio tech UMTS.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_TYPE_BITMASK_UMTS = (1 << NETWORK_TYPE_UMTS);
+    /**
+     * network type bitmask indicating the support of radio tech TD_SCDMA.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_TYPE_BITMASK_TD_SCDMA = (1 << NETWORK_TYPE_TD_SCDMA);
+    // 4G
+    /**
+     * network type bitmask indicating the support of radio tech LTE.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_TYPE_BITMASK_LTE = (1 << NETWORK_TYPE_LTE);
+    /**
+     * network type bitmask indicating the support of radio tech LTE CA (carrier aggregation).
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_TYPE_BITMASK_LTE_CA = (1 << NETWORK_TYPE_LTE_CA);
+
+    /**
+     * @return Modem supported radio access family bitmask {@link NetworkTypeBitMask}
+     *
+     * <p>Requires permission: {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} or
+     * that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public @NetworkTypeBitMask int getSupportedRadioAccessFamily() {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.getRadioAccessFamily(getSlotIndex(), getOpPackageName());
+            } else {
+                // This can happen when the ITelephony interface is not up yet.
+                return NETWORK_TYPE_BITMASK_UNKNOWN;
+            }
+        } catch (RemoteException ex) {
+            // This shouldn't happen in the normal case
+            return NETWORK_TYPE_BITMASK_UNKNOWN;
+        } catch (NullPointerException ex) {
+            // This could happen before phone restarts due to crashing
+            return NETWORK_TYPE_BITMASK_UNKNOWN;
+        }
+    }
+
 }
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index 85b4941..4bdec08 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -186,10 +186,10 @@
     /**
      * Get User downloaded Profiles.
      *
-     *  Provide all available user downloaded profile on the phone.
-     *  @param slotId on which phone the switch will operate on
+     * Return opportunistic subscriptions that can be visible to the caller.
+     * @return the list of opportunistic subscription info. If none exists, an empty list.
      */
-    List<SubscriptionInfo> getOpportunisticSubscriptions(int slotId, String callingPackage);
+    List<SubscriptionInfo> getOpportunisticSubscriptions(String callingPackage);
 
     int getSlotIndex(int subId);
 
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index eda8e77..eb6be65 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -456,6 +456,27 @@
     }
 
     /**
+     * Ensure the caller (or self, if not processing an IPC) has
+     * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} or carrier privileges.
+     *
+     * @throws SecurityException if the caller does not have the required permission/privileges
+     */
+    public static void enforeceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege(
+            Context context, int subId, String message) {
+        if (context.checkCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+                == PERMISSION_GRANTED) {
+            return;
+        }
+
+        if (DBG) {
+            Rlog.d(LOG_TAG, "No READ_PRIVILEDED_PHONE_STATE permission, " +
+                    "check carrier privilege next.");
+        }
+
+        enforceCallingOrSelfCarrierPrivilege(subId, message);
+    }
+
+    /**
      * Make sure the caller (or self, if not processing an IPC) has carrier privileges.
      *
      * @throws SecurityException if the caller does not have the required privileges
diff --git a/tests/net/java/android/net/UidRangeTest.java b/tests/net/java/android/net/UidRangeTest.java
index 1d1013e..860d732 100644
--- a/tests/net/java/android/net/UidRangeTest.java
+++ b/tests/net/java/android/net/UidRangeTest.java
@@ -20,7 +20,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
-import android.os.Parcel;
 import android.support.test.runner.AndroidJUnit4;
 import android.support.test.filters.SmallTest;
 
@@ -31,34 +30,10 @@
 @SmallTest
 public class UidRangeTest {
 
-    static {
-        System.loadLibrary("frameworksnettestsjni");
-    }
-
-    private static native byte[] readAndWriteNative(byte[] inParcel);
-    private static native int getStart(byte[] inParcel);
-    private static native int getStop(byte[] inParcel);
-
-    @Test
-    public void testNativeParcelUnparcel() {
-        UidRange original = new UidRange(1234, Integer.MAX_VALUE);
-
-        byte[] inParcel = marshall(original);
-        byte[] outParcel = readAndWriteNative(inParcel);
-        UidRange roundTrip = unmarshall(outParcel);
-
-        assertEquals(original, roundTrip);
-        assertArrayEquals(inParcel, outParcel);
-    }
-
-    @Test
-    public void testIndividualNativeFields() {
-        UidRange original = new UidRange(0x11115678, 0x22224321);
-        byte[] originalBytes = marshall(original);
-
-        assertEquals(original.start, getStart(originalBytes));
-        assertEquals(original.stop, getStop(originalBytes));
-    }
+  /*
+   * UidRange is no longer passed to netd. UID ranges between the framework and netd are passed as
+   * UidRangeParcel objects.
+   */
 
     @Test
     public void testSingleItemUidRangeAllowed() {
@@ -91,28 +66,4 @@
         } catch (IllegalArgumentException expected) {
         }
     }
-
-    /**
-     * Write a {@link UidRange} into an empty parcel and return the underlying data.
-     *
-     * @see unmarshall(byte[])
-     */
-    private static byte[] marshall(UidRange range) {
-        Parcel p = Parcel.obtain();
-        range.writeToParcel(p, /* flags */ 0);
-        p.setDataPosition(0);
-        return p.marshall();
-    }
-
-    /**
-     * Read raw bytes into a parcel, and read a {@link UidRange} back out of them.
-     *
-     * @see marshall(UidRange)
-     */
-    private static UidRange unmarshall(byte[] data) {
-        Parcel p = Parcel.obtain();
-        p.unmarshall(data, 0, data.length);
-        p.setDataPosition(0);
-        return UidRange.CREATOR.createFromParcel(p);
-    }
-}
+}
\ No newline at end of file
diff --git a/tests/net/jni/UidRangeTest.cpp b/tests/net/jni/UidRangeTest.cpp
deleted file mode 100644
index 7941731..0000000
--- a/tests/net/jni/UidRangeTest.cpp
+++ /dev/null
@@ -1,79 +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.
- */
-
-#include <memory>
-
-#include <binder/Parcel.h>
-
-#include "UidRangeTest.h"
-
-using android::net::UidRange;
-
-extern "C"
-JNIEXPORT jbyteArray Java_android_net_UidRangeTest_readAndWriteNative(JNIEnv* env, jclass,
-        jbyteArray inParcel) {
-    const UidRange range = unmarshall(env, inParcel);
-    return marshall(env, range);
-}
-
-extern "C"
-JNIEXPORT jint Java_android_net_UidRangeTest_getStart(JNIEnv* env, jclass, jbyteArray inParcel) {
-    const UidRange range = unmarshall(env, inParcel);
-    return range.getStart();
-}
-
-extern "C"
-JNIEXPORT jint Java_android_net_UidRangeTest_getStop(JNIEnv* env, jclass, jbyteArray inParcel) {
-    const UidRange range = unmarshall(env, inParcel);
-    return range.getStop();
-}
-
-
-/**
- * Reads exactly one UidRange from 'parcelData' assuming that it is a Parcel. Any bytes afterward
- * are ignored.
- */
-UidRange unmarshall(JNIEnv* env, jbyteArray parcelData) {
-    const int length = env->GetArrayLength(parcelData);
-
-    std::unique_ptr<uint8_t> bytes(new uint8_t[length]);
-    env->GetByteArrayRegion(parcelData, 0, length, reinterpret_cast<jbyte*>(bytes.get()));
-
-    android::Parcel p;
-    p.setData(bytes.get(), length);
-
-    UidRange range;
-    range.readFromParcel(&p);
-    return range;
-}
-
-/**
- * Creates a Java byte[] array and writes the contents of 'range' to it as a Parcel containing
- * exactly one object.
- *
- * Every UidRange maps to a unique parcel object, so both 'marshall(e, unmarshall(e, x))' and
- * 'unmarshall(e, marshall(e, x))' should be fixed points.
- */
-jbyteArray marshall(JNIEnv* env, const UidRange& range) {
-    android::Parcel p;
-    range.writeToParcel(&p);
-    const int length = p.dataSize();
-
-    jbyteArray parcelData = env->NewByteArray(length);
-    env->SetByteArrayRegion(parcelData, 0, length, reinterpret_cast<const jbyte*>(p.data()));
-
-    return parcelData;
-}
diff --git a/tests/net/jni/UidRangeTest.h b/tests/net/jni/UidRangeTest.h
deleted file mode 100644
index b7e7453..0000000
--- a/tests/net/jni/UidRangeTest.h
+++ /dev/null
@@ -1,38 +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.
- */
-
-#ifndef _ANDROID_NET_UIDRANGETEST_H_
-#define _ANDROID_NET_UIDRANGETEST_H_
-
-#include <jni.h>
-
-#include "android/net/UidRange.h"
-
-android::net::UidRange unmarshall(JNIEnv* env, jbyteArray parcelData);
-
-jbyteArray marshall(JNIEnv* env, const android::net::UidRange& range);
-
-extern "C"
-JNIEXPORT jbyteArray Java_android_net_UidRangeTest_readAndWriteNative(JNIEnv* env, jclass,
-        jbyteArray inParcel);
-
-extern "C"
-JNIEXPORT jint Java_android_net_UidRangeTest_getStart(JNIEnv* env, jclass, jbyteArray inParcel);
-
-extern "C"
-JNIEXPORT jint Java_android_net_UidRangeTest_getStop(JNIEnv* env, jclass, jbyteArray inParcel);
-
-#endif  //  _ANDROID_NET_UIDRANGETEST_H_