Merge "Protects query pulse reason exception"
diff --git a/api/current.txt b/api/current.txt
index cd33830..4657394 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -41939,13 +41939,13 @@
     method public static long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.system.Int64Ref, long) throws android.system.ErrnoException;
     method public static int sendto(java.io.FileDescriptor, java.nio.ByteBuffer, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
     method public static int sendto(java.io.FileDescriptor, byte[], int, int, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
-    method public static void setegid(int) throws android.system.ErrnoException;
+    method public static deprecated void setegid(int) throws android.system.ErrnoException;
     method public static void setenv(java.lang.String, java.lang.String, boolean) throws android.system.ErrnoException;
-    method public static void seteuid(int) throws android.system.ErrnoException;
-    method public static void setgid(int) throws android.system.ErrnoException;
+    method public static deprecated void seteuid(int) throws android.system.ErrnoException;
+    method public static deprecated void setgid(int) throws android.system.ErrnoException;
     method public static int setsid() throws android.system.ErrnoException;
     method public static void setsockoptInt(java.io.FileDescriptor, int, int, int) throws android.system.ErrnoException;
-    method public static void setuid(int) throws android.system.ErrnoException;
+    method public static deprecated void setuid(int) throws android.system.ErrnoException;
     method public static void setxattr(java.lang.String, java.lang.String, byte[], int) throws android.system.ErrnoException;
     method public static void shutdown(java.io.FileDescriptor, int) throws android.system.ErrnoException;
     method public static java.io.FileDescriptor socket(int, int, int) throws android.system.ErrnoException;
@@ -51901,6 +51901,7 @@
   public abstract class Animation implements java.lang.Cloneable {
     ctor public Animation();
     ctor public Animation(android.content.Context, android.util.AttributeSet);
+    method public void addAnimationListener(android.view.animation.Animation.AnimationListener);
     method protected void applyTransformation(float, android.view.animation.Transformation);
     method public void cancel();
     method protected android.view.animation.Animation clone() throws java.lang.CloneNotSupportedException;
@@ -51925,6 +51926,7 @@
     method public void initialize(int, int, int, int);
     method public boolean isFillEnabled();
     method public boolean isInitialized();
+    method public void removeAnimationListener(android.view.animation.Animation.AnimationListener);
     method public void reset();
     method protected float resolveSize(int, float, int, int);
     method public void restrictDuration(long);
diff --git a/api/system-current.txt b/api/system-current.txt
index 734ac82..f7ea8be 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6269,6 +6269,7 @@
     method public int getSimCardState();
     method public int getSupportedRadioAccessFamily();
     method public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms();
+    method public android.telephony.UiccCardInfo[] getUiccCardsInfo();
     method public android.telephony.UiccSlotInfo[] getUiccSlotsInfo();
     method public android.os.Bundle getVisualVoicemailSettings();
     method public int getVoiceActivationState();
@@ -6365,6 +6366,18 @@
     field public static final android.os.Parcelable.Creator<android.telephony.UiccAccessRule> CREATOR;
   }
 
+  public class UiccCardInfo implements android.os.Parcelable {
+    ctor public UiccCardInfo(boolean, int, java.lang.String, java.lang.String, int);
+    method public int describeContents();
+    method public int getCardId();
+    method public java.lang.String getEid();
+    method public java.lang.String getIccId();
+    method public int getSlotIndex();
+    method public boolean isEuicc();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telephony.UiccCardInfo> CREATOR;
+  }
+
   public class UiccSlotInfo implements android.os.Parcelable {
     ctor public UiccSlotInfo(boolean, boolean, java.lang.String, int, int, boolean);
     method public int describeContents();
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index 7bbeb16..8f28ae1 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -2869,7 +2869,6 @@
 Lcom/android/internal/telephony/dataconnection/DataConnection;->mPhone:Lcom/android/internal/telephony/Phone;
 Lcom/android/internal/telephony/dataconnection/DataConnection;->mRilRat:I
 Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyAllOfConnected(Ljava/lang/String;)V
-Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyAllOfDisconnectDcRetrying(Ljava/lang/String;)V
 Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyDisconnectCompleted(Lcom/android/internal/telephony/dataconnection/DataConnection$DisconnectParams;Z)V
 Lcom/android/internal/telephony/dataconnection/DataConnection;->onConnect(Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams;)V
 Lcom/android/internal/telephony/dataconnection/DataConnection;->tearDownData(Ljava/lang/Object;)V
@@ -2937,7 +2936,6 @@
 Lcom/android/internal/telephony/DctConstants$State;->FAILED:Lcom/android/internal/telephony/DctConstants$State;
 Lcom/android/internal/telephony/DctConstants$State;->IDLE:Lcom/android/internal/telephony/DctConstants$State;
 Lcom/android/internal/telephony/DctConstants$State;->RETRYING:Lcom/android/internal/telephony/DctConstants$State;
-Lcom/android/internal/telephony/DctConstants$State;->SCANNING:Lcom/android/internal/telephony/DctConstants$State;
 Lcom/android/internal/telephony/DctConstants$State;->values()[Lcom/android/internal/telephony/DctConstants$State;
 Lcom/android/internal/telephony/DefaultPhoneNotifier;->mRegistry:Lcom/android/internal/telephony/ITelephonyRegistry;
 Lcom/android/internal/telephony/DriverCall$State;->ACTIVE:Lcom/android/internal/telephony/DriverCall$State;
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 48a767b..3561f71 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -924,6 +924,9 @@
 
     private AutofillPopupWindow mAutofillPopupWindow;
 
+    /** @hide */
+    boolean mEnterAnimationComplete;
+
     private static native String getDlWarning();
 
     /** Return the intent that started this activity. */
@@ -2328,6 +2331,7 @@
             }
             notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_STOP);
         }
+        mEnterAnimationComplete = false;
     }
 
     /**
@@ -7085,6 +7089,8 @@
      * @hide
      */
     public void dispatchEnterAnimationComplete() {
+        mEnterAnimationComplete = true;
+        mInstrumentation.onEnterAnimationComplete();
         onEnterAnimationComplete();
         if (getWindow() != null && getWindow().getDecorView() != null) {
             getWindow().getDecorView().getViewTreeObserver().dispatchOnEnterAnimationComplete();
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 015bc6c..d7c7f3c 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -110,6 +110,7 @@
     private PerformanceCollector mPerformanceCollector;
     private Bundle mPerfMetrics = new Bundle();
     private UiAutomation mUiAutomation;
+    private final Object mAnimationCompleteLock = new Object();
 
     public Instrumentation() {
     }
@@ -397,6 +398,31 @@
         idler.waitForIdle();
     }
 
+    private void waitForEnterAnimationComplete(Activity activity) {
+        synchronized (mAnimationCompleteLock) {
+            long timeout = 5000;
+            try {
+                // We need to check that this specified Activity completed the animation, not just
+                // any Activity. If it was another Activity, then decrease the timeout by how long
+                // it's already waited and wait for the thread to wakeup again.
+                while (timeout > 0 && !activity.mEnterAnimationComplete) {
+                    long startTime = System.currentTimeMillis();
+                    mAnimationCompleteLock.wait(timeout);
+                    long totalTime = System.currentTimeMillis() - startTime;
+                    timeout -= totalTime;
+                }
+            } catch (InterruptedException e) {
+            }
+        }
+    }
+
+    /** @hide */
+    public void onEnterAnimationComplete() {
+        synchronized (mAnimationCompleteLock) {
+            mAnimationCompleteLock.notifyAll();
+        }
+    }
+
     /**
      * Execute a call on the application's main thread, blocking until it is
      * complete.  Useful for doing things that are not thread-safe, such as
@@ -499,6 +525,7 @@
                 }
             } while (mWaitingActivities.contains(aw));
 
+            waitForEnterAnimationComplete(aw.activity);
             return aw.activity;
         }
     }
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index 60eeeea..f8d5014 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -195,12 +195,10 @@
             }
             int childHeight = child.getMeasuredHeight();
             MarginLayoutParams params = (MarginLayoutParams) child.getLayoutParams();
-            left += params.getMarginStart();
-            int right = left + child.getMeasuredWidth();
+            int layoutLeft;
+            int layoutRight;
             int top = (int) (getPaddingTop() + (ownHeight - childHeight) / 2.0f);
             int bottom = top + childHeight;
-            int layoutLeft = left;
-            int layoutRight = right;
             if ((child == mExpandButton && mShowExpandButtonAtEnd)
                     || child == mProfileBadge
                     || child == mAppOps) {
@@ -211,6 +209,12 @@
                 }
                 layoutLeft = layoutRight - child.getMeasuredWidth();
                 end = layoutLeft - params.getMarginStart();
+            } else {
+                left += params.getMarginStart();
+                int right = left + child.getMeasuredWidth();
+                layoutLeft = left;
+                layoutRight = right;
+                left = right + params.getMarginEnd();
             }
             if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
                 int ltrLeft = layoutLeft;
@@ -218,7 +222,6 @@
                 layoutRight = getWidth() - ltrLeft;
             }
             child.layout(layoutLeft, top, layoutRight, bottom);
-            left = right + params.getMarginEnd();
         }
         updateTouchListener();
     }
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index 0e1f767..95a346f 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -30,6 +30,9 @@
 
 import dalvik.system.CloseGuard;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Abstraction for an Animation that can be applied to Views, Surfaces, or
  * other objects. See the {@link android.view.animation animation package
@@ -182,10 +185,14 @@
     Interpolator mInterpolator;
 
     /**
-     * The animation listener to be notified when the animation starts, ends or repeats.
+     * An animation listener to be notified when the animation starts, ends or repeats.
      */
-    @UnsupportedAppUsage
-    AnimationListener mListener;
+    private AnimationListener mListener;
+
+    /**
+     * A list of animation listeners to be notified when the animation starts, ends or repeats.
+     */
+    private List<AnimationListener> mListeners;
 
     /**
      * Desired Z order mode during animation.
@@ -371,23 +378,17 @@
         if (mListenerHandler == null) {
             mOnStart = new Runnable() {
                 public void run() {
-                    if (mListener != null) {
-                        mListener.onAnimationStart(Animation.this);
-                    }
+                    dispatchAnimationStart();
                 }
             };
             mOnRepeat = new Runnable() {
                 public void run() {
-                    if (mListener != null) {
-                        mListener.onAnimationRepeat(Animation.this);
-                    }
+                    dispatchAnimationRepeat();
                 }
             };
             mOnEnd = new Runnable() {
                 public void run() {
-                    if (mListener != null) {
-                        mListener.onAnimationEnd(Animation.this);
-                    }
+                    dispatchAnimationEnd();
                 }
             };
         }
@@ -830,6 +831,10 @@
         return true;
     }
 
+    private boolean hasAnimationListener() {
+        return mListener != null || (mListeners != null && !mListeners.isEmpty());
+    }
+
     /**
      * <p>Binds an animation listener to this animation. The animation listener
      * is notified of animation events such as the end of the animation or the
@@ -842,6 +847,32 @@
     }
 
     /**
+     * <p>Adds an animation listener to this animation. The animation listener
+     * is notified of animation events such as the end of the animation or the
+     * repetition of the animation.</p>
+     *
+     * @param listener the animation listener to be notified
+     */
+    public void addAnimationListener(AnimationListener listener) {
+        if (mListeners == null) {
+            mListeners = new ArrayList<>(1);
+        }
+        mListeners.add(listener);
+    }
+
+    /**
+     * <p>Removes an animation listener that has been added with
+     * {@link #addAnimationListener(AnimationListener)}.</p>
+     *
+     * @param listener the animation listener to be removed
+     */
+    public void removeAnimationListener(AnimationListener listener) {
+        if (mListeners != null) {
+            mListeners.remove(listener);
+        }
+    }
+
+    /**
      * Gurantees that this animation has an interpolator. Will use
      * a AccelerateDecelerateInterpolator is nothing else was specified.
      */
@@ -947,26 +978,59 @@
     }
 
     private void fireAnimationStart() {
-        if (mListener != null) {
-            if (mListenerHandler == null) mListener.onAnimationStart(this);
+        if (hasAnimationListener()) {
+            if (mListenerHandler == null) dispatchAnimationStart();
             else mListenerHandler.postAtFrontOfQueue(mOnStart);
         }
     }
 
     private void fireAnimationRepeat() {
-        if (mListener != null) {
-            if (mListenerHandler == null) mListener.onAnimationRepeat(this);
+        if (hasAnimationListener()) {
+            if (mListenerHandler == null) dispatchAnimationRepeat();
             else mListenerHandler.postAtFrontOfQueue(mOnRepeat);
         }
     }
 
     private void fireAnimationEnd() {
-        if (mListener != null) {
-            if (mListenerHandler == null) mListener.onAnimationEnd(this);
+        if (hasAnimationListener()) {
+            if (mListenerHandler == null) dispatchAnimationEnd();
             else mListenerHandler.postAtFrontOfQueue(mOnEnd);
         }
     }
 
+    void dispatchAnimationStart() {
+        if (mListener != null) {
+            mListener.onAnimationStart(this);
+        }
+        if (mListeners != null && !mListeners.isEmpty()) {
+            for (AnimationListener listener : mListeners) {
+                listener.onAnimationStart(this);
+            }
+        }
+    }
+
+    void dispatchAnimationRepeat() {
+        if (mListener != null) {
+            mListener.onAnimationRepeat(this);
+        }
+        if (mListeners != null && !mListeners.isEmpty()) {
+            for (AnimationListener listener : mListeners) {
+                listener.onAnimationRepeat(this);
+            }
+        }
+    }
+
+    void dispatchAnimationEnd() {
+        if (mListener != null) {
+            mListener.onAnimationEnd(this);
+        }
+        if (mListeners != null && !mListeners.isEmpty()) {
+            for (AnimationListener listener : mListeners) {
+                listener.onAnimationEnd(this);
+            }
+        }
+    }
+
     /**
      * Gets the transformation to apply at a specified point in time. Implementations of this
      * method should always replace the specified Transformation or document they are doing
diff --git a/core/java/android/view/animation/AnimationSet.java b/core/java/android/view/animation/AnimationSet.java
index 767024e..03c6ca6 100644
--- a/core/java/android/view/animation/AnimationSet.java
+++ b/core/java/android/view/animation/AnimationSet.java
@@ -389,16 +389,12 @@
         }
 
         if (started && !mStarted) {
-            if (mListener != null) {
-                mListener.onAnimationStart(this);
-            }
+            dispatchAnimationStart();
             mStarted = true;
         }
 
         if (ended != mEnded) {
-            if (mListener != null) {
-                mListener.onAnimationEnd(this);
-            }
+            dispatchAnimationEnd();
             mEnded = ended;
         }
 
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 36e81e6..1ba7d8e 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -26,6 +26,8 @@
 import android.annotation.SystemService;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
+import android.app.ActivityThread;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.graphics.Rect;
@@ -37,11 +39,13 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
 import android.os.ServiceManager.ServiceNotFoundException;
 import android.os.Trace;
+import android.provider.Settings;
 import android.text.style.SuggestionSpan;
 import android.util.Log;
 import android.util.Pools.Pool;
@@ -232,6 +236,8 @@
 
     static final String PENDING_EVENT_COUNTER = "aq:imm";
 
+    private static final int NOT_A_SUBTYPE_ID = -1;
+
     /**
      * A constant that represents Voice IME.
      *
@@ -2071,6 +2077,13 @@
     /**
      * Force switch to a new input method component. This can only be called
      * from an application or a service which has a token of the currently active input method.
+     *
+     * <p>On Android {@link Build.VERSION_CODES#Q} and later devices, the undocumented behavior that
+     * token can be {@code null} when the caller has
+     * {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} is deprecated. Instead, update
+     * {@link android.provider.Settings.Secure#DEFAULT_INPUT_METHOD} and
+     * {@link android.provider.Settings.Secure#SELECTED_INPUT_METHOD_SUBTYPE} directly.</p>
+     *
      * @param token Supplies the identifying token given to an input method
      * when it was started, which allows it to perform this operation on
      * itself.
@@ -2082,14 +2095,50 @@
     @Deprecated
     public void setInputMethod(IBinder token, String id) {
         if (token == null) {
-            // Note: null token is allowed for callers that have WRITE_SECURE_SETTINGS permission.
-            // Thus we cannot always rely on InputMethodPrivilegedOperationsRegistry unfortunately.
-            // TODO(Bug 114488811): Consider deprecating null token rule.
-            try {
-                mService.setInputMethod(token, id);
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
+            // There are still some system components that rely on this undocumented behavior
+            // regarding null IME token with WRITE_SECURE_SETTINGS.  Provide a fallback logic as a
+            // temporary remedy.
+            if (id == null) {
+                return;
             }
+            if (Process.myUid() == Process.SYSTEM_UID) {
+                Log.w(TAG, "System process should not be calling setInputMethod() because almost "
+                        + "always it is a bug under multi-user / multi-profile environment. "
+                        + "Consider interacting with InputMethodManagerService directly via "
+                        + "LocalServices.");
+                return;
+            }
+            final Context fallbackContext = ActivityThread.currentApplication();
+            if (fallbackContext == null) {
+                return;
+            }
+            if (fallbackContext.checkSelfPermission(WRITE_SECURE_SETTINGS)
+                    != PackageManager.PERMISSION_GRANTED) {
+                return;
+            }
+            final List<InputMethodInfo> imis = getEnabledInputMethodList();
+            final int numImis = imis.size();
+            boolean found = false;
+            for (int i = 0; i < numImis; ++i) {
+                final InputMethodInfo imi = imis.get(i);
+                if (id.equals(imi.getId())) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) {
+                Log.e(TAG, "Ignoring setInputMethod(null, " + id + ") because the specified "
+                        + "id not found in enabled IMEs.");
+                return;
+            }
+            Log.w(TAG, "The undocumented behavior that setInputMethod() accepts null token "
+                    + "when the caller has WRITE_SECURE_SETTINGS is deprecated. This behavior may "
+                    + "be completely removed in a future version.  Update secure settings directly "
+                    + "instead.");
+            final ContentResolver resolver = fallbackContext.getContentResolver();
+            Settings.Secure.putInt(resolver, Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE,
+                    NOT_A_SUBTYPE_ID);
+            Settings.Secure.putString(resolver, Settings.Secure.DEFAULT_INPUT_METHOD, id);
             return;
         }
         InputMethodPrivilegedOperationsRegistry.get(token).setInputMethod(id);
diff --git a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
index d4c451e..78d366c 100644
--- a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
+++ b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
@@ -68,10 +68,10 @@
 
     public boolean wakeLockScreenGestureEnabled(int user) {
         return boolSettingDefaultOn(Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE, user)
-                && wakeLockScreenGestureAvailable();
+                && wakeScreenGestureAvailable();
     }
 
-    public boolean wakeLockScreenGestureAvailable() {
+    public boolean wakeScreenGestureAvailable() {
         return mContext.getResources()
                 .getBoolean(R.bool.config_dozeWakeLockScreenSensorAvailable);
     }
@@ -81,10 +81,6 @@
                 && wakeScreenGestureAvailable();
     }
 
-    public boolean wakeScreenGestureAvailable() {
-        return !TextUtils.isEmpty(wakeScreenSensorType());
-    }
-
     public String doubleTapSensorType() {
         return mContext.getResources().getString(R.string.config_dozeDoubleTapSensorType);
     }
@@ -93,10 +89,6 @@
         return mContext.getResources().getString(R.string.config_dozeLongPressSensorType);
     }
 
-    public String wakeScreenSensorType() {
-        return mContext.getResources().getString(R.string.config_dozeWakeScreenSensorType);
-    }
-
     public boolean pulseOnLongPressEnabled(int user) {
         return pulseOnLongPressAvailable() && boolSettingDefaultOff(
                 Settings.Secure.DOZE_PULSE_ON_LONG_PRESS, user);
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 3873d24..70f4ed2 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -65,8 +65,6 @@
             int displayId);
     void showInputMethodAndSubtypeEnablerFromClient(in IInputMethodClient client, String topId);
     boolean isInputMethodPickerShownForTest();
-    // TODO(Bug 114488811): this can be removed once we deprecate special null token rule.
-    void setInputMethod(in IBinder token, String id);
     void registerSuggestionSpansForNotification(in SuggestionSpan[] spans);
     boolean notifySuggestionPicked(in SuggestionSpan span, String originalString, int index);
     InputMethodSubtype getCurrentInputMethodSubtype();
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 9f5eab5..cb4f416 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2160,9 +2160,6 @@
     <!-- If the sensor that wakes up the lock screen is available or not. -->
     <bool name="config_dozeWakeLockScreenSensorAvailable">false</bool>
 
-    <!-- Type of the wake up sensor. Empty if not supported. -->
-    <string name="config_dozeWakeScreenSensorType" translatable="false"></string>
-
     <!-- Control whether the always on display mode is available. This should only be enabled on
          devices where the display has been tuned to be power efficient in DOZE and/or DOZE_SUSPEND
          states. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e5ff1aa..a4a97d3 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3499,7 +3499,6 @@
 
   <java-symbol type="integer" name="db_wal_truncate_size" />
   <java-symbol type="integer" name="config_wakeUpDelayDoze" />
-  <java-symbol type="string" name="config_dozeWakeScreenSensorType" />
 
   <!-- For Bluetooth AbsoluteVolume -->
   <java-symbol type="fraction" name="config_prescaleAbsoluteVolume_index1" />
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
index 953cef7d..aa29174 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
@@ -210,6 +210,10 @@
                         throw new InvalidAlgorithmParameterException(
                             "HMAC key size must be at least 64 bits.");
                     }
+                    if (mKeySizeBits > 512 && spec.isStrongBoxBacked()) {
+                        throw new InvalidAlgorithmParameterException(
+                            "StrongBox HMAC key size must be smaller than 512 bits.");
+                    }
 
                     // JCA HMAC key algorithm implies a digest (e.g., HmacSHA256 key algorithm
                     // implies SHA-256 digest). Because keymaster HMAC key is authorized only for
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index 5fc742a..d44c894 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -303,7 +303,7 @@
             if (mKeySizeBits == -1) {
                 mKeySizeBits = getDefaultKeySize(keymasterAlgorithm);
             }
-            checkValidKeySize(keymasterAlgorithm, mKeySizeBits);
+            checkValidKeySize(keymasterAlgorithm, mKeySizeBits, mSpec.isStrongBoxBacked());
 
             if (spec.getKeystoreAlias() == null) {
                 throw new InvalidAlgorithmParameterException("KeyStore entry alias not provided");
@@ -724,10 +724,18 @@
         }
     }
 
-    private static void checkValidKeySize(int keymasterAlgorithm, int keySize)
+    private static void checkValidKeySize(
+            int keymasterAlgorithm,
+            int keySize,
+            boolean isStrongBoxBacked)
             throws InvalidAlgorithmParameterException {
         switch (keymasterAlgorithm) {
             case KeymasterDefs.KM_ALGORITHM_EC:
+                if (isStrongBoxBacked && keySize != 256) {
+                    throw new InvalidAlgorithmParameterException(
+                            "Unsupported StrongBox EC key size: "
+                            + keySize + " bits. Supported: 256");
+                }
                 if (!SUPPORTED_EC_NIST_CURVE_SIZES.contains(keySize)) {
                     throw new InvalidAlgorithmParameterException("Unsupported EC key size: "
                             + keySize + " bits. Supported: " + SUPPORTED_EC_NIST_CURVE_SIZES);
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 1cdc291..125ab2e 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -479,7 +479,7 @@
         public static final int HE_AAC = 4;
         /** Enhanced Low Delay AAC (AAC-ELD) audio codec */
         public static final int AAC_ELD = 5;
-        /** Ogg Vorbis audio codec */
+        /** Ogg Vorbis audio codec (Support is optional) */
         public static final int VORBIS = 6;
         /** Opus audio codec */
         public static final int OPUS = 7;
diff --git a/media/java/android/media/Session2Command.java b/media/java/android/media/Session2Command.java
new file mode 100644
index 0000000..a5e2ae4
--- /dev/null
+++ b/media/java/android/media/Session2Command.java
@@ -0,0 +1,596 @@
+/*
+ * Copyright 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.media;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Define a command that a {@link MediaController2} can send to a {@link MediaSession2}.
+ * <p>
+ * If {@link #getCommandCode()} isn't {@link #COMMAND_CODE_CUSTOM}), it's predefined command.
+ * If {@link #getCommandCode()} is {@link #COMMAND_CODE_CUSTOM}), it's custom command and
+ * {@link #getCustomCommand()} shouldn't be {@code null}.
+ * <p>
+ * This API is not generally intended for third party application developers.
+ * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
+ * for consistent behavior across all devices.
+ * </p>
+ * @hide
+ */
+public final class Session2Command implements Parcelable {
+    /**
+     * The first version of session commands. This version is for commands introduced in API 29.
+     * <p>
+     * This would be used to specify which commands should be added by
+     * {@link Session2CommandGroup.Builder#addAllPredefinedCommands(int)}
+     *
+     * @see Session2CommandGroup.Builder#addAllPredefinedCommands(int)
+     */
+    public static final int COMMAND_VERSION_1 = 1;
+
+    /**
+     * @hide
+     */
+    public static final int COMMAND_VERSION_CURRENT = COMMAND_VERSION_1;
+
+    /**
+     * @hide
+     */
+    @IntDef({COMMAND_VERSION_1})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CommandVersion {}
+
+    /**
+     * @hide
+     */
+    @IntDef({COMMAND_CODE_CUSTOM,
+            COMMAND_CODE_PLAYER_PLAY,
+            COMMAND_CODE_PLAYER_PAUSE,
+            COMMAND_CODE_PLAYER_PREPARE,
+            COMMAND_CODE_PLAYER_SEEK_TO,
+            COMMAND_CODE_PLAYER_SET_SPEED,
+            COMMAND_CODE_PLAYER_GET_PLAYLIST,
+            COMMAND_CODE_PLAYER_SET_PLAYLIST,
+            COMMAND_CODE_PLAYER_SKIP_TO_PLAYLIST_ITEM,
+            COMMAND_CODE_PLAYER_SKIP_TO_PREVIOUS_PLAYLIST_ITEM,
+            COMMAND_CODE_PLAYER_SKIP_TO_NEXT_PLAYLIST_ITEM,
+            COMMAND_CODE_PLAYER_SET_SHUFFLE_MODE,
+            COMMAND_CODE_PLAYER_SET_REPEAT_MODE,
+            COMMAND_CODE_PLAYER_GET_PLAYLIST_METADATA,
+            COMMAND_CODE_PLAYER_ADD_PLAYLIST_ITEM,
+            COMMAND_CODE_PLAYER_REMOVE_PLAYLIST_ITEM,
+            COMMAND_CODE_PLAYER_REPLACE_PLAYLIST_ITEM,
+            COMMAND_CODE_PLAYER_GET_CURRENT_MEDIA_ITEM,
+            COMMAND_CODE_PLAYER_UPDATE_LIST_METADATA,
+            COMMAND_CODE_PLAYER_SET_MEDIA_ITEM,
+            COMMAND_CODE_VOLUME_SET_VOLUME,
+            COMMAND_CODE_VOLUME_ADJUST_VOLUME,
+            COMMAND_CODE_SESSION_FAST_FORWARD,
+            COMMAND_CODE_SESSION_REWIND,
+            COMMAND_CODE_SESSION_SKIP_FORWARD,
+            COMMAND_CODE_SESSION_SKIP_BACKWARD,
+            COMMAND_CODE_SESSION_SET_RATING,
+            COMMAND_CODE_LIBRARY_GET_LIBRARY_ROOT,
+            COMMAND_CODE_LIBRARY_SUBSCRIBE,
+            COMMAND_CODE_LIBRARY_UNSUBSCRIBE,
+            COMMAND_CODE_LIBRARY_GET_CHILDREN,
+            COMMAND_CODE_LIBRARY_GET_ITEM,
+            COMMAND_CODE_LIBRARY_SEARCH,
+            COMMAND_CODE_LIBRARY_GET_SEARCH_RESULT
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CommandCode {}
+
+    /**
+     * Command code for the custom command which can be defined by string action in the
+     * {@link Session2Command}.
+     */
+    public static final int COMMAND_CODE_CUSTOM = 0;
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////
+    // Player commands (i.e. commands to {@link Session2Player})
+    ////////////////////////////////////////////////////////////////////////////////////////////////
+    static final ArrayMap<Integer, Range> VERSION_PLAYER_COMMANDS_MAP = new ArrayMap<>();
+    static final ArrayMap<Integer, Range> VERSION_PLAYER_PLAYLIST_COMMANDS_MAP = new ArrayMap<>();
+
+    // TODO: check the link tag, and reassign int values properly.
+    /**
+     * Command code for {@link MediaController2#play()}.
+     * <p>
+     * Command would be sent directly to the player if the session doesn't reject the request
+     * through the {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info,
+     * Session2Command)}.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_PLAYER_PLAY = 10000;
+
+    /**
+     * Command code for {@link MediaController2#pause()}.
+     * <p>
+     * Command would be sent directly to the player if the session doesn't reject the request
+     * through the {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info,
+     * Session2Command)}.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_PLAYER_PAUSE = 10001;
+
+    /**
+     * Command code for {@link MediaController2#prepare()}.
+     * <p>
+     * Command would be sent directly to the player if the session doesn't reject the request
+     * through the {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info,
+     * Session2Command)}.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_PLAYER_PREPARE = 10002;
+
+    /**
+     * Command code for {@link MediaController2#seekTo(long)}.
+     * <p>
+     * Command would be sent directly to the player if the session doesn't reject the request
+     * through the {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info,
+     * Session2Command)}.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_PLAYER_SEEK_TO = 10003;
+
+    /**
+     * Command code for {@link MediaController2#setPlaybackSpeed(float)}}.
+     * <p>
+     * Command would be sent directly to the player if the session doesn't reject the request
+     * through the {@link Session22Callback#onCommandRequest(MediaSession2, Controller2Info,
+     * Session2Command)}.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_PLAYER_SET_SPEED = 10004;
+
+    /**
+     * Command code for {@link MediaController2#getPlaylist()}. This will expose metadata
+     * information to the controller.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_PLAYER_GET_PLAYLIST = 10005;
+
+    /**
+     * Command code for {@link MediaController2#setPlaylist(List, MediaMetadata)}.
+     * <p>
+     * Command would be sent directly to the player if the session doesn't reject the request
+     * through the
+     * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)}.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_PLAYER_SET_PLAYLIST = 10006;
+
+    /**
+     * Command code for {@link MediaController2#skipToPlaylistItem(int)}.
+     * <p>
+     * Command would be sent directly to the player if the session doesn't reject the request
+     * through the
+     * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)}.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_PLAYER_SKIP_TO_PLAYLIST_ITEM = 10007;
+
+    /**
+     * Command code for {@link MediaController2#skipToPreviousPlaylistItem()}.
+     * <p>
+     * Command would be sent directly to the player if the session doesn't reject the request
+     * through the {@link Session2Callback#onCommandRequest(
+     * MediaSession2, Controller2Info, Session2Command)}.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_PLAYER_SKIP_TO_PREVIOUS_PLAYLIST_ITEM = 10008;
+
+    /**
+     * Command code for {@link MediaController2#skipToNextPlaylistItem()}.
+     * <p>
+     * Command would be sent directly to the player if the session doesn't reject the request
+     * through the {@link Session2Callback#onCommandRequest(
+     * MediaSession2, Controller2Info, Session2Command)}.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+
+    public static final int COMMAND_CODE_PLAYER_SKIP_TO_NEXT_PLAYLIST_ITEM = 10009;
+
+    /**
+     * Command code for {@link MediaController2#setShuffleMode(int)}.
+     * <p>
+     * Command would be sent directly to the player if the session doesn't reject the request
+     * through the
+     * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)}.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_PLAYER_SET_SHUFFLE_MODE = 10010;
+
+    /**
+     * Command code for {@link MediaController2#setRepeatMode(int)}.
+     * <p>
+     * Command would be sent directly to the player if the session doesn't reject the request
+     * through the
+     * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)}.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_PLAYER_SET_REPEAT_MODE = 10011;
+
+    /**
+     * Command code for {@link MediaController2#getPlaylistMetadata()}. This will expose metadata
+     * information to the controller.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_PLAYER_GET_PLAYLIST_METADATA = 10012;
+
+    /**
+     * Command code for {@link MediaController2#addPlaylistItem(int, String)}.
+     * <p>
+     * Command would be sent directly to the player if the session doesn't reject the request
+     * through the
+     * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)}.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_PLAYER_ADD_PLAYLIST_ITEM = 10013;
+
+    /**
+     * Command code for {@link MediaController2#removePlaylistItem(int, String)}.
+     * <p>
+     * Command would be sent directly to the player if the session doesn't reject the request
+     * through the
+     * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)}.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_PLAYER_REMOVE_PLAYLIST_ITEM = 10014;
+
+    /**
+     * Command code for {@link MediaController2#replacePlaylistItem(int, String)}.
+     * <p>
+     * Command would be sent directly to the player if the session doesn't reject the request
+     * through the
+     * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)}.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_PLAYER_REPLACE_PLAYLIST_ITEM = 10015;
+
+    /**
+     * Command code for {@link MediaController2#getCurrentMediaItem()}. This will expose metadata
+     * information to the controller.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_PLAYER_GET_CURRENT_MEDIA_ITEM = 10016;
+
+    /**
+     * Command code for {@link MediaController2#updatePlaylistMetadata(MediaMetadata)}.
+     * <p>
+     * Command would be sent directly to the player if the session doesn't reject the request
+     * through the
+     * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)}.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_PLAYER_UPDATE_LIST_METADATA = 10017;
+
+    /**
+     * Command code for {@link MediaController2#setMediaItem(String)}.
+     * <p>
+     * Command would be sent directly to the player if the session doesn't reject the request
+     * through the
+     * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)}.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_PLAYER_SET_MEDIA_ITEM = 10018;
+
+    static {
+        VERSION_PLAYER_COMMANDS_MAP.put(COMMAND_VERSION_1,
+                new Range(COMMAND_CODE_PLAYER_PLAY, COMMAND_CODE_PLAYER_SET_MEDIA_ITEM));
+    }
+
+    static {
+        VERSION_PLAYER_PLAYLIST_COMMANDS_MAP.put(COMMAND_VERSION_1,
+                new Range(COMMAND_CODE_PLAYER_GET_PLAYLIST,
+                        COMMAND_CODE_PLAYER_SET_MEDIA_ITEM));
+    }
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////
+    // Volume commands (i.e. commands to {@link AudioManager} or {@link RouteMediaPlayer})
+    ////////////////////////////////////////////////////////////////////////////////////////////////
+    static final ArrayMap<Integer, Range> VERSION_VOLUME_COMMANDS_MAP = new ArrayMap<>();
+
+    /**
+     * Command code for {@link MediaController2#setVolumeTo(int, int)}.
+     * <p>
+     * <p>
+     * If the session doesn't reject the request through the
+     * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)},
+     * command would adjust the device volume. It would send to the player directly only if it's
+     * remote player. See RouteMediaPlayer for a remote player.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_VOLUME_SET_VOLUME = 30000;
+
+    /**
+     * Command code for {@link MediaController2#adjustVolume(int, int)}.
+     * <p>
+     * If the session doesn't reject the request through the
+     * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)},
+     * command would adjust the device volume. It would send to the player directly only if it's
+     * remote player. See RouteMediaPlayer for a remote player.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_VOLUME_ADJUST_VOLUME = 30001;
+
+    static {
+        VERSION_VOLUME_COMMANDS_MAP.put(COMMAND_VERSION_1,
+                new Range(COMMAND_CODE_VOLUME_SET_VOLUME,
+                        COMMAND_CODE_VOLUME_ADJUST_VOLUME));
+    }
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////
+    // Session commands (i.e. commands to {@link MediaSession2#Session2Callback})
+    ////////////////////////////////////////////////////////////////////////////////////////////////
+    static final ArrayMap<Integer, Range> VERSION_SESSION_COMMANDS_MAP = new ArrayMap<>();
+
+    /**
+     * Command code for {@link MediaController2#fastForward()}.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_SESSION_FAST_FORWARD = 40000;
+
+    /**
+     * Command code for {@link MediaController2#rewind()}.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_SESSION_REWIND = 40001;
+
+    /**
+     * Command code for {@link MediaController2#skipForward()}.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_SESSION_SKIP_FORWARD = 40002;
+
+    /**
+     * Command code for {@link MediaController2#skipBackward()}.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_SESSION_SKIP_BACKWARD = 40003;
+
+    /**
+     * Command code for {@link MediaController2#setRating(String, Rating)}.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_SESSION_SET_RATING = 40010;
+
+    public static final Parcelable.Creator<Session2Command> CREATOR =
+            new Parcelable.Creator<Session2Command>() {
+                @Override
+                public Session2Command createFromParcel(Parcel in) {
+                    return new Session2Command(in);
+                }
+
+                @Override
+                public Session2Command[] newArray(int size) {
+                    return new Session2Command[size];
+                }
+            };
+
+    static {
+        VERSION_SESSION_COMMANDS_MAP.put(COMMAND_VERSION_1,
+                new Range(COMMAND_CODE_SESSION_FAST_FORWARD, COMMAND_CODE_SESSION_SET_RATING));
+    }
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////
+    // Session commands (i.e. commands to {@link MediaLibrarySession#MediaLibrarySessionCallback})
+    ////////////////////////////////////////////////////////////////////////////////////////////////
+    static final ArrayMap<Integer, Range> VERSION_LIBRARY_COMMANDS_MAP = new ArrayMap<>();
+
+    /**
+     * Command code for {@link MediaBrowser2#getLibraryRoot(Library2Params)}.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_LIBRARY_GET_LIBRARY_ROOT = 50000;
+
+    /**
+     * Command code for {@link MediaBrowser2#subscribe(String, Library2Params)}.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_LIBRARY_SUBSCRIBE = 50001;
+
+    /**
+     * Command code for {@link MediaBrowser2#unsubscribe(String)}.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_LIBRARY_UNSUBSCRIBE = 50002;
+
+    /**
+     * Command code for {@link MediaBrowser2#getChildren(String, int, int, Library2Params)}.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_LIBRARY_GET_CHILDREN = 50003;
+
+    /**
+     * Command code for {@link MediaBrowser2#getItem(String)}.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_LIBRARY_GET_ITEM = 50004;
+
+    /**
+     * Command code for {@link MediaBrowser2#search(String, LibraryParams)}.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_LIBRARY_SEARCH = 50005;
+
+    /**
+     * Command code for {@link MediaBrowser2#getSearchResult(String, int, int, Library2Params)}.
+     * <p>
+     * Code version is {@link #COMMAND_VERSION_1}.
+     */
+    public static final int COMMAND_CODE_LIBRARY_GET_SEARCH_RESULT = 50006;
+
+    static {
+        VERSION_LIBRARY_COMMANDS_MAP.put(COMMAND_VERSION_1,
+                new Range(COMMAND_CODE_LIBRARY_GET_LIBRARY_ROOT,
+                        COMMAND_CODE_LIBRARY_GET_SEARCH_RESULT));
+    }
+
+    @CommandCode private final int mCommandCode;
+    // Nonnull if it's custom command
+    private final String mCustomCommand;
+    private final Bundle mExtras;
+
+    /**
+     * Constructor for creating a predefined command.
+     *
+     * @param commandCode A command code for predefined command.
+     */
+    public Session2Command(@CommandCode int commandCode) {
+        if (commandCode == COMMAND_CODE_CUSTOM) {
+            throw new IllegalArgumentException("commandCode shouldn't be COMMAND_CODE_CUSTOM");
+        }
+        mCommandCode = commandCode;
+        mCustomCommand = null;
+        mExtras = null;
+    }
+
+    /**
+     * Constructor for creating a custom command.
+     *
+     * @param action The action of this custom command.
+     * @param extras An extra bundle for this custom command.
+     */
+    public Session2Command(@NonNull String action, @Nullable Bundle extras) {
+        if (action == null) {
+            throw new IllegalArgumentException("action shouldn't be null");
+        }
+        mCommandCode = COMMAND_CODE_CUSTOM;
+        mCustomCommand = action;
+        mExtras = extras;
+    }
+
+    /**
+     * Used by parcelable creator.
+     */
+    @SuppressWarnings("WeakerAccess") /* synthetic access */
+    Session2Command(Parcel in) {
+        mCommandCode = in.readInt();
+        mCustomCommand = in.readString();
+        mExtras = in.readBundle();
+    }
+
+    /**
+     * Gets the command code of a predefined command.
+     * This will return {@link #COMMAND_CODE_CUSTOM} for a custom command.
+     */
+    public @CommandCode int getCommandCode() {
+        return mCommandCode;
+    }
+
+    /**
+     * Gets the action of a custom command.
+     * This will return {@code null} for a predefined command.
+     */
+    public @Nullable String getCustomCommand() {
+        return mCustomCommand;
+    }
+
+    /**
+     * Gets the extra bundle of a custom command.
+     * This will return {@code null} for a predefined command.
+     */
+    public @Nullable Bundle getExtras() {
+        return mExtras;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mCommandCode);
+        dest.writeString(mCustomCommand);
+        dest.writeBundle(mExtras);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof Session2Command)) {
+            return false;
+        }
+        Session2Command other = (Session2Command) obj;
+        return mCommandCode == other.mCommandCode
+                && TextUtils.equals(mCustomCommand, other.mCustomCommand);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mCustomCommand, mCommandCode);
+    }
+
+    @SuppressWarnings("WeakerAccess") /* synthetic access */
+    static final class Range {
+        public final int lower;
+        public final int upper;
+
+        Range(int lower, int upper) {
+            this.lower = lower;
+            this.upper = upper;
+        }
+    }
+}
+
diff --git a/media/java/android/media/Session2CommandGroup.java b/media/java/android/media/Session2CommandGroup.java
new file mode 100644
index 0000000..de34fe5
--- /dev/null
+++ b/media/java/android/media/Session2CommandGroup.java
@@ -0,0 +1,321 @@
+/*
+ * Copyright 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.media;
+
+import static android.media.Session2Command.COMMAND_CODE_CUSTOM;
+import static android.media.Session2Command.COMMAND_VERSION_1;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.media.Session2Command.Range;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArrayMap;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A set of {@link Session2Command} which represents a command group.
+ * <p>
+ * This API is not generally intended for third party application developers.
+ * Use the <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>
+ * {@link androidx.media2.SessionCommandGroup} for consistent behavior across all devices.
+ * </p>
+ * @hide
+ */
+public final class Session2CommandGroup implements Parcelable {
+    private static final String TAG = "Session2CommandGroup";
+
+    public static final Parcelable.Creator<Session2CommandGroup> CREATOR =
+            new Parcelable.Creator<Session2CommandGroup>() {
+                @Override
+                public Session2CommandGroup createFromParcel(Parcel in) {
+                    return new Session2CommandGroup(in);
+                }
+
+                @Override
+                public Session2CommandGroup[] newArray(int size) {
+                    return new Session2CommandGroup[size];
+                }
+            };
+
+    Set<Session2Command> mCommands = new HashSet<>();
+
+    /**
+     * Default Constructor.
+     */
+    public Session2CommandGroup() { }
+
+    /**
+     * Creates a new Session2CommandGroup with commands copied from another object.
+     *
+     * @param commands The collection of commands to copy.
+     */
+    public Session2CommandGroup(@Nullable Collection<Session2Command> commands) {
+        if (commands != null) {
+            mCommands.addAll(commands);
+        }
+    }
+
+    /**
+     * Used by parcelable creator.
+     */
+    @SuppressWarnings("WeakerAccess") /* synthetic access */
+    Session2CommandGroup(Parcel in) {
+        Session2Command[] commands = in.readParcelableArray(
+                Session2Command.class.getClassLoader(), Session2Command.class);
+        if (commands != null) {
+            for (Session2Command command : commands) {
+                mCommands.add(command);
+            }
+        }
+    }
+
+    /**
+     * Adds a command to this command group.
+     *
+     * @param command A command to add. Shouldn't be {@code null}.
+     * @hide TODO remove this method
+     */
+    public void addCommand(@NonNull Session2Command command) {
+        if (command == null) {
+            throw new IllegalArgumentException("command shouldn't be null");
+        }
+        if (!hasCommand(command)) {
+            mCommands.add(command);
+        }
+    }
+
+    /**
+     * Adds a predefined command with given {@code commandCode} to this command group.
+     *
+     * @param commandCode A command code to add.
+     *                    Shouldn't be {@link Session2Command#COMMAND_CODE_CUSTOM}.
+     * @hide TODO remove this method
+     */
+    public void addCommand(@Session2Command.CommandCode int commandCode) {
+        if (commandCode == COMMAND_CODE_CUSTOM) {
+            throw new IllegalArgumentException(
+                    "Use addCommand(Session2Command) for COMMAND_CODE_CUSTOM.");
+        }
+        if (!hasCommand(commandCode)) {
+            mCommands.add(new Session2Command(commandCode));
+        }
+    }
+
+    /**
+     * Checks whether this command group has a command that matches given {@code command}.
+     *
+     * @param command A command to find. Shouldn't be {@code null}.
+     */
+    public boolean hasCommand(@NonNull Session2Command command) {
+        if (command == null) {
+            throw new IllegalArgumentException("command shouldn't be null");
+        }
+        return mCommands.contains(command);
+    }
+
+    /**
+     * Checks whether this command group has a command that matches given {@code commandCode}.
+     *
+     * @param commandCode A command code to find.
+     *                    Shouldn't be {@link Session2Command#COMMAND_CODE_CUSTOM}.
+     */
+    public boolean hasCommand(@Session2Command.CommandCode int commandCode) {
+        if (commandCode == COMMAND_CODE_CUSTOM) {
+            throw new IllegalArgumentException("Use hasCommand(Command) for custom command");
+        }
+        for (Session2Command command : mCommands) {
+            if (command.getCommandCode() == commandCode) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Gets all commands of this command group.
+     */
+    public @NonNull Set<Session2Command> getCommands() {
+        return new HashSet<>(mCommands);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeParcelableArray((Session2Command[]) mCommands.toArray(), 0);
+    }
+
+    /**
+     * Builds a {@link Session2CommandGroup} object.
+     */
+    public static final class Builder {
+        private Set<Session2Command> mCommands;
+
+        public Builder() {
+            mCommands = new HashSet<>();
+        }
+
+        /**
+         * Creates a new builder for {@link Session2CommandGroup} with commands copied from another
+         * {@link Session2CommandGroup} object.
+         * @param commandGroup
+         */
+        public Builder(@NonNull Session2CommandGroup commandGroup) {
+            mCommands = commandGroup.getCommands();
+        }
+
+        /**
+         * Adds a command to this command group.
+         *
+         * @param command A command to add. Shouldn't be {@code null}.
+         */
+        public @NonNull Builder addCommand(@NonNull Session2Command command) {
+            if (command == null) {
+                throw new IllegalArgumentException("command shouldn't be null");
+            }
+            mCommands.add(command);
+            return this;
+        }
+
+        /**
+         * Adds a predefined command with given {@code commandCode} to this command group.
+         *
+         * @param commandCode A command code to add.
+         *                    Shouldn't be {@link Session2Command#COMMAND_CODE_CUSTOM}.
+         */
+        public @NonNull Builder addCommand(@Session2Command.CommandCode int commandCode) {
+            if (commandCode == COMMAND_CODE_CUSTOM) {
+                throw new IllegalArgumentException(
+                        "Use addCommand(Session2Command) for COMMAND_CODE_CUSTOM.");
+            }
+            mCommands.add(new Session2Command(commandCode));
+            return this;
+        }
+
+        /**
+         * Adds all predefined session commands except for the commands added after the specified
+         * version without default implementation. This provides convenient way to add commands
+         * with implementation.
+         *
+         * @param version command version
+         * @see Session2Command#COMMAND_VERSION_1
+         * @see
+         * MediaSession2.Session2Callback#onConnect
+         */
+        public @NonNull Builder addAllPredefinedCommands(
+                @Session2Command.CommandVersion int version) {
+            if (version != COMMAND_VERSION_1) {
+                throw new IllegalArgumentException("Unknown command version " + version);
+            }
+            addAllPlayerCommands(version);
+            addAllVolumeCommands(version);
+            addAllSessionCommands(version);
+            addAllLibraryCommands(version);
+            return this;
+        }
+
+        /**
+         * Removes a command from this group which matches given {@code command}.
+         *
+         * @param command A command to find. Shouldn't be {@code null}.
+         */
+        public @NonNull Builder removeCommand(@NonNull Session2Command command) {
+            if (command == null) {
+                throw new IllegalArgumentException("command shouldn't be null");
+            }
+            mCommands.remove(command);
+            return this;
+        }
+
+        /**
+         * Removes a command from this group which matches given {@code commandCode}.
+         *
+         * @param commandCode A command code to find.
+         *                    Shouldn't be {@link Session2Command#COMMAND_CODE_CUSTOM}.
+         */
+        public @NonNull Builder removeCommand(@Session2Command.CommandCode int commandCode) {
+            if (commandCode == COMMAND_CODE_CUSTOM) {
+                throw new IllegalArgumentException("commandCode shouldn't be COMMAND_CODE_CUSTOM");
+            }
+            mCommands.remove(new Session2Command(commandCode));
+            return this;
+        }
+
+        @NonNull Builder addAllPlayerCommands(@Session2Command.CommandVersion int version) {
+            addCommands(version, Session2Command.VERSION_PLAYER_COMMANDS_MAP);
+            return this;
+        }
+
+        @NonNull Builder addAllPlayerCommands(@Session2Command.CommandVersion int version,
+                boolean includePlaylistCommands) {
+            if (includePlaylistCommands) {
+                return addAllPlayerCommands(version);
+            }
+            for (int i = COMMAND_VERSION_1; i <= version; i++) {
+                Range include = Session2Command.VERSION_PLAYER_COMMANDS_MAP.get(i);
+                Range exclude = Session2Command.VERSION_PLAYER_PLAYLIST_COMMANDS_MAP.get(i);
+                for (int code = include.lower; code <= include.upper; code++) {
+                    if (code < exclude.lower && code > exclude.upper) {
+                        addCommand(code);
+                    }
+                }
+            }
+            return this;
+        }
+
+        @NonNull Builder addAllVolumeCommands(@Session2Command.CommandVersion int version) {
+            addCommands(version, Session2Command.VERSION_VOLUME_COMMANDS_MAP);
+            return this;
+        }
+
+        @NonNull Builder addAllSessionCommands(@Session2Command.CommandVersion int version) {
+            addCommands(version, Session2Command.VERSION_SESSION_COMMANDS_MAP);
+            return this;
+        }
+
+        @NonNull Builder addAllLibraryCommands(@Session2Command.CommandVersion int version) {
+            addCommands(version, Session2Command.VERSION_LIBRARY_COMMANDS_MAP);
+            return this;
+        }
+
+        private void addCommands(
+                @Session2Command.CommandVersion int version, ArrayMap<Integer, Range> map) {
+            for (int i = COMMAND_VERSION_1; i <= version; i++) {
+                Range range = map.get(i);
+                for (int code = range.lower; code <= range.upper; code++) {
+                    addCommand(code);
+                }
+            }
+        }
+
+        /**
+         * Builds {@link Session2CommandGroup}.
+         *
+         * @return a new {@link Session2CommandGroup}.
+         */
+        public @NonNull Session2CommandGroup build() {
+            return new Session2CommandGroup(mCommands);
+        }
+    }
+}
diff --git a/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
index 1dca10a..2fe740d 100644
--- a/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
@@ -76,7 +76,7 @@
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
                 android:background="@null"
-                systemui:intent="intent:#Intent;component=com.android.car.settings/.common.CarSettingActivity;launchFlags=0x14008000;end"
+                systemui:intent="intent:#Intent;component=com.android.car.settings/.common.CarSettingActivity;launchFlags=0x24000000;end"
             />
             <com.android.systemui.statusbar.policy.Clock
                 android:id="@+id/clock"
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
index c039fcc..959f9b2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
@@ -16,7 +16,6 @@
 package com.android.settingslib.media;
 
 import android.bluetooth.BluetoothClass;
-import android.bluetooth.BluetoothProfile;
 import android.content.Context;
 import android.util.Log;
 
@@ -36,12 +35,6 @@
         super(context, MediaDeviceType.TYPE_BLUETOOTH_DEVICE);
         mCachedDevice = device;
         initDeviceRecord();
-        buildConnectedState(device);
-    }
-
-    private void buildConnectedState(CachedBluetoothDevice device) {
-        mIsConnected = device.isActiveDevice(BluetoothProfile.A2DP)
-                || device.isActiveDevice(BluetoothProfile.HEARING_AID);
     }
 
     @Override
@@ -61,11 +54,6 @@
     }
 
     @Override
-    public void notifyConnectedChanged() {
-        buildConnectedState(mCachedDevice);
-    }
-
-    @Override
     public void connect() {
         //TODO(b/117129183): add callback to notify LocalMediaManager connection state.
         mIsConnected = mCachedDevice.setActive();
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java
index a9fc434..ab1cca0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java
@@ -18,7 +18,6 @@
 import android.app.Notification;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothProfile;
 import android.content.Context;
 import android.util.Log;
 
@@ -31,7 +30,6 @@
 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
 
 /**
@@ -41,8 +39,8 @@
 
     private static final String TAG = "BluetoothMediaManager";
 
-    private final DeviceProfileNotReadyObserverCallback mObserverCallback =
-            new DeviceProfileNotReadyObserverCallback();
+    private final DeviceAttributeChangeCallback mCachedDeviceCallback =
+            new DeviceAttributeChangeCallback();
 
     private LocalBluetoothManager mLocalBluetoothManager;
     private LocalBluetoothProfileManager mProfileManager;
@@ -50,10 +48,6 @@
     private MediaDevice mLastAddedDevice;
     private MediaDevice mLastRemovedDevice;
 
-    private boolean mIsA2dpProfileReady = false;
-    private boolean mIsHearingAidProfileReady = false;
-    private Collection<CachedBluetoothDevice> mCachedDevices;
-
     BluetoothMediaManager(Context context, LocalBluetoothManager localBluetoothManager,
             Notification notification) {
         super(context, notification);
@@ -68,18 +62,6 @@
         mLocalBluetoothManager.getEventManager().registerCallback(this);
         buildBluetoothDeviceList();
         dispatchDeviceListAdded();
-
-        // The profile may not ready when calling startScan().
-        // Device status are all disconnected since profiles are not ready to connected.
-        // In this case, we observe all devices in CachedDeviceManager.
-        // When one of these device is connected to profile, will call buildBluetoothDeviceList()
-        // again to find the connected devices.
-        if (!mIsA2dpProfileReady && !mIsHearingAidProfileReady) {
-            mCachedDevices = mLocalBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy();
-            for (CachedBluetoothDevice device : mCachedDevices) {
-                device.registerCallback(mObserverCallback);
-            }
-        }
     }
 
     private void buildBluetoothDeviceList() {
@@ -114,8 +96,6 @@
                 addMediaDevice(cachedDevice);
             }
         }
-
-        mIsA2dpProfileReady = a2dpProfile.isProfileReady();
     }
 
     private void addConnectedHearingAidDevices() {
@@ -150,14 +130,13 @@
                 addMediaDevice(cachedDevice);
             }
         }
-
-        mIsHearingAidProfileReady = hapProfile.isProfileReady();
     }
 
     private void addMediaDevice(CachedBluetoothDevice cachedDevice) {
         MediaDevice mediaDevice = findMediaDevice(MediaDeviceUtils.getId(cachedDevice));
         if (mediaDevice == null) {
             mediaDevice = new BluetoothMediaDevice(mContext, cachedDevice);
+            cachedDevice.registerCallback(mCachedDeviceCallback);
             mLastAddedDevice = mediaDevice;
             mMediaDevices.add(mediaDevice);
         }
@@ -166,6 +145,16 @@
     @Override
     public void stopScan() {
         mLocalBluetoothManager.getEventManager().unregisterCallback(this);
+        unregisterCachedDeviceCallback();
+    }
+
+    private void unregisterCachedDeviceCallback() {
+        for (MediaDevice device : mMediaDevices) {
+            if (device instanceof BluetoothMediaDevice) {
+                ((BluetoothMediaDevice) device).getCachedDevice()
+                        .unregisterCallback(mCachedDeviceCallback);
+            }
+        }
     }
 
     @Override
@@ -177,6 +166,8 @@
             final List<MediaDevice> removeDevicesList = new ArrayList<>();
             for (MediaDevice device : mMediaDevices) {
                 if (device instanceof BluetoothMediaDevice) {
+                    ((BluetoothMediaDevice) device).getCachedDevice()
+                            .unregisterCallback(mCachedDeviceCallback);
                     removeDevicesList.add(device);
                 }
             }
@@ -221,6 +212,7 @@
     private void removeMediaDevice(CachedBluetoothDevice cachedDevice) {
         final MediaDevice mediaDevice = findMediaDevice(MediaDeviceUtils.getId(cachedDevice));
         if (mediaDevice != null) {
+            cachedDevice.unregisterCallback(mCachedDeviceCallback);
             mLastRemovedDevice = mediaDevice;
             mMediaDevices.remove(mediaDevice);
         }
@@ -260,30 +252,10 @@
             dispatchDeviceRemoved(cachedDevice);
         }
     }
-
-    @Override
-    public void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile) {
-        Log.d(TAG, "onActiveDeviceChanged : device : "
-                + activeDevice + ", profile : " + bluetoothProfile);
-        if (BluetoothProfile.HEARING_AID == bluetoothProfile
-                || BluetoothProfile.A2DP == bluetoothProfile) {
-            final String id = activeDevice == null
-                    ? PhoneMediaDevice.ID : MediaDeviceUtils.getId(activeDevice);
-            dispatchActiveDeviceChanged(id);
-        }
-    }
-
-    class DeviceProfileNotReadyObserverCallback implements CachedBluetoothDevice.Callback {
-
+    class DeviceAttributeChangeCallback implements CachedBluetoothDevice.Callback {
         @Override
         public void onDeviceAttributesChanged() {
-            if (!mIsA2dpProfileReady && !mIsHearingAidProfileReady) {
-                for (CachedBluetoothDevice device : mCachedDevices) {
-                    device.unregisterCallback(mObserverCallback);
-                }
-                buildBluetoothDeviceList();
-                dispatchDeviceListAdded();
-            }
+            dispatchDeviceAttributesChanged();
         }
     }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
index a2b161f..21a81e0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
@@ -16,7 +16,6 @@
 package com.android.settingslib.media;
 
 import android.content.Context;
-import android.widget.Toast;
 
 import androidx.mediarouter.media.MediaRouter;
 
@@ -54,22 +53,15 @@
     }
 
     @Override
-    public void notifyConnectedChanged() {
-        //TODO(b/117129183): check mIsConnected state
-    }
-
-    @Override
     public void connect() {
         //TODO(b/117129183): use MediaController2 to transfer media
         mIsConnected = true;
         super.connect();
-        //mIsConnected = true;
-        Toast.makeText(mContext, "This is cast device !", Toast.LENGTH_SHORT).show();
     }
 
     @Override
     public void disconnect() {
         //TODO(b/117129183): disconnected last select device
-        //mIsConnected = false;
+        mIsConnected = false;
     }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index 154834e..c9479d4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -39,9 +39,6 @@
     private static final Comparator<MediaDevice> COMPARATOR = Comparator.naturalOrder();
     private static final String TAG = "LocalMediaManager";
 
-    public static final String NOTIFICATION_EXTRA = "notification_extra";
-    public static final String NOTIFICATION_PACKAGE_NAME = "notification_package_name";
-
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({MediaDeviceState.STATE_CONNECTED,
             MediaDeviceState.STATE_CONNECTING,
@@ -61,6 +58,7 @@
     private InfoMediaManager mInfoMediaManager;
 
     private LocalBluetoothManager mLocalBluetoothManager;
+    private MediaDevice mLastConnectedDevice;
     private MediaDevice mPhoneDevice;
 
     /**
@@ -100,43 +98,29 @@
      * @param connectDevice the MediaDevice
      */
     public void connectDevice(MediaDevice connectDevice) {
-        final MediaDevice currentDevice = getCurrentConnectedDevice();
-        final MediaDevice device =
-                MediaDeviceUtils.findMediaDevice(mMediaDevices, connectDevice.getId());
-        if (device != null && currentDevice != null
-                && device.getId().equals(currentDevice.getId())) {
+        if (connectDevice == mLastConnectedDevice) {
             return;
         }
 
-        //TODO(b/117129183): For demo, will remove check connectDevice is InfoMediaDevice.
-        if (currentDevice != null && !(connectDevice instanceof InfoMediaDevice)) {
-            currentDevice.disconnect();
+        if (mLastConnectedDevice != null) {
+            mLastConnectedDevice.disconnect();
         }
 
-        device.connect();
+        connectDevice.connect();
+        if (connectDevice.isConnected()) {
+            mLastConnectedDevice = connectDevice;
+        }
 
-        final int state = device.isConnected()
+        final int state = connectDevice.isConnected()
                 ? MediaDeviceState.STATE_CONNECTED
                 : MediaDeviceState.STATE_DISCONNECTED;
-        dispatchSelectedDeviceStateChanged(mMediaDevices, device, state);
+        dispatchSelectedDeviceStateChanged(connectDevice, state);
     }
 
-    private MediaDevice getCurrentConnectedDevice() {
-        for (MediaDevice device : mMediaDevices) {
-            if (device.isConnected()) {
-                return device;
-            }
-        }
-        Log.w(TAG, "getCurrentConnectedDevice() cannot find current connected device !");
-        return null;
-    }
-
-    void dispatchSelectedDeviceStateChanged(List<MediaDevice> mMediaDevices, MediaDevice device,
-            @MediaDeviceState int state) {
+    void dispatchSelectedDeviceStateChanged(MediaDevice device, @MediaDeviceState int state) {
         synchronized (mCallbacks) {
             for (DeviceCallback callback : mCallbacks) {
-                callback.onSelectedDeviceStateChanged(new ArrayList<>(mMediaDevices), device,
-                        state);
+                callback.onSelectedDeviceStateChanged(device, state);
             }
         }
     }
@@ -188,6 +172,23 @@
         mInfoMediaManager.stopScan();
     }
 
+    /**
+     * Find the MediaDevice through id.
+     *
+     * @param devices the list of MediaDevice
+     * @param id the unique id of MediaDevice
+     * @return MediaDevice
+     */
+    public MediaDevice getMediaDeviceById(List<MediaDevice> devices, String id) {
+        for (MediaDevice mediaDevice : devices) {
+            if (mediaDevice.getId().equals(id)) {
+                return mediaDevice;
+            }
+        }
+        Log.i(TAG, "getMediaDeviceById() can't found device");
+        return null;
+    }
+
     class MediaDeviceCallback implements MediaManager.MediaDeviceCallback {
         @Override
         public void onDeviceAdded(MediaDevice device) {
@@ -225,25 +226,6 @@
         public void onDeviceAttributesChanged() {
             dispatchDeviceListUpdate();
         }
-
-        @Override
-        public void onActiveDeviceChanged(String id) {
-            final MediaDevice currentDevice = getCurrentConnectedDevice();
-            final MediaDevice connectDevice = MediaDeviceUtils.findMediaDevice(mMediaDevices, id);
-
-            if (connectDevice != null && currentDevice != null
-                    && connectDevice.getId().equals(currentDevice.getId())) {
-                return;
-            }
-            if (currentDevice != null) {
-                currentDevice.notifyConnectedChanged();
-            }
-            if (connectDevice != null) {
-                connectDevice.notifyConnectedChanged();
-            }
-
-            dispatchDeviceListUpdate();
-        }
     }
 
 
@@ -267,7 +249,6 @@
          * {@link MediaDeviceState#STATE_CONNECTING},
          * {@link MediaDeviceState#STATE_DISCONNECTED}
          */
-        void onSelectedDeviceStateChanged(List<MediaDevice> devices, MediaDevice device,
-                @MediaDeviceState int state);
+        void onSelectedDeviceStateChanged(MediaDevice device, @MediaDeviceState int state);
     }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
index e4aeda6..33b621c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
@@ -17,7 +17,6 @@
 
 import android.content.Context;
 import android.text.TextUtils;
-import android.util.Log;
 
 import androidx.annotation.IntDef;
 
@@ -55,7 +54,6 @@
         ConnectionRecordManager.getInstance().fetchLastSelectedDevice(mContext);
         mConnectedRecord = ConnectionRecordManager.getInstance().fetchConnectionRecord(mContext,
                 getId());
-        Log.d("ttttt", getName() + " used: " + mConnectedRecord);
     }
 
     /**
@@ -88,11 +86,6 @@
     public abstract String getId();
 
     /**
-     * Notify MediaDevice to change their connected state.
-     */
-    public abstract void notifyConnectedChanged();
-
-    /**
      * Transfer MediaDevice for media
      */
     public void connect() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDeviceUtils.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDeviceUtils.java
index 8066eb0..bdddaf3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDeviceUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDeviceUtils.java
@@ -15,21 +15,14 @@
  */
 package com.android.settingslib.media;
 
-import android.util.Log;
-
 import androidx.mediarouter.media.MediaRouter;
 
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 
-import java.util.List;
-
 /**
  * MediaDeviceUtils provides utility function for MediaDevice
  */
 public class MediaDeviceUtils {
-
-    private static final String TAG = "MediaDeviceUtils";
-
     /**
      * Use CachedBluetoothDevice address to represent unique id
      *
@@ -49,21 +42,4 @@
     public static String getId(MediaRouter.RouteInfo route) {
         return route.getId();
     }
-
-    /**
-     * Find the MediaDevice through id.
-     *
-     * @param devices the list of MediaDevice
-     * @param id the unique id of MediaDevice
-     * @return MediaDevice
-     */
-    public static MediaDevice findMediaDevice(List<MediaDevice> devices, String id) {
-        for (MediaDevice mediaDevice : devices) {
-            if (mediaDevice.getId().equals(id)) {
-                return mediaDevice;
-            }
-        }
-        Log.e(TAG, "findMediaDevice() can't found device");
-        return null;
-    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java
index ee11070..72b6b09 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java
@@ -17,6 +17,7 @@
 
 import android.app.Notification;
 import android.content.Context;
+import android.util.Log;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -67,7 +68,13 @@
     public abstract void stopScan();
 
     protected MediaDevice findMediaDevice(String id) {
-        return MediaDeviceUtils.findMediaDevice(mMediaDevices, id);
+        for (MediaDevice mediaDevice : mMediaDevices) {
+            if (mediaDevice.getId().equals(id)) {
+                return mediaDevice;
+            }
+        }
+        Log.e(TAG, "findMediaDevice() can't found device");
+        return null;
     }
 
     protected void dispatchDeviceAdded(MediaDevice mediaDevice) {
@@ -89,7 +96,7 @@
     protected void dispatchDeviceListAdded() {
         synchronized (mCallbacks) {
             for (MediaDeviceCallback callback : mCallbacks) {
-                callback.onDeviceListAdded(new ArrayList<>(mMediaDevices));
+                callback.onDeviceListAdded(mMediaDevices);
             }
         }
     }
@@ -110,14 +117,6 @@
         }
     }
 
-    protected void dispatchActiveDeviceChanged(String id) {
-        synchronized (mCallbacks) {
-            for (MediaDeviceCallback callback : mCallbacks) {
-                callback.onActiveDeviceChanged(id);
-            }
-        }
-    }
-
     /**
      * Callback for notifying device is added, removed and attributes changed.
      */
@@ -154,12 +153,5 @@
          * Callback for notifying MediaDevice attributes is changed.
          */
         void onDeviceAttributesChanged();
-
-        /**
-         * Callback for notifying active MediaDevice is changed.
-         *
-         * @param id the id of MediaDevice
-         */
-        void onActiveDeviceChanged(String id);
     }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
index 59150f1..e0f3c2f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
@@ -15,7 +15,6 @@
  */
 package com.android.settingslib.media;
 
-import android.bluetooth.BluetoothDevice;
 import android.content.Context;
 import android.util.Log;
 
@@ -25,8 +24,6 @@
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
 
-import java.util.List;
-
 /**
  * PhoneMediaDevice extends MediaDevice to represents Phone device.
  */
@@ -45,29 +42,6 @@
         mLocalBluetoothManager = localBluetoothManager;
         mProfileManager = mLocalBluetoothManager.getProfileManager();
         initDeviceRecord();
-
-        mIsConnected = isPhoneActive();
-    }
-
-    private boolean isPhoneActive() {
-        boolean isActive = true;
-
-        final HearingAidProfile hapProfile = mProfileManager.getHearingAidProfile();
-        final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile();
-
-        if (a2dpProfile.getActiveDevice() == null) {
-            final List<BluetoothDevice> activeDevices = hapProfile.getActiveDevices();
-            for (BluetoothDevice btDevice : activeDevices) {
-                if (btDevice != null) {
-                    isActive = false;
-                    break;
-                }
-            }
-        } else {
-            isActive = false;
-        }
-
-        return isActive;
     }
 
     @Override
@@ -88,11 +62,6 @@
     }
 
     @Override
-    public void notifyConnectedChanged() {
-        mIsConnected = isPhoneActive();
-    }
-
-    @Override
     public void connect() {
         final HearingAidProfile hapProfile = mProfileManager.getHearingAidProfile();
         final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile();
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
index 089f773..871e248 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
@@ -101,6 +101,9 @@
     }
 
     public void handleBroadcast(Intent intent) {
+        if (mWifiManager == null) {
+            return;
+        }
         String action = intent.getAction();
         if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
             updateWifiState();
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 2f082b9..e47ca32 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -212,7 +212,7 @@
         mConnectivityManager = connectivityManager;
 
         // check if verbose logging developer option has been turned on or off
-        sVerboseLogging = (mWifiManager.getVerboseLoggingLevel() > 0);
+        sVerboseLogging = mWifiManager != null && (mWifiManager.getVerboseLoggingLevel() > 0);
 
         mFilter = filter;
 
@@ -283,7 +283,7 @@
             mScanner = new Scanner();
         }
 
-        if (mWifiManager.isWifiEnabled()) {
+        if (isWifiEnabled()) {
             mScanner.resume();
         }
     }
@@ -413,7 +413,7 @@
     }
 
     public boolean isWifiEnabled() {
-        return mWifiManager.isWifiEnabled();
+        return mWifiManager != null && mWifiManager.isWifiEnabled();
     }
 
     /**
@@ -638,7 +638,7 @@
     private void updateNetworkInfo(NetworkInfo networkInfo) {
 
         /* Sticky broadcasts can call this when wifi is disabled */
-        if (!mWifiManager.isWifiEnabled()) {
+        if (!isWifiEnabled()) {
             clearAccessPointsAndConditionallyUpdate();
             return;
         }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
index 1cbf277..9bbdd01 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
@@ -25,10 +25,8 @@
 
 import androidx.mediarouter.media.MediaRouter;
 
-import com.android.settingslib.bluetooth.A2dpProfile;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
-import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -61,8 +59,6 @@
             new BluetoothClass(BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO);
 
     @Mock
-    private A2dpProfile mA2dpProfile;
-    @Mock
     private BluetoothDevice mDevice1;
     @Mock
     private BluetoothDevice mDevice2;
@@ -77,8 +73,6 @@
     @Mock
     private LocalBluetoothManager mLocalBluetoothManager;
     @Mock
-    private LocalBluetoothProfileManager mProfileManager;
-    @Mock
     private MediaRouter.RouteInfo mRouteInfo1;
     @Mock
     private MediaRouter.RouteInfo mRouteInfo2;
@@ -115,9 +109,6 @@
         when(mRouteInfo1.getName()).thenReturn(DEVICE_NAME_1);
         when(mRouteInfo2.getName()).thenReturn(DEVICE_NAME_2);
         when(mRouteInfo3.getName()).thenReturn(DEVICE_NAME_3);
-        when(mLocalBluetoothManager.getProfileManager()).thenReturn(mProfileManager);
-        when(mProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
-        when(mA2dpProfile.getActiveDevice()).thenReturn(mDevice1);
 
         mBluetoothMediaDevice1 = new BluetoothMediaDevice(mContext, mCachedDevice1);
         mBluetoothMediaDevice2 = new BluetoothMediaDevice(mContext, mCachedDevice2);
diff --git a/packages/SystemUI/docs/dagger.md b/packages/SystemUI/docs/dagger.md
index 7751bb1..cca2d13 100644
--- a/packages/SystemUI/docs/dagger.md
+++ b/packages/SystemUI/docs/dagger.md
@@ -6,6 +6,8 @@
 
 Go read about Dagger 2.
 
+ - [User's guide](https://google.github.io/dagger/users-guide)
+
 TODO: Add some links.
 
 ## State of the world
diff --git a/packages/SystemUI/res/drawable/ic_home_button_outline.xml b/packages/SystemUI/res/drawable/ic_home_button_outline.xml
deleted file mode 100644
index 5bf345d..0000000
--- a/packages/SystemUI/res/drawable/ic_home_button_outline.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-  ~ Copyright (C) 2018 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="28dp"
-        android:height="10dp"
-        android:viewportWidth="28"
-        android:viewportHeight="10">
-    <path
-        android:pathData="M23,1H5C2.7909,1 1,2.7909 1,5C1,7.2091 2.7909,9 5,9H23C25.2091,9 27,7.2091 27,5C27,2.7909 25.2091,1 23,1ZM5,0C2.2386,0 0,2.2386 0,5C0,7.7614 2.2386,10 5,10H23C25.7614,10 28,7.7614 28,5C28,2.2386 25.7614,0 23,0H5Z"
-        android:fillColor="?attr/wallpaperTextColor"
-        android:fillType="evenOdd"/>
-</vector>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index 5766604..669e6ff 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -208,9 +208,11 @@
                     android.app.slice.SliceItem.FORMAT_IMAGE);
             if (icon != null) {
                 iconDrawable = icon.getIcon().loadDrawable(mContext);
-                final int width = (int) (iconDrawable.getIntrinsicWidth()
-                        / (float) iconDrawable.getIntrinsicHeight() * mIconSize);
-                iconDrawable.setBounds(0, 0, Math.max(width, 1), mIconSize);
+                if (iconDrawable != null) {
+                    final int width = (int) (iconDrawable.getIntrinsicWidth()
+                            / (float) iconDrawable.getIntrinsicHeight() * mIconSize);
+                    iconDrawable.setBounds(0, 0, Math.max(width, 1), mIconSize);
+                }
             }
             button.setCompoundDrawables(iconDrawable, null, null, null);
             button.setOnClickListener(this);
diff --git a/packages/SystemUI/src/com/android/systemui/DependencyBinder.java b/packages/SystemUI/src/com/android/systemui/DependencyBinder.java
index 23ef030..b93a5fd 100644
--- a/packages/SystemUI/src/com/android/systemui/DependencyBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/DependencyBinder.java
@@ -22,6 +22,8 @@
 import com.android.systemui.plugins.VolumeDialogController;
 import com.android.systemui.power.PowerNotificationWarnings;
 import com.android.systemui.power.PowerUI;
+import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl;
 import com.android.systemui.statusbar.phone.ManagedProfileController;
@@ -224,4 +226,9 @@
      */
     @Binds
     public abstract PowerUI.WarningsUI provideWarningsUi(PowerNotificationWarnings controllerImpl);
+
+    /**
+     */
+    @Binds
+    public abstract QSHost provideQsHost(QSTileHost controllerImpl);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 8bac7c5..297c146 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -34,7 +34,6 @@
 import com.android.systemui.keyguard.DismissCallbackRegistry;
 import com.android.systemui.power.EnhancedEstimates;
 import com.android.systemui.power.EnhancedEstimatesImpl;
-import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.statusbar.KeyguardIndicationController;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -52,10 +51,10 @@
 import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.phone.ScrimState;
 import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.util.InjectionInflationController;
+import com.android.systemui.util.leak.GarbageMonitor;
 import com.android.systemui.volume.VolumeDialogComponent;
 
 import java.util.function.Consumer;
@@ -144,11 +143,6 @@
         return new KeyguardIndicationController(context, indicationArea, lockIcon);
     }
 
-    public QSTileHost createQSTileHost(Context context, StatusBar statusBar,
-            StatusBarIconController iconController) {
-        return new QSTileHost(context, statusBar, iconController);
-    }
-
     public VolumeDialogComponent createVolumeDialogComponent(SystemUI systemUi, Context context) {
         return new VolumeDialogComponent(systemUi, context);
     }
@@ -237,5 +231,8 @@
          * ViewCreator generates all Views that need injection.
          */
         InjectionInflationController.ViewCreator createViewCreator();
+
+        @Singleton
+        GarbageMonitor createGarbageMonitor();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index c8595eb..881aa18 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -33,7 +33,6 @@
 import android.widget.FrameLayout;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.phone.StatusBarWindowController;
@@ -122,12 +121,12 @@
     }
 
     @Inject
-    public BubbleController(Context context) {
+    public BubbleController(Context context, StatusBarWindowController statusBarWindowController) {
         mContext = context;
         WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
         mDisplaySize = new Point();
         wm.getDefaultDisplay().getSize(mDisplaySize);
-        mStatusBarWindowController = Dependency.get(StatusBarWindowController.class);
+        mStatusBarWindowController = statusBarWindowController;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
index ab77e55..50003e3 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
@@ -35,7 +35,7 @@
     private static final int SIZE = Build.IS_DEBUGGABLE ? 400 : 50;
     static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
 
-    private static final int REASONS = 8;
+    private static final int REASONS = 9;
 
     public static final int PULSE_REASON_NONE = -1;
     public static final int PULSE_REASON_INTENT = 0;
@@ -46,6 +46,7 @@
     public static final int PULSE_REASON_SENSOR_LONG_PRESS = 5;
     public static final int PULSE_REASON_DOCKING = 6;
     public static final int REASON_SENSOR_WAKE_UP = 7;
+    public static final int PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN = 8;
 
     private static boolean sRegisterKeyguardCallback = true;
 
@@ -178,15 +179,6 @@
     }
 
     /**
-     * Appends lock screen wake up event to the logs.
-     * @param wake if we're waking up or sleeping.
-     */
-    public static void traceLockScreenWakeUp(boolean wake) {
-        if (!ENABLED) return;
-        log("wakeLockScreen " + wake);
-    }
-
-    /**
      * Appends wake-display event to the logs.
      * @param wake if we're waking up or sleeping.
      */
@@ -213,6 +205,7 @@
             case PULSE_REASON_SENSOR_DOUBLE_TAP: return "doubletap";
             case PULSE_REASON_SENSOR_LONG_PRESS: return "longpress";
             case PULSE_REASON_DOCKING: return "docking";
+            case PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN: return "wakelockscreen";
             case REASON_SENSOR_WAKE_UP: return "wakeup";
             default: throw new IllegalArgumentException("bad reason: " + pulseReason);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index c2676d0..35b64ed 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -17,6 +17,7 @@
 package com.android.systemui.doze;
 
 import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_DISPLAY;
+import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_LOCK_SCREEN;
 
 import android.annotation.AnyThread;
 import android.app.ActivityManager;
@@ -115,10 +116,17 @@
                 new PluginSensor(
                         new SensorManagerPlugin.Sensor(TYPE_WAKE_DISPLAY),
                         Settings.Secure.DOZE_WAKE_SCREEN_GESTURE,
-                        true /* configured */,
+                        mConfig.wakeScreenGestureAvailable(),
                         DozeLog.REASON_SENSOR_WAKE_UP,
                         false /* reports touch coordinates */,
                         false /* touchscreen */),
+                new PluginSensor(
+                        new SensorManagerPlugin.Sensor(TYPE_WAKE_LOCK_SCREEN),
+                        Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE,
+                        mConfig.wakeScreenGestureAvailable(),
+                        DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN,
+                        false /* reports touch coordinates */,
+                        false /* touchscreen */),
         };
 
         mProxSensor = new ProxSensor(policy);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 1e228f2..6a9b689 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -135,11 +135,12 @@
         boolean isPickup = pulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP;
         boolean isLongPress = pulseReason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS;
         boolean isWakeDisplay = pulseReason == DozeLog.REASON_SENSOR_WAKE_UP;
+        boolean isWakeLockScreen = pulseReason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN;
         boolean wakeEvent = rawValues != null && rawValues.length > 0 && rawValues[0] != 0;
 
         if (isWakeDisplay) {
             onWakeScreen(wakeEvent);
-        } else if (isLongPress) {
+        } else if (isLongPress || isWakeLockScreen) {
             requestPulse(pulseReason, sensorPerformedProxCheck);
         } else {
             proximityCheckThenCall((result) -> {
@@ -156,7 +157,6 @@
                     mDozeHost.extendPulse();
                 }
             }, sensorPerformedProxCheck, pulseReason);
-            return;
         }
 
         if (isPickup) {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/LockScreenWakeUpController.java b/packages/SystemUI/src/com/android/systemui/doze/LockScreenWakeUpController.java
deleted file mode 100644
index 70143e2..0000000
--- a/packages/SystemUI/src/com/android/systemui/doze/LockScreenWakeUpController.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * 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.doze;
-
-import android.content.Context;
-import android.os.Handler;
-import android.os.PowerManager;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.hardware.AmbientDisplayConfiguration;
-import com.android.systemui.Dependency;
-import com.android.systemui.plugins.SensorManagerPlugin;
-import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.StatusBarStateController;
-import com.android.systemui.util.AsyncSensorManager;
-
-/**
- * Controller responsible for waking up or making the device sleep based on ambient sensors.
- */
-public class LockScreenWakeUpController implements StatusBarStateController.StateListener,
-        SensorManagerPlugin.SensorEventListener {
-
-    private static final String TAG = LockScreenWakeUpController.class.getSimpleName();
-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
-    private final AsyncSensorManager mAsyncSensorManager;
-    private final SensorManagerPlugin.Sensor mSensor;
-    private final AmbientDisplayConfiguration mAmbientConfiguration;
-    private final PowerManager mPowerManager;
-    private final DozeHost mDozeHost;
-    private final Handler mHandler;
-    private boolean mRegistered;
-    private boolean mDozing;
-
-    public LockScreenWakeUpController(Context context, DozeHost dozeHost) {
-        this(Dependency.get(AsyncSensorManager.class),
-                new SensorManagerPlugin.Sensor(SensorManagerPlugin.Sensor.TYPE_WAKE_LOCK_SCREEN),
-                new AmbientDisplayConfiguration(context),
-                context.getSystemService(PowerManager.class),
-                dozeHost, Dependency.get(StatusBarStateController.class), new Handler());
-    }
-
-    @VisibleForTesting
-    public LockScreenWakeUpController(AsyncSensorManager asyncSensorManager,
-            SensorManagerPlugin.Sensor sensor, AmbientDisplayConfiguration ambientConfiguration,
-            PowerManager powerManager, DozeHost dozeHost,
-            StatusBarStateController statusBarStateController, Handler handler) {
-        mAsyncSensorManager = asyncSensorManager;
-        mSensor = sensor;
-        mAmbientConfiguration = ambientConfiguration;
-        mPowerManager = powerManager;
-        mDozeHost = dozeHost;
-        mHandler = handler;
-        statusBarStateController.addCallback(this);
-    }
-
-    @Override
-    public void onStateChanged(int newState) {
-        boolean isLockScreen = newState == StatusBarState.KEYGUARD
-                || newState == StatusBarState.SHADE_LOCKED;
-
-        if (!mAmbientConfiguration.wakeLockScreenGestureEnabled(UserHandle.USER_CURRENT)) {
-            if (mRegistered) {
-                mAsyncSensorManager.unregisterPluginListener(mSensor, this);
-                mRegistered = false;
-            }
-            return;
-        }
-
-        if (isLockScreen && !mRegistered) {
-            mAsyncSensorManager.registerPluginListener(mSensor, this);
-            mRegistered = true;
-        } else if (!isLockScreen && mRegistered) {
-            mAsyncSensorManager.unregisterPluginListener(mSensor, this);
-            mRegistered = false;
-        }
-    }
-
-    @Override
-    public void onDozingChanged(boolean isDozing) {
-        mDozing = isDozing;
-    }
-
-    @Override
-    public void onSensorChanged(SensorManagerPlugin.SensorEvent event) {
-        mHandler.post(()-> {
-            float[] rawValues = event.getValues();
-            boolean wakeEvent = rawValues != null && rawValues.length > 0 && rawValues[0] != 0;
-
-            DozeLog.traceLockScreenWakeUp(wakeEvent);
-            if (wakeEvent && mDozing) {
-                if (DEBUG) Log.d(TAG, "Wake up.");
-                mPowerManager.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:NODOZE");
-            } else if (!wakeEvent && !mDozing) {
-                if (DEBUG) Log.d(TAG, "Nap time.");
-                mPowerManager.goToSleep(SystemClock.uptimeMillis(),
-                        PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON, 0);
-            } else if (DEBUG) {
-                Log.d(TAG, "Skip sensor event. Wake? " + wakeEvent + " dozing: " + mDozing);
-            }
-        });
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index aba9bb8..e63f88a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -18,6 +18,8 @@
 
 import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS;
 
+import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
+
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.UserInfo;
@@ -48,7 +50,6 @@
 import com.android.settingslib.Utils;
 import com.android.settingslib.drawable.UserIconDrawable;
 import com.android.settingslib.graph.SignalDrawable;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.R.dimen;
 import com.android.systemui.plugins.ActivityStarter;
@@ -63,11 +64,16 @@
 import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener;
 import com.android.systemui.tuner.TunerService;
 
+import javax.inject.Inject;
+import javax.inject.Named;
+
 public class QSFooterImpl extends FrameLayout implements QSFooter,
         OnClickListener, OnUserInfoChangedListener, EmergencyListener, SignalCallback {
 
-    private ActivityStarter mActivityStarter;
-    private UserInfoController mUserInfoController;
+    private final ActivityStarter mActivityStarter;
+    private final UserInfoController mUserInfoController;
+    private final NetworkController mNetworkController;
+    private final DeviceProvisionedController mDeviceProvisionedController;
     private SettingsButton mSettingsButton;
     protected View mSettingsContainer;
     private PageIndicator mPageIndicator;
@@ -100,9 +106,17 @@
     private final CellSignalState mInfo = new CellSignalState();
     private OnClickListener mExpandClickListener;
 
-    public QSFooterImpl(Context context, AttributeSet attrs) {
+    @Inject
+    public QSFooterImpl(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
+            ActivityStarter activityStarter, UserInfoController userInfoController,
+            NetworkController networkController,
+            DeviceProvisionedController deviceProvisionedController) {
         super(context, attrs);
         mColorForeground = Utils.getColorAttrDefaultColor(context, android.R.attr.colorForeground);
+        mActivityStarter = activityStarter;
+        mUserInfoController = userInfoController;
+        mNetworkController = networkController;
+        mDeviceProvisionedController = deviceProvisionedController;
     }
 
     @Override
@@ -111,7 +125,7 @@
         mDivider = findViewById(R.id.qs_footer_divider);
         mEdit = findViewById(android.R.id.edit);
         mEdit.setOnClickListener(view ->
-                Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() ->
+                mActivityStarter.postQSRunnableDismissingKeyguard(() ->
                         mQsPanel.showEdit(view)));
 
         mPageIndicator = findViewById(R.id.footer_page_indicator);
@@ -137,8 +151,6 @@
 
         updateResources();
 
-        mUserInfoController = Dependency.get(UserInfoController.class);
-        mActivityStarter = Dependency.get(ActivityStarter.class);
         addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight,
                 oldBottom) -> updateAnimator(right - left));
         setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
@@ -316,14 +328,14 @@
     private void updateListeners() {
         if (mListening) {
             mUserInfoController.addCallback(this);
-            if (Dependency.get(NetworkController.class).hasVoiceCallingFeature()) {
-                Dependency.get(NetworkController.class).addEmergencyListener(this);
-                Dependency.get(NetworkController.class).addCallback(this);
+            if (mNetworkController.hasVoiceCallingFeature()) {
+                mNetworkController.addEmergencyListener(this);
+                mNetworkController.addCallback(this);
             }
         } else {
             mUserInfoController.removeCallback(this);
-            Dependency.get(NetworkController.class).removeEmergencyListener(this);
-            Dependency.get(NetworkController.class).removeCallback(this);
+            mNetworkController.removeEmergencyListener(this);
+            mNetworkController.removeCallback(this);
         }
     }
 
@@ -344,7 +356,7 @@
         }
 
         if (v == mSettingsButton) {
-            if (!Dependency.get(DeviceProvisionedController.class).isCurrentUserSetup()) {
+            if (!mDeviceProvisionedController.isCurrentUserSetup()) {
                 // If user isn't setup just unlock the device and dump them back at SUW.
                 mActivityStarter.postQSRunnableDismissingKeyguard(() -> { });
                 return;
@@ -353,7 +365,7 @@
                     mExpanded ? MetricsProto.MetricsEvent.ACTION_QS_EXPANDED_SETTINGS_LAUNCH
                             : MetricsProto.MetricsEvent.ACTION_QS_COLLAPSED_SETTINGS_LAUNCH);
             if (mSettingsButton.isTunerClick()) {
-                Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() -> {
+                mActivityStarter.postQSRunnableDismissingKeyguard(() -> {
                     if (TunerService.isTunerEnabled(mContext)) {
                         TunerService.showResetRequest(mContext, () -> {
                             // Relaunch settings so that the tuner disappears.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index bedba9a..34d30fe 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -79,15 +79,18 @@
 
     private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
     private final InjectionInflationController mInjectionInflater;
+    private final QSTileHost mHost;
 
     @Inject
     public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler,
             InjectionInflationController injectionInflater,
-            Context context) {
+            Context context,
+            QSTileHost qsTileHost) {
         mRemoteInputQuickSettingsDisabler = remoteInputQsDisabler;
         mInjectionInflater = injectionInflater;
         SysUiServiceProvider.getComponent(context, CommandQueue.class)
                 .observe(getLifecycle(), this);
+        mHost = qsTileHost;
     }
 
     @Override
@@ -122,6 +125,7 @@
                 mQSPanel.getTileLayout().restoreInstanceState(savedInstanceState);
             }
         }
+        setHost(mHost);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index ca8e824..3a6b785 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -20,6 +20,7 @@
 import android.content.Intent;
 import android.content.res.Resources;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
@@ -30,6 +31,7 @@
 
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
+import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.plugins.qs.QSFactory;
 import com.android.systemui.plugins.qs.QSTile;
@@ -52,7 +54,12 @@
 import java.util.List;
 import java.util.function.Predicate;
 
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
 /** Platform implementation of the quick settings tile host **/
+@Singleton
 public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory> {
     private static final String TAG = "QSTileHost";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -60,29 +67,44 @@
     public static final String TILES_SETTING = Secure.QS_TILES;
 
     private final Context mContext;
-    private final StatusBar mStatusBar;
     private final LinkedHashMap<String, QSTile> mTiles = new LinkedHashMap<>();
     protected final ArrayList<String> mTileSpecs = new ArrayList<>();
     private final TileServices mServices;
+    private final TunerService mTunerService;
+    private final PluginManager mPluginManager;
 
     private final List<Callback> mCallbacks = new ArrayList<>();
     private final AutoTileManager mAutoTiles;
     private final StatusBarIconController mIconController;
     private final ArrayList<QSFactory> mQsFactories = new ArrayList<>();
     private int mCurrentUser;
+    private StatusBar mStatusBar;
 
-    public QSTileHost(Context context, StatusBar statusBar,
-            StatusBarIconController iconController) {
+    @Inject
+    public QSTileHost(Context context,
+            StatusBarIconController iconController,
+            QSFactoryImpl defaultFactory,
+            @Named(Dependency.MAIN_HANDLER_NAME) Handler mainHandler,
+            @Named(Dependency.BG_LOOPER_NAME) Looper bgLooper,
+            PluginManager pluginManager,
+            TunerService tunerService) {
         mIconController = iconController;
         mContext = context;
-        mStatusBar = statusBar;
+        mTunerService = tunerService;
+        mPluginManager = pluginManager;
 
-        mServices = new TileServices(this, Dependency.get(Dependency.BG_LOOPER));
+        mServices = new TileServices(this, bgLooper);
 
-        mQsFactories.add(new QSFactoryImpl(this));
-        Dependency.get(PluginManager.class).addPluginListener(this, QSFactory.class, true);
+        defaultFactory.setHost(this);
+        mQsFactories.add(defaultFactory);
+        pluginManager.addPluginListener(this, QSFactory.class, true);
 
-        Dependency.get(TunerService.class).addTunable(this, TILES_SETTING);
+        mainHandler.post(() -> {
+            // This is technically a hack to avoid circular dependency of
+            // QSTileHost -> XXXTile -> QSTileHost. Posting ensures creation
+            // finishes before creating any tiles.
+            tunerService.addTunable(this, TILES_SETTING);
+        });
         // AutoTileManager can modify mTiles so make sure mTiles has already been initialized.
         mAutoTiles = new AutoTileManager(context, this);
     }
@@ -94,16 +116,16 @@
     public void destroy() {
         mTiles.values().forEach(tile -> tile.destroy());
         mAutoTiles.destroy();
-        Dependency.get(TunerService.class).removeTunable(this);
+        mTunerService.removeTunable(this);
         mServices.destroy();
-        Dependency.get(PluginManager.class).removePluginListener(this);
+        mPluginManager.removePluginListener(this);
     }
 
     @Override
     public void onPluginConnected(QSFactory plugin, Context pluginContext) {
         // Give plugins priority over creation so they can override if they wish.
         mQsFactories.add(0, plugin);
-        String value = Dependency.get(TunerService.class).getValue(TILES_SETTING);
+        String value = mTunerService.getValue(TILES_SETTING);
         // Force remove and recreate of all tiles.
         onTuningChanged(TILES_SETTING, "");
         onTuningChanged(TILES_SETTING, value);
@@ -113,7 +135,7 @@
     public void onPluginDisconnected(QSFactory plugin) {
         mQsFactories.remove(plugin);
         // Force remove and recreate of all tiles.
-        String value = Dependency.get(TunerService.class).getValue(TILES_SETTING);
+        String value = mTunerService.getValue(TILES_SETTING);
         onTuningChanged(TILES_SETTING, "");
         onTuningChanged(TILES_SETTING, value);
     }
@@ -140,16 +162,25 @@
 
     @Override
     public void collapsePanels() {
+        if (mStatusBar == null) {
+            mStatusBar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
+        }
         mStatusBar.postAnimateCollapsePanels();
     }
 
     @Override
     public void forceCollapsePanels() {
+        if (mStatusBar == null) {
+            mStatusBar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
+        }
         mStatusBar.postAnimateForceCollapsePanels();
     }
 
     @Override
     public void openPanels() {
+        if (mStatusBar == null) {
+            mStatusBar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
+        }
         mStatusBar.postAnimateOpenPanels();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index fd2c4e3..d26cee9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -47,12 +47,79 @@
 import com.android.systemui.qs.tiles.WorkModeTile;
 import com.android.systemui.util.leak.GarbageMonitor;
 
+import javax.inject.Inject;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+
+@Singleton
 public class QSFactoryImpl implements QSFactory {
 
     private static final String TAG = "QSFactory";
-    private final QSTileHost mHost;
 
-    public QSFactoryImpl(QSTileHost host) {
+    private final Provider<WifiTile> mWifiTileProvider;
+    private final Provider<BluetoothTile> mBluetoothTileProvider;
+    private final Provider<CellularTile> mCellularTileProvider;
+    private final Provider<DndTile> mDndTileProvider;
+    private final Provider<ColorInversionTile> mColorInversionTileProvider;
+    private final Provider<AirplaneModeTile> mAirplaneModeTileProvider;
+    private final Provider<WorkModeTile> mWorkModeTileProvider;
+    private final Provider<RotationLockTile> mRotationLockTileProvider;
+    private final Provider<FlashlightTile> mFlashlightTileProvider;
+    private final Provider<LocationTile> mLocationTileProvider;
+    private final Provider<CastTile> mCastTileProvider;
+    private final Provider<HotspotTile> mHotspotTileProvider;
+    private final Provider<UserTile> mUserTileProvider;
+    private final Provider<BatterySaverTile> mBatterySaverTileProvider;
+    private final Provider<DataSaverTile> mDataSaverTileProvider;
+    private final Provider<NightDisplayTile> mNightDisplayTileProvider;
+    private final Provider<NfcTile> mNfcTileProvider;
+    private final Provider<SensorPrivacyTile> mSensorPrivacyTileProvider;
+    private final Provider<GarbageMonitor.MemoryTile> mMemoryTileProvider;
+
+    private QSTileHost mHost;
+
+    @Inject
+    public QSFactoryImpl(Provider<WifiTile> wifiTileProvider,
+            Provider<BluetoothTile> bluetoothTileProvider,
+            Provider<CellularTile> cellularTileProvider,
+            Provider<DndTile> dndTileProvider,
+            Provider<ColorInversionTile> colorInversionTileProvider,
+            Provider<AirplaneModeTile> airplaneModeTileProvider,
+            Provider<WorkModeTile> workModeTileProvider,
+            Provider<RotationLockTile> rotationLockTileProvider,
+            Provider<FlashlightTile> flashlightTileProvider,
+            Provider<LocationTile> locationTileProvider,
+            Provider<CastTile> castTileProvider,
+            Provider<HotspotTile> hotspotTileProvider,
+            Provider<UserTile> userTileProvider,
+            Provider<BatterySaverTile> batterySaverTileProvider,
+            Provider<DataSaverTile> dataSaverTileProvider,
+            Provider<NightDisplayTile> nightDisplayTileProvider,
+            Provider<NfcTile> nfcTileProvider,
+            Provider<SensorPrivacyTile> sensorPrivacyTileProvider,
+            Provider<GarbageMonitor.MemoryTile> memoryTileProvider) {
+        mWifiTileProvider = wifiTileProvider;
+        mBluetoothTileProvider = bluetoothTileProvider;
+        mCellularTileProvider = cellularTileProvider;
+        mDndTileProvider = dndTileProvider;
+        mColorInversionTileProvider = colorInversionTileProvider;
+        mAirplaneModeTileProvider = airplaneModeTileProvider;
+        mWorkModeTileProvider = workModeTileProvider;
+        mRotationLockTileProvider = rotationLockTileProvider;
+        mFlashlightTileProvider = flashlightTileProvider;
+        mLocationTileProvider = locationTileProvider;
+        mCastTileProvider = castTileProvider;
+        mHotspotTileProvider = hotspotTileProvider;
+        mUserTileProvider = userTileProvider;
+        mBatterySaverTileProvider = batterySaverTileProvider;
+        mDataSaverTileProvider = dataSaverTileProvider;
+        mNightDisplayTileProvider = nightDisplayTileProvider;
+        mNfcTileProvider = nfcTileProvider;
+        mSensorPrivacyTileProvider = sensorPrivacyTileProvider;
+        mMemoryTileProvider = memoryTileProvider;
+    }
+
+    public void setHost(QSTileHost host) {
         mHost = host;
     }
 
@@ -68,41 +135,41 @@
         // Stock tiles.
         switch (tileSpec) {
             case "wifi":
-                return new WifiTile(mHost);
+                return mWifiTileProvider.get();
             case "bt":
-                return new BluetoothTile(mHost);
+                return mBluetoothTileProvider.get();
             case "cell":
-                return new CellularTile(mHost);
+                return mCellularTileProvider.get();
             case "dnd":
-                return new DndTile(mHost);
+                return mDndTileProvider.get();
             case "inversion":
-                return new ColorInversionTile(mHost);
+                return mColorInversionTileProvider.get();
             case "airplane":
-                return new AirplaneModeTile(mHost);
+                return mAirplaneModeTileProvider.get();
             case "work":
-                return new WorkModeTile(mHost);
+                return mWorkModeTileProvider.get();
             case "rotation":
-                return new RotationLockTile(mHost);
+                return mRotationLockTileProvider.get();
             case "flashlight":
-                return new FlashlightTile(mHost);
+                return mFlashlightTileProvider.get();
             case "location":
-                return new LocationTile(mHost);
+                return mLocationTileProvider.get();
             case "cast":
-                return new CastTile(mHost);
+                return mCastTileProvider.get();
             case "hotspot":
-                return new HotspotTile(mHost);
+                return mHotspotTileProvider.get();
             case "user":
-                return new UserTile(mHost);
+                return mUserTileProvider.get();
             case "battery":
-                return new BatterySaverTile(mHost);
+                return mBatterySaverTileProvider.get();
             case "saver":
-                return new DataSaverTile(mHost);
+                return mDataSaverTileProvider.get();
             case "night":
-                return new NightDisplayTile(mHost);
+                return mNightDisplayTileProvider.get();
             case "nfc":
-                return new NfcTile(mHost);
+                return mNfcTileProvider.get();
             case "sensorprivacy":
-                return new SensorPrivacyTile(mHost);
+                return mSensorPrivacyTileProvider.get();
         }
 
         // Intent tiles.
@@ -112,7 +179,7 @@
         // Debug tiles.
         if (Build.IS_DEBUGGABLE) {
             if (tileSpec.equals(GarbageMonitor.MemoryTile.TILE_SPEC)) {
-                return new GarbageMonitor.MemoryTile(mHost);
+                return mMemoryTileProvider.get();
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index cc27135..e1a4378 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -14,6 +14,9 @@
 
 package com.android.systemui.qs.tileimpl;
 
+import static androidx.lifecycle.Lifecycle.State.DESTROYED;
+import static androidx.lifecycle.Lifecycle.State.RESUMED;
+
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_CLICK;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_LONG_PRESS;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_SECONDARY_CLICK;
@@ -38,6 +41,11 @@
 import android.util.Log;
 import android.util.SparseArray;
 
+import androidx.annotation.NonNull;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.LifecycleRegistry;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.settingslib.RestrictedLockUtils;
@@ -66,7 +74,7 @@
  *
  * @param <TState> see above
  */
-public abstract class QSTileImpl<TState extends State> implements QSTile {
+public abstract class QSTileImpl<TState extends State> implements QSTile, LifecycleOwner {
     protected final String TAG = "Tile." + getClass().getSimpleName();
     protected static final boolean DEBUG = Log.isLoggable("Tile", Log.DEBUG);
 
@@ -94,6 +102,8 @@
     private boolean mShowingDetail;
     private int mIsFullQs;
 
+    private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this);
+
     public abstract TState newTileState();
 
     abstract protected void handleClick();
@@ -113,6 +123,12 @@
         mContext = host.getContext();
     }
 
+    @NonNull
+    @Override
+    public Lifecycle getLifecycle() {
+        return mLifecycle;
+    }
+
     /**
      * Adds or removes a listening client for the tile. If the tile has one or more
      * listening client it will go into the listening state.
@@ -341,12 +357,14 @@
         if (listening) {
             if (mListeners.add(listener) && mListeners.size() == 1) {
                 if (DEBUG) Log.d(TAG, "handleSetListening true");
+                mLifecycle.markState(RESUMED);
                 handleSetListening(listening);
                 refreshState(); // Ensure we get at least one refresh after listening.
             }
         } else {
             if (mListeners.remove(listener) && mListeners.size() == 0) {
                 if (DEBUG) Log.d(TAG, "handleSetListening false");
+                mLifecycle.markState(DESTROYED);
                 handleSetListening(listening);
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index c8c2158..387de71 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -32,7 +32,6 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.TelephonyProperties;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
@@ -40,16 +39,21 @@
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 
+import javax.inject.Inject;
+
 /** Quick settings tile: Airplane mode **/
 public class AirplaneModeTile extends QSTileImpl<BooleanState> {
     private final Icon mIcon =
             ResourceIcon.get(R.drawable.ic_signal_airplane);
     private final GlobalSetting mSetting;
+    private final ActivityStarter mActivityStarter;
 
     private boolean mListening;
 
-    public AirplaneModeTile(QSHost host) {
+    @Inject
+    public AirplaneModeTile(QSHost host, ActivityStarter activityStarter) {
         super(host);
+        mActivityStarter = activityStarter;
 
         mSetting = new GlobalSetting(mContext, mHandler, Global.AIRPLANE_MODE_ON) {
             @Override
@@ -70,7 +74,7 @@
         MetricsLogger.action(mContext, getMetricsCategory(), !airplaneModeEnabled);
         if (!airplaneModeEnabled && Boolean.parseBoolean(
                 SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {
-            Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(
+            mActivityStarter.postStartActivityDismissingKeyguard(
                     new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS), 0);
             return;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
index da2828e..7f76900 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
@@ -23,13 +23,14 @@
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settingslib.graph.BatteryMeterDrawableBase;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.policy.BatteryController;
 
+import javax.inject.Inject;
+
 public class BatterySaverTile extends QSTileImpl<BooleanState> implements
         BatteryController.BatteryStateChangeCallback {
 
@@ -40,9 +41,11 @@
     private boolean mCharging;
     private boolean mPluggedIn;
 
-    public BatterySaverTile(QSHost host) {
+    @Inject
+    public BatterySaverTile(QSHost host, BatteryController batteryController) {
         super(host);
-        mBatteryController = Dependency.get(BatteryController.class);
+        mBatteryController = batteryController;
+        mBatteryController.observe(getLifecycle(), this);
     }
 
     @Override
@@ -57,11 +60,6 @@
 
     @Override
     public void handleSetListening(boolean listening) {
-        if (listening) {
-            mBatteryController.addCallback(this);
-        } else {
-            mBatteryController.removeCallback(this);
-        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 3ab1c21..5b85498 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -36,7 +36,6 @@
 import com.android.settingslib.Utils;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.graph.BluetoothDeviceLayerDrawable;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.DetailAdapter;
@@ -51,6 +50,8 @@
 import java.util.Collection;
 import java.util.List;
 
+import javax.inject.Inject;
+
 /** Quick settings tile: Bluetooth **/
 public class BluetoothTile extends QSTileImpl<BooleanState> {
     private static final Intent BLUETOOTH_SETTINGS = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
@@ -59,11 +60,15 @@
     private final BluetoothDetailAdapter mDetailAdapter;
     private final ActivityStarter mActivityStarter;
 
-    public BluetoothTile(QSHost host) {
+    @Inject
+    public BluetoothTile(QSHost host,
+            BluetoothController bluetoothController,
+            ActivityStarter activityStarter) {
         super(host);
-        mController = Dependency.get(BluetoothController.class);
-        mActivityStarter = Dependency.get(ActivityStarter.class);
+        mController = bluetoothController;
+        mActivityStarter = activityStarter;
         mDetailAdapter = (BluetoothDetailAdapter) createDetailAdapter();
+        mController.observe(getLifecycle(), mCallback);
     }
 
     @Override
@@ -78,11 +83,6 @@
 
     @Override
     public void handleSetListening(boolean listening) {
-        if (listening) {
-            mController.addCallback(mCallback);
-        } else {
-            mController.removeCallback(mCallback);
-        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 921db69..f05ac4c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -33,7 +33,6 @@
 import com.android.internal.app.MediaRouteDialogPresenter;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.DetailAdapter;
@@ -51,6 +50,8 @@
 import java.util.LinkedHashMap;
 import java.util.Set;
 
+import javax.inject.Inject;
+
 /** Quick settings tile: Cast **/
 public class CastTile extends QSTileImpl<BooleanState> {
     private static final Intent CAST_SETTINGS =
@@ -65,13 +66,18 @@
     private Dialog mDialog;
     private boolean mWifiConnected;
 
-    public CastTile(QSHost host) {
+    @Inject
+    public CastTile(QSHost host, CastController castController, KeyguardMonitor keyguardMonitor,
+            NetworkController networkController, ActivityStarter activityStarter) {
         super(host);
-        mController = Dependency.get(CastController.class);
+        mController = castController;
         mDetailAdapter = new CastDetailAdapter();
-        mKeyguard = Dependency.get(KeyguardMonitor.class);
-        mNetworkController = Dependency.get(NetworkController.class);
-        mActivityStarter = Dependency.get(ActivityStarter.class);
+        mKeyguard = keyguardMonitor;
+        mNetworkController = networkController;
+        mActivityStarter = activityStarter;
+        mController.observe(this, mCallback);
+        mKeyguard.observe(this, mCallback);
+        mNetworkController.observe(this, mSignalCallback);
     }
 
     @Override
@@ -87,15 +93,8 @@
     @Override
     public void handleSetListening(boolean listening) {
         if (DEBUG) Log.d(TAG, "handleSetListening " + listening);
-        if (listening) {
-            mController.addCallback(mCallback);
-            mKeyguard.addCallback(mCallback);
-            mNetworkController.addCallback(mSignalCallback);
-        } else {
+        if (!listening) {
             mController.setDiscovering(false);
-            mController.removeCallback(mCallback);
-            mKeyguard.removeCallback(mCallback);
-            mNetworkController.removeCallback(mSignalCallback);
         }
     }
 
@@ -135,7 +134,7 @@
             mDialog = MediaRouteDialogPresenter.createDialog(mContext, ROUTE_TYPE_REMOTE_DISPLAY,
                     v -> {
                         mDialog.dismiss();
-                        Dependency.get(ActivityStarter.class)
+                        mActivityStarter
                                 .postStartActivityDismissingKeyguard(getLongClickIntent(), 0);
                     });
             mDialog.getWindow().setType(LayoutParams.TYPE_KEYGUARD_DIALOG);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 9e341e2..1155a41 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -35,7 +35,6 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settingslib.net.DataUsageController;
-import com.android.systemui.Dependency;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.plugins.ActivityStarter;
@@ -51,6 +50,8 @@
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
 
+import javax.inject.Inject;
+
 /** Quick settings tile: Cellular **/
 public class CellularTile extends QSTileImpl<SignalState> {
     private static final String ENABLE_SETTINGS_DATA_PLAN = "enable.settings.data.plan";
@@ -63,13 +64,16 @@
     private final ActivityStarter mActivityStarter;
     private final KeyguardMonitor mKeyguardMonitor;
 
-    public CellularTile(QSHost host) {
+    @Inject
+    public CellularTile(QSHost host, NetworkController networkController,
+            ActivityStarter activityStarter, KeyguardMonitor keyguardMonitor) {
         super(host);
-        mController = Dependency.get(NetworkController.class);
-        mActivityStarter = Dependency.get(ActivityStarter.class);
-        mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
+        mController = networkController;
+        mActivityStarter = activityStarter;
+        mKeyguardMonitor = keyguardMonitor;
         mDataController = mController.getMobileDataController();
         mDetailAdapter = new CellularDetailAdapter();
+        mController.observe(getLifecycle(), mSignalCallback);
     }
 
     @Override
@@ -84,11 +88,6 @@
 
     @Override
     public void handleSetListening(boolean listening) {
-        if (listening) {
-            mController.addCallback(mSignalCallback);
-        } else {
-            mController.removeCallback(mSignalCallback);
-        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index c13a07f..ecb4048 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -30,6 +30,8 @@
 import com.android.systemui.qs.SecureSetting;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 
+import javax.inject.Inject;
+
 /** Quick settings tile: Invert colors **/
 public class ColorInversionTile extends QSTileImpl<BooleanState> {
 
@@ -38,6 +40,7 @@
 
     private boolean mListening;
 
+    @Inject
     public ColorInversionTile(QSHost host) {
         super(host);
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
index fd8b9c9..c6c6f87 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
@@ -20,7 +20,6 @@
 import android.widget.Switch;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.Dependency;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
@@ -30,14 +29,18 @@
 import com.android.systemui.statusbar.policy.DataSaverController;
 import com.android.systemui.statusbar.policy.NetworkController;
 
+import javax.inject.Inject;
+
 public class DataSaverTile extends QSTileImpl<BooleanState> implements
         DataSaverController.Listener{
 
     private final DataSaverController mDataSaverController;
 
-    public DataSaverTile(QSHost host) {
+    @Inject
+    public DataSaverTile(QSHost host, NetworkController networkController) {
         super(host);
-        mDataSaverController = Dependency.get(NetworkController.class).getDataSaverController();
+        mDataSaverController = networkController.getDataSaverController();
+        mDataSaverController.observe(getLifecycle(), this);
     }
 
     @Override
@@ -47,11 +50,6 @@
 
     @Override
     public void handleSetListening(boolean listening) {
-        if (listening) {
-            mDataSaverController.addCallback(this);
-        } else {
-            mDataSaverController.removeCallback(this);
-        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 50c8698..5f04e56 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -49,7 +49,6 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settingslib.notification.EnableZenModeDialog;
-import com.android.systemui.Dependency;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.SysUIToast;
@@ -62,6 +61,8 @@
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.volume.ZenModePanel;
 
+import javax.inject.Inject;
+
 /** Quick settings tile: Do not disturb **/
 public class DndTile extends QSTileImpl<BooleanState> {
 
@@ -76,17 +77,22 @@
 
     private final ZenModeController mController;
     private final DndDetailAdapter mDetailAdapter;
+    private final ActivityStarter mActivityStarter;
 
     private boolean mListening;
     private boolean mShowingDetail;
     private boolean mReceiverRegistered;
 
-    public DndTile(QSHost host) {
+    @Inject
+    public DndTile(QSHost host, ZenModeController zenModeController,
+            ActivityStarter activityStarter) {
         super(host);
-        mController = Dependency.get(ZenModeController.class);
+        mController = zenModeController;
+        mActivityStarter = activityStarter;
         mDetailAdapter = new DndDetailAdapter();
         mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_SET_VISIBLE));
         mReceiverRegistered = true;
+        mController.observe(getLifecycle(), mZenCallback);
     }
 
     @Override
@@ -157,7 +163,7 @@
             // show on-boarding screen
             Intent intent = new Intent(Settings.ZEN_MODE_ONBOARDING);
             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
-            Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(intent, 0);
+            mActivityStarter.postStartActivityDismissingKeyguard(intent, 0);
         } else {
             switch (zenDuration) {
                 case Settings.Secure.ZEN_DURATION_PROMPT:
@@ -281,10 +287,8 @@
         if (mListening == listening) return;
         mListening = listening;
         if (mListening) {
-            mController.addCallback(mZenCallback);
             Prefs.registerListener(mContext, mPrefListener);
         } else {
-            mController.removeCallback(mZenCallback);
             Prefs.unregisterListener(mContext, mPrefListener);
         }
     }
@@ -445,7 +449,7 @@
     private final ZenModePanel.Callback mZenModePanelCallback = new ZenModePanel.Callback() {
         @Override
         public void onPrioritySettings() {
-            Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(
+            mActivityStarter.postStartActivityDismissingKeyguard(
                     ZEN_PRIORITY_SETTINGS, 0);
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
index d7ac253..dfa3fb9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -23,13 +23,14 @@
 import android.widget.Switch;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.policy.FlashlightController;
 
+import javax.inject.Inject;
+
 /** Quick settings tile: Control flashlight **/
 public class FlashlightTile extends QSTileImpl<BooleanState> implements
         FlashlightController.FlashlightListener {
@@ -37,9 +38,11 @@
     private final Icon mIcon = ResourceIcon.get(R.drawable.ic_signal_flashlight);
     private final FlashlightController mFlashlightController;
 
-    public FlashlightTile(QSHost host) {
+    @Inject
+    public FlashlightTile(QSHost host, FlashlightController flashlightController) {
         super(host);
-        mFlashlightController = Dependency.get(FlashlightController.class);
+        mFlashlightController = flashlightController;
+        mFlashlightController.observe(getLifecycle(), this);
     }
 
     @Override
@@ -56,11 +59,6 @@
 
     @Override
     public void handleSetListening(boolean listening) {
-        if (listening) {
-            mFlashlightController.addCallback(this);
-        } else {
-            mFlashlightController.removeCallback(this);
-        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 6bf0793..b7e07f8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -25,7 +25,6 @@
 import android.widget.Switch;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.plugins.qs.QSTile.AirplaneBooleanState;
 import com.android.systemui.qs.GlobalSetting;
@@ -34,6 +33,8 @@
 import com.android.systemui.statusbar.policy.DataSaverController;
 import com.android.systemui.statusbar.policy.HotspotController;
 
+import javax.inject.Inject;
+
 /** Quick settings tile: Hotspot **/
 public class HotspotTile extends QSTileImpl<AirplaneBooleanState> {
     private static final Intent TETHER_SETTINGS = new Intent().setComponent(new ComponentName(
@@ -48,16 +49,20 @@
     private final GlobalSetting mAirplaneMode;
     private boolean mListening;
 
-    public HotspotTile(QSHost host) {
+    @Inject
+    public HotspotTile(QSHost host, HotspotController hotspotController,
+            DataSaverController dataSaverController) {
         super(host);
-        mHotspotController = Dependency.get(HotspotController.class);
-        mDataSaverController = Dependency.get(DataSaverController.class);
+        mHotspotController = hotspotController;
+        mDataSaverController = dataSaverController;
         mAirplaneMode = new GlobalSetting(mContext, mHandler, Global.AIRPLANE_MODE_ON) {
             @Override
             protected void handleValueChanged(int value) {
                 refreshState();
             }
         };
+        mHotspotController.observe(this, mCallbacks);
+        mDataSaverController.observe(this, mCallbacks);
     }
 
     @Override
@@ -80,12 +85,7 @@
         if (mListening == listening) return;
         mListening = listening;
         if (listening) {
-            mHotspotController.addCallback(mCallbacks);
-            mDataSaverController.addCallback(mCallbacks);
             refreshState();
-        } else {
-            mHotspotController.removeCallback(mCallbacks);
-            mDataSaverController.removeCallback(mCallbacks);
         }
         mAirplaneMode.setListening(listening);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index b5f2d00..d740033 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -23,7 +23,6 @@
 import android.widget.Switch;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.R.drawable;
 import com.android.systemui.plugins.ActivityStarter;
@@ -34,6 +33,8 @@
 import com.android.systemui.statusbar.policy.LocationController;
 import com.android.systemui.statusbar.policy.LocationController.LocationChangeCallback;
 
+import javax.inject.Inject;
+
 /** Quick settings tile: Location **/
 public class LocationTile extends QSTileImpl<BooleanState> {
 
@@ -41,12 +42,18 @@
 
     private final LocationController mController;
     private final KeyguardMonitor mKeyguard;
+    private final ActivityStarter mActivityStarter;
     private final Callback mCallback = new Callback();
 
-    public LocationTile(QSHost host) {
+    @Inject
+    public LocationTile(QSHost host, LocationController locationController,
+            KeyguardMonitor keyguardMonitor, ActivityStarter activityStarter) {
         super(host);
-        mController = Dependency.get(LocationController.class);
-        mKeyguard = Dependency.get(KeyguardMonitor.class);
+        mController = locationController;
+        mKeyguard = keyguardMonitor;
+        mActivityStarter = activityStarter;
+        mController.observe(this, mCallback);
+        mKeyguard.observe(this, mCallback);
     }
 
     @Override
@@ -56,13 +63,6 @@
 
     @Override
     public void handleSetListening(boolean listening) {
-        if (listening) {
-            mController.addCallback(mCallback);
-            mKeyguard.addCallback(mCallback);
-        } else {
-            mController.removeCallback(mCallback);
-            mKeyguard.removeCallback(mCallback);
-        }
     }
 
     @Override
@@ -73,7 +73,7 @@
     @Override
     protected void handleClick() {
         if (mKeyguard.isSecure() && mKeyguard.isShowing()) {
-            Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() -> {
+            mActivityStarter.postQSRunnableDismissingKeyguard(() -> {
                 final boolean wasEnabled = mState.value;
                 mHost.openPanels();
                 mController.setLocationEnabled(!wasEnabled);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
index a365e4c..476a239 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
@@ -33,6 +33,8 @@
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 
+import javax.inject.Inject;
+
 /** Quick settings tile: Enable/Disable NFC **/
 public class NfcTile extends QSTileImpl<BooleanState> {
 
@@ -40,6 +42,7 @@
 
     private boolean mListening;
 
+    @Inject
     public NfcTile(QSHost host) {
         super(host);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
index 90890c0..b04132d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
@@ -44,6 +44,8 @@
 import java.util.Calendar;
 import java.util.TimeZone;
 
+import javax.inject.Inject;
+
 public class NightDisplayTile extends QSTileImpl<BooleanState>
         implements ColorDisplayController.Callback {
 
@@ -58,6 +60,7 @@
     private ColorDisplayController mController;
     private boolean mIsListening;
 
+    @Inject
     public NightDisplayTile(QSHost host) {
         super(host);
         mController = new ColorDisplayController(mContext, ActivityManager.getCurrentUser());
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index 6345816..21f3d6e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -24,7 +24,6 @@
 import android.widget.Switch;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.qs.QSHost;
@@ -32,15 +31,19 @@
 import com.android.systemui.statusbar.policy.RotationLockController;
 import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback;
 
+import javax.inject.Inject;
+
 /** Quick settings tile: Rotation **/
 public class RotationLockTile extends QSTileImpl<BooleanState> {
 
     private final Icon mIcon = ResourceIcon.get(R.drawable.ic_qs_auto_rotate);
     private final RotationLockController mController;
 
-    public RotationLockTile(QSHost host) {
+    @Inject
+    public RotationLockTile(QSHost host, RotationLockController rotationLockController) {
         super(host);
-        mController = Dependency.get(RotationLockController.class);
+        mController = rotationLockController;
+        mController.observe(this, mCallback);
     }
 
     @Override
@@ -49,11 +52,6 @@
     }
 
     public void handleSetListening(boolean listening) {
-        if (listening) {
-            mController.addCallback(mCallback);
-        } else {
-            mController.removeCallback(mCallback);
-        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyTile.java
index ff368f8..5230cea 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyTile.java
@@ -23,7 +23,6 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
@@ -31,6 +30,8 @@
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 
+import javax.inject.Inject;
+
 /** Quick settings tile: SensorPrivacy mode **/
 public class SensorPrivacyTile extends QSTileImpl<BooleanState> implements
         SensorPrivacyManager.OnSensorPrivacyChangedListener {
@@ -39,12 +40,16 @@
             ResourceIcon.get(R.drawable.ic_signal_sensors);
     private final KeyguardMonitor mKeyguard;
     private final SensorPrivacyManager mSensorPrivacyManager;
+    private final ActivityStarter mActivityStarter;
 
-    public SensorPrivacyTile(QSHost host) {
+    @Inject
+    public SensorPrivacyTile(QSHost host, SensorPrivacyManager sensorPrivacyManager,
+            KeyguardMonitor keyguardMonitor, ActivityStarter activityStarter) {
         super(host);
 
-        mSensorPrivacyManager = Dependency.get(SensorPrivacyManager.class);
-        mKeyguard = Dependency.get(KeyguardMonitor.class);
+        mSensorPrivacyManager = sensorPrivacyManager;
+        mKeyguard = keyguardMonitor;
+        mActivityStarter = activityStarter;
     }
 
     @Override
@@ -57,7 +62,7 @@
         final boolean wasEnabled = mState.value;
         // Don't allow disabling from the lockscreen.
         if (wasEnabled && mKeyguard.isSecure() && mKeyguard.isShowing()) {
-            Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() -> {
+            mActivityStarter.postQSRunnableDismissingKeyguard(() -> {
                 MetricsLogger.action(mContext, getMetricsCategory(), !wasEnabled);
                 setEnabled(!wasEnabled);
             });
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
index e5c51a6..7c1ffde 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
@@ -22,7 +22,6 @@
 import android.util.Pair;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.Dependency;
 import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.qs.QSTile.State;
@@ -31,16 +30,21 @@
 import com.android.systemui.statusbar.policy.UserInfoController;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 
+import javax.inject.Inject;
+
 public class UserTile extends QSTileImpl<State> implements UserInfoController.OnUserInfoChangedListener {
 
     private final UserSwitcherController mUserSwitcherController;
     private final UserInfoController mUserInfoController;
     private Pair<String, Drawable> mLastUpdate;
 
-    public UserTile(QSHost host) {
+    @Inject
+    public UserTile(QSHost host, UserSwitcherController userSwitcherController,
+            UserInfoController userInfoController) {
         super(host);
-        mUserSwitcherController = Dependency.get(UserSwitcherController.class);
-        mUserInfoController = Dependency.get(UserInfoController.class);
+        mUserSwitcherController = userSwitcherController;
+        mUserInfoController = userInfoController;
+        mUserInfoController.observe(getLifecycle(), this);
     }
 
     @Override
@@ -70,11 +74,6 @@
 
     @Override
     public void handleSetListening(boolean listening) {
-        if (listening) {
-            mUserInfoController.addCallback(this);
-        } else {
-            mUserInfoController.removeCallback(this);
-        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 6939ae7..52a8814 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -30,7 +30,6 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settingslib.wifi.AccessPoint;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.DetailAdapter;
@@ -51,6 +50,8 @@
 
 import java.util.List;
 
+import javax.inject.Inject;
+
 /** Quick settings tile: Wifi **/
 public class WifiTile extends QSTileImpl<SignalState> {
     private static final Intent WIFI_SETTINGS = new Intent(Settings.ACTION_WIFI_SETTINGS);
@@ -64,12 +65,15 @@
     private final ActivityStarter mActivityStarter;
     private boolean mExpectDisabled;
 
-    public WifiTile(QSHost host) {
+    @Inject
+    public WifiTile(QSHost host, NetworkController networkController,
+            ActivityStarter activityStarter) {
         super(host);
-        mController = Dependency.get(NetworkController.class);
+        mController = networkController;
         mWifiController = mController.getAccessPointController();
         mDetailAdapter = (WifiDetailAdapter) createDetailAdapter();
-        mActivityStarter = Dependency.get(ActivityStarter.class);
+        mActivityStarter = activityStarter;
+        mController.observe(getLifecycle(), mSignalCallback);
     }
 
     @Override
@@ -79,11 +83,6 @@
 
     @Override
     public void handleSetListening(boolean listening) {
-        if (listening) {
-            mController.addCallback(mSignalCallback);
-        } else {
-            mController.removeCallback(mSignalCallback);
-        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
index 3109dea..f921eb9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
@@ -22,13 +22,14 @@
 import android.widget.Switch;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.phone.ManagedProfileController;
 
+import javax.inject.Inject;
+
 /** Quick settings tile: Work profile on/off */
 public class WorkModeTile extends QSTileImpl<BooleanState> implements
         ManagedProfileController.Callback {
@@ -36,9 +37,11 @@
 
     private final ManagedProfileController mProfileController;
 
-    public WorkModeTile(QSHost host) {
+    @Inject
+    public WorkModeTile(QSHost host, ManagedProfileController managedProfileController) {
         super(host);
-        mProfileController = Dependency.get(ManagedProfileController.class);
+        mProfileController = managedProfileController;
+        mProfileController.observe(getLifecycle(), this);
     }
 
     @Override
@@ -48,11 +51,6 @@
 
     @Override
     public void handleSetListening(boolean listening) {
-        if (listening) {
-            mProfileController.addCallback(this);
-        } else {
-            mProfileController.removeCallback(this);
-        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 538e0f0..81757d0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -44,7 +44,6 @@
 import android.view.MotionEvent;
 
 import com.android.internal.policy.ScreenDecorationsUtils;
-import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
 import com.android.systemui.Prefs;
 import com.android.systemui.SysUiServiceProvider;
@@ -90,8 +89,7 @@
     private final Handler mHandler;
     private final Runnable mConnectionRunnable = this::internalConnectToCurrentUser;
     private final ComponentName mRecentsComponentName;
-    private final DeviceProvisionedController mDeviceProvisionedController
-            = Dependency.get(DeviceProvisionedController.class);
+    private final DeviceProvisionedController mDeviceProvisionedController;
     private final List<OverviewProxyListener> mConnectionCallbacks = new ArrayList<>();
     private final Intent mQuickStepIntent;
 
@@ -343,9 +341,10 @@
             = this::cleanupAfterDeath;
 
     @Inject
-    public OverviewProxyService(Context context) {
+    public OverviewProxyService(Context context, DeviceProvisionedController provisionController) {
         mContext = context;
         mHandler = new Handler();
+        mDeviceProvisionedController = provisionController;
         mConnectionBackoffAttempts = 0;
         mRecentsComponentName = ComponentName.unflattenFromString(context.getString(
                 com.android.internal.R.string.config_recentsComponentName));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
index 6f1548d..9e91133 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
@@ -21,7 +21,6 @@
 
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.NotificationVisibility;
-import com.android.systemui.Dependency;
 import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 
@@ -36,15 +35,16 @@
  */
 @Singleton
 public class SmartReplyController {
-    private IStatusBarService mBarService;
+    private final IStatusBarService mBarService;
+    private final NotificationEntryManager mEntryManager;
     private Set<String> mSendingKeys = new ArraySet<>();
     private Callback mCallback;
-    private final NotificationEntryManager mEntryManager =
-            Dependency.get(NotificationEntryManager.class);
 
     @Inject
-    public SmartReplyController() {
-        mBarService = Dependency.get(IStatusBarService.class);
+    public SmartReplyController(NotificationEntryManager entryManager,
+            IStatusBarService statusBarService) {
+        mBarService = statusBarService;
+        mEntryManager = entryManager;
     }
 
     public void setCallback(Callback callback) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index eb1fc30..75bad6d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -27,7 +27,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.NotificationVisibility;
-import com.android.systemui.Dependency;
 import com.android.systemui.UiOffloadThread;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.StatusBarStateController;
@@ -59,11 +58,9 @@
             new ArraySet<>();
 
     // Dependencies:
-    private final NotificationListenerService mNotificationListener =
-            Dependency.get(NotificationListener.class);
-    private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
-    protected NotificationEntryManager mEntryManager
-            = Dependency.get(NotificationEntryManager.class);
+    private final NotificationListenerService mNotificationListener;
+    private final UiOffloadThread mUiOffloadThread;
+    protected NotificationEntryManager mEntryManager;
 
     protected Handler mHandler = new Handler();
     protected IStatusBarService mBarService;
@@ -150,11 +147,17 @@
     };
 
     @Inject
-    public NotificationLogger() {
+    public NotificationLogger(NotificationListener notificationListener,
+            UiOffloadThread uiOffloadThread,
+            NotificationEntryManager entryManager,
+            StatusBarStateController statusBarStateController) {
+        mNotificationListener = notificationListener;
+        mUiOffloadThread = uiOffloadThread;
+        mEntryManager = entryManager;
         mBarService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
         // Not expected to be destroyed, don't need to unsubscribe
-        Dependency.get(StatusBarStateController.class).addCallback(this);
+        statusBarStateController.addCallback(this);
     }
 
     public void setUpWithContainer(NotificationListContainer listContainer) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 92a9efe..6f2b63d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -158,8 +158,11 @@
      * @return duration in millis.
      */
     public long getWallpaperAodDuration() {
-        return shouldControlScreenOff() ? DozeScreenState.ENTER_DOZE_HIDE_WALLPAPER_DELAY
-                : mAlwaysOnPolicy.wallpaperVisibilityDuration;
+        if (mAmbientDisplayConfiguration.wakeLockScreenGestureEnabled(UserHandle.USER_CURRENT)
+                || shouldControlScreenOff()) {
+            return DozeScreenState.ENTER_DOZE_HIDE_WALLPAPER_DELAY;
+        }
+        return mAlwaysOnPolicy.wallpaperVisibilityDuration;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 21c506b..2e9d9bc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -19,7 +19,6 @@
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
 import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 
-import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
 import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_BUTTON;
 import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_UNLOCK;
 import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_RIGHT_BUTTON;
@@ -54,7 +53,6 @@
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.util.MathUtils;
 import android.util.TypedValue;
 import android.view.View;
 import android.view.ViewGroup;
@@ -172,8 +170,6 @@
     private boolean mDozing;
     private int mIndicationBottomMargin;
     private float mDarkAmount;
-    private int mBurnInXOffset;
-    private int mBurnInYOffset;
 
     public KeyguardBottomAreaView(Context context) {
         this(context, null);
@@ -250,8 +246,6 @@
         mIndicationText = findViewById(R.id.keyguard_indication_text);
         mIndicationBottomMargin = getResources().getDimensionPixelSize(
                 R.dimen.keyguard_indication_margin_bottom);
-        mBurnInYOffset = getResources().getDimensionPixelSize(
-                R.dimen.default_burn_in_prevention_offset);
         updateCameraVisibility();
         mUnlockMethodCache = UnlockMethodCache.getInstance(getContext());
         mUnlockMethodCache.addListener(this);
@@ -322,8 +316,6 @@
         super.onConfigurationChanged(newConfig);
         mIndicationBottomMargin = getResources().getDimensionPixelSize(
                 R.dimen.keyguard_indication_margin_bottom);
-        mBurnInYOffset = getResources().getDimensionPixelSize(
-                R.dimen.default_burn_in_prevention_offset);
         MarginLayoutParams mlp = (MarginLayoutParams) mIndicationArea.getLayoutParams();
         if (mlp.bottomMargin != mIndicationBottomMargin) {
             mlp.bottomMargin = mIndicationBottomMargin;
@@ -569,7 +561,15 @@
         mDarkAmount = darkAmount;
         mIndicationController.setDarkAmount(darkAmount);
         mLockIcon.setDarkAmount(darkAmount);
-        dozeTimeTick();
+    }
+
+    /**
+     * When keyguard is in pulsing (AOD2) state.
+     * @param pulsing {@code true} when pulsing.
+     * @param animated if transition should be animated.
+     */
+    public void setPulsing(boolean pulsing, boolean animated) {
+        mLockIcon.setPulsing(pulsing, animated);
     }
 
     private static boolean isSuccessfulLaunch(int result) {
@@ -830,6 +830,7 @@
 
         updateCameraVisibility();
         updateLeftAffordanceIcon();
+        mLockIcon.setDozing(dozing);
 
         if (dozing) {
             mOverlayContainer.setVisibility(INVISIBLE);
@@ -841,21 +842,6 @@
         }
     }
 
-    public void dozeTimeTick() {
-        // Move views every minute to avoid burn-in
-        int burnInYOffset = -getBurnInOffset(mBurnInYOffset, false /* xAxis */);
-        burnInYOffset = (int) MathUtils.lerp(0, burnInYOffset, mDarkAmount);
-        mLockIcon.setTranslationY(burnInYOffset);
-    }
-
-    public void setBurnInXOffset(int burnInXOffset) {
-        if (mBurnInXOffset == burnInXOffset) {
-            return;
-        }
-        mBurnInXOffset = burnInXOffset;
-        mLockIcon.setTranslationX(burnInXOffset);
-    }
-
     private class DefaultLeftButton implements IntentButton {
 
         private IconState mIconState = new IconState();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
index e156e77..6632d58 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
@@ -25,7 +25,6 @@
 import android.view.View;
 
 import com.android.internal.colorextraction.ColorExtractor.GradientColors;
-import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.policy.BatteryController;
@@ -83,10 +82,11 @@
     private final Context mContext;
 
     @Inject
-    public LightBarController(Context ctx) {
+    public LightBarController(Context ctx, DarkIconDispatcher darkIconDispatcher,
+            BatteryController batteryController) {
         mDarkModeColor = Color.valueOf(ctx.getColor(R.color.dark_mode_icon_color_single_tone));
-        mStatusBarIconController = Dependency.get(DarkIconDispatcher.class);
-        mBatteryController = Dependency.get(BatteryController.class);
+        mStatusBarIconController = darkIconDispatcher;
+        mBatteryController = batteryController;
         mBatteryController.addCallback(this);
         mContext = ctx;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 1be3975..d934d95 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -45,8 +45,6 @@
     private static final int STATE_FACE_UNLOCK = 2;
     private static final int STATE_FINGERPRINT = 3;
     private static final int STATE_FINGERPRINT_ERROR = 4;
-    private static final boolean HOLLOW_PILL = SystemProperties
-            .getBoolean("persist.sysui.hollow_pill", false);
 
     private int mLastState = 0;
     private boolean mLastDeviceInteractive;
@@ -60,6 +58,8 @@
     private boolean mHasFingerPrintIcon;
     private boolean mHasFaceUnlockIcon;
     private int mDensity;
+    private boolean mPulsing;
+    private boolean mDozing;
 
     private final Runnable mDrawOffTimeout = () -> update(true /* forceUpdate */);
     private float mDarkAmount;
@@ -159,6 +159,7 @@
             mLastScreenOn = mScreenOn;
         }
 
+        setVisibility(mDozing && !mPulsing ? GONE : VISIBLE);
         updateClickability();
     }
 
@@ -224,16 +225,6 @@
                 throw new IllegalArgumentException();
         }
 
-        if (HOLLOW_PILL && deviceInteractive) {
-            switch (state) {
-                case STATE_FINGERPRINT:
-                case STATE_LOCK_OPEN:
-                case STATE_LOCKED:
-                case STATE_FACE_UNLOCK:
-                    iconRes = R.drawable.ic_home_button_outline;
-            }
-        }
-
         return mContext.getDrawable(iconRes);
     }
 
@@ -281,6 +272,24 @@
         updateDarkTint();
     }
 
+    /**
+     * When keyguard is in pulsing (AOD2) state.
+     * @param pulsing {@code true} when pulsing.
+     * @param animated if transition should be animated.
+     */
+    public void setPulsing(boolean pulsing, boolean animated) {
+        mPulsing = pulsing;
+        update();
+    }
+
+    /**
+     * Sets the dozing state of the keyguard.
+     */
+    public void setDozing(boolean dozing) {
+        mDozing = dozing;
+        update();
+    }
+
     private void updateDarkTint() {
         Drawable drawable = getDrawable().mutate();
         int color = ColorUtils.blendARGB(Color.TRANSPARENT, Color.WHITE, mDarkAmount);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 242573d..1b18c6c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -579,7 +579,6 @@
         }
         mNotificationStackScroller.setIntrinsicPadding(stackScrollerPadding);
         mNotificationStackScroller.setAntiBurnInOffsetX(mClockPositionResult.clockX);
-        mKeyguardBottomArea.setBurnInXOffset(mClockPositionResult.clockX);
 
         mStackScrollerMeasuringPass++;
         requestScrollerTopPaddingUpdate(animate);
@@ -2806,6 +2805,7 @@
         }
         mNotificationStackScroller.setPulsing(pulsing, animatePulse);
         mKeyguardStatusView.setPulsing(pulsing, animatePulse);
+        mKeyguardBottomArea.setPulsing(pulsing, animatePulse);
     }
 
     public void setAmbientIndicationBottomPadding(int ambientIndicationBottomPadding) {
@@ -2818,7 +2818,6 @@
     public void dozeTimeTick() {
         mKeyguardStatusBar.dozeTimeTick();
         mKeyguardStatusView.dozeTimeTick();
-        mKeyguardBottomArea.dozeTimeTick();
         if (mInterpolatedDarkAmount > 0) {
             positionClockAndNotifications();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 6a4da98..e25c829 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -93,12 +93,12 @@
      * A scrim varies its opacity based on a busyness factor, for example
      * how many notifications are currently visible.
      */
-    public static final float GRADIENT_SCRIM_ALPHA_BUSY = 0.70f;
+    public static final float GRADIENT_SCRIM_ALPHA_BUSY = 0.7f;
     /**
-     * A scrim varies its opacity based on a busyness factor, for example
-     * how many notifications are currently visible.
+     * Scrim opacity when a wallpaper doesn't support ambient mode.
      */
-    public static final float GRADIENT_SCRIM_DARK_KEYGUARD = 0.80f;
+    public static final float PULSING_WALLPAPER_SCRIM_ALPHA = 0.6f;
+
     /**
      * The most common scrim, the one under the keyguard.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index 226665e..fb3c4aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -141,7 +141,8 @@
 
         @Override
         public float getBehindAlpha(float busyness) {
-            return mWallpaperSupportsAmbientMode && !mHasBackdrop ? 0f : 1f;
+            return mWallpaperSupportsAmbientMode && !mHasBackdrop ? 0f
+                    : ScrimController.PULSING_WALLPAPER_SCRIM_ALPHA;
         }
     },
 
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 40e2aae..7f16480 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -148,7 +148,6 @@
 import com.android.systemui.doze.DozeHost;
 import com.android.systemui.doze.DozeLog;
 import com.android.systemui.doze.DozeReceiver;
-import com.android.systemui.doze.LockScreenWakeUpController;
 import com.android.systemui.fragments.ExtensionFragmentListener;
 import com.android.systemui.fragments.FragmentHostManager;
 import com.android.systemui.keyguard.KeyguardSliceProvider;
@@ -160,7 +159,6 @@
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
 import com.android.systemui.qs.QSFragment;
 import com.android.systemui.qs.QSPanel;
-import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.ScreenPinningRequest;
 import com.android.systemui.shared.system.WindowManagerWrapper;
@@ -588,7 +586,6 @@
     protected NotificationPresenter mPresenter;
     private NotificationActivityStarter mNotificationActivityStarter;
     private boolean mPulsing;
-    private LockScreenWakeUpController mLockScreenWakeUpController;
 
     @Override
     public void onActiveStateChanged(int code, int uid, String packageName, boolean active) {
@@ -940,8 +937,6 @@
                             .withPlugin(QS.class)
                             .withDefault(this::createDefaultQSFragment)
                             .build());
-            final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this,
-                    mIconController);
             mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow,
                     (visible) -> {
                         mBrightnessMirrorVisible = visible;
@@ -950,7 +945,6 @@
             fragmentHostManager.addTagListener(QS.TAG, (tag, f) -> {
                 QS qs = (QS) f;
                 if (qs instanceof QSFragment) {
-                    ((QSFragment) qs).setHost(qsh);
                     mQSPanel = ((QSFragment) qs).getQsPanel();
                     mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
                 }
@@ -999,7 +993,6 @@
         for (int i = 0; i < pattern.length; i++) {
             mCameraLaunchGestureVibePattern[i] = pattern[i];
         }
-        mLockScreenWakeUpController = new LockScreenWakeUpController(mContext, mDozeServiceHost);
 
         // receive broadcasts
         IntentFilter filter = new IntentFilter();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
index 5d61f4a..6190c8f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -30,7 +30,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settingslib.fuelgauge.BatterySaverUtils;
 import com.android.settingslib.utils.PowerUtil;
-import com.android.systemui.Dependency;
 import com.android.systemui.power.EnhancedEstimates;
 import com.android.systemui.power.Estimate;
 
@@ -55,7 +54,7 @@
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     private static final int UPDATE_GRANULARITY_MSEC = 1000 * 60;
 
-    private final EnhancedEstimates mEstimates = Dependency.get(EnhancedEstimates.class);
+    private final EnhancedEstimates mEstimates;
     private final ArrayList<BatteryController.BatteryStateChangeCallback> mChangeCallbacks = new ArrayList<>();
     private final PowerManager mPowerManager;
     private final Handler mHandler;
@@ -73,15 +72,17 @@
     private long mLastEstimateTimestamp = -1;
 
     @Inject
-    public BatteryControllerImpl(Context context) {
-        this(context, context.getSystemService(PowerManager.class));
+    public BatteryControllerImpl(Context context, EnhancedEstimates enhancedEstimates) {
+        this(context, enhancedEstimates, context.getSystemService(PowerManager.class));
     }
 
     @VisibleForTesting
-    BatteryControllerImpl(Context context, PowerManager powerManager) {
+    BatteryControllerImpl(Context context, EnhancedEstimates enhancedEstimates,
+            PowerManager powerManager) {
         mContext = context;
         mHandler = new Handler();
         mPowerManager = powerManager;
+        mEstimates = enhancedEstimates;
 
         registerReceiver();
         updatePowerSave();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index c855000..8916242 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -18,6 +18,7 @@
 
 import static com.android.systemui.Dependency.BG_LOOPER_NAME;
 
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
@@ -34,7 +35,6 @@
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
-import com.android.systemui.Dependency;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -73,8 +73,9 @@
     /**
      */
     @Inject
-    public BluetoothControllerImpl(Context context, @Named(BG_LOOPER_NAME) Looper bgLooper) {
-        mLocalBluetoothManager = Dependency.get(LocalBluetoothManager.class);
+    public BluetoothControllerImpl(Context context, @Named(BG_LOOPER_NAME) Looper bgLooper,
+            @Nullable LocalBluetoothManager localBluetoothManager) {
+        mLocalBluetoothManager = localBluetoothManager;
         mBgHandler = new Handler(bgLooper);
         if (mLocalBluetoothManager != null) {
             mLocalBluetoothManager.getEventManager().registerCallback(this);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java
index c995162..f5e745f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java
@@ -14,6 +14,8 @@
 
 package com.android.systemui.statusbar.policy;
 
+import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
+
 import android.app.ActivityManager;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -21,13 +23,14 @@
 import android.net.Uri;
 import android.provider.Settings.Global;
 import android.provider.Settings.Secure;
+import android.os.Handler;
 
-import com.android.systemui.Dependency;
 import com.android.systemui.settings.CurrentUserTracker;
 
 import java.util.ArrayList;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 import javax.inject.Singleton;
 
 /**
@@ -41,16 +44,28 @@
     private final Context mContext;
     private final Uri mDeviceProvisionedUri;
     private final Uri mUserSetupUri;
+    protected final ContentObserver mSettingsObserver;
 
     /**
      */
     @Inject
-    public DeviceProvisionedControllerImpl(Context context) {
+    public DeviceProvisionedControllerImpl(Context context,
+            @Named(MAIN_HANDLER_NAME) Handler mainHandler) {
         super(context);
         mContext = context;
         mContentResolver = context.getContentResolver();
         mDeviceProvisionedUri = Global.getUriFor(Global.DEVICE_PROVISIONED);
         mUserSetupUri = Secure.getUriFor(Secure.USER_SETUP_COMPLETE);
+        mSettingsObserver = new ContentObserver(mainHandler) {
+            @Override
+            public void onChange(boolean selfChange, Uri uri, int userId) {
+                if (mUserSetupUri.equals(uri)) {
+                    notifySetupChanged();
+                } else {
+                    notifyProvisionedChanged();
+                }
+            }
+        };
     }
 
     @Override
@@ -127,17 +142,4 @@
             mListeners.get(i).onDeviceProvisionedChanged();
         }
     }
-
-    protected final ContentObserver mSettingsObserver = new ContentObserver(Dependency.get(
-            Dependency.MAIN_HANDLER)) {
-
-        @Override
-        public void onChange(boolean selfChange, Uri uri, int userId) {
-            if (mUserSetupUri.equals(uri)) {
-                notifySetupChanged();
-            } else {
-                notifyProvisionedChanged();
-            }
-        }
-    };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index 420abe8..b561ac1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -16,20 +16,22 @@
 
 package com.android.systemui.statusbar.policy;
 
+import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
+
 import android.app.ActivityManager;
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.wifi.WifiManager;
+import android.os.Handler;
 import android.os.UserManager;
 import android.util.Log;
 
-import com.android.systemui.Dependency;
-
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 import javax.inject.Singleton;
 
 /**
@@ -43,6 +45,7 @@
     private final ArrayList<Callback> mCallbacks = new ArrayList<>();
     private final ConnectivityManager mConnectivityManager;
     private final WifiManager mWifiManager;
+    private final Handler mMainHandler;
     private final Context mContext;
 
     private int mHotspotState;
@@ -52,11 +55,12 @@
     /**
      */
     @Inject
-    public HotspotControllerImpl(Context context) {
+    public HotspotControllerImpl(Context context, @Named(MAIN_HANDLER_NAME) Handler mainHandler) {
         mContext = context;
         mConnectivityManager =
                 (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
         mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+        mMainHandler = mainHandler;
     }
 
     @Override
@@ -118,10 +122,13 @@
      * @param shouldListen whether we should start listening to various wifi statuses
      */
     private void updateWifiStateListeners(boolean shouldListen) {
+        if (mWifiManager == null) {
+            return;
+        }
         if (shouldListen) {
             mWifiManager.registerSoftApCallback(
                     this,
-                    Dependency.get(Dependency.MAIN_HANDLER));
+                    mMainHandler);
         } else {
             mWifiManager.unregisterSoftApCallback(this);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.java
index 2a10db6..630bd18 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.java
@@ -21,7 +21,6 @@
 import android.content.res.Configuration;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.Dependency;
 import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.qs.QSFragment;
 import com.android.systemui.statusbar.CommandQueue;
@@ -44,11 +43,12 @@
     @VisibleForTesting CommandQueue mCommandQueue;
 
     @Inject
-    public RemoteInputQuickSettingsDisabler(Context context) {
+    public RemoteInputQuickSettingsDisabler(Context context,
+            ConfigurationController configController) {
         mContext = context;
         mCommandQueue = SysUiServiceProvider.getComponent(context, CommandQueue.class);
         mLastOrientation = mContext.getResources().getConfiguration().orientation;
-        Dependency.get(ConfigurationController.class).addCallback(this);
+        configController.addCallback(this);
     }
 
     public int adjustDisableFlags(int state) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index e0259c9..d88ae78 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -15,6 +15,8 @@
  */
 package com.android.systemui.statusbar.policy;
 
+import static com.android.systemui.Dependency.BG_HANDLER_NAME;
+
 import android.app.ActivityManager;
 import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
@@ -47,7 +49,6 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.net.LegacyVpnInfo;
 import com.android.internal.net.VpnConfig;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.settings.CurrentUserTracker;
 
@@ -56,6 +57,7 @@
 import java.util.ArrayList;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 import javax.inject.Singleton;
 
 /**
@@ -84,6 +86,7 @@
     private final DevicePolicyManager mDevicePolicyManager;
     private final PackageManager mPackageManager;
     private final UserManager mUserManager;
+    private final Handler mBgHandler;
 
     @GuardedBy("mCallbacks")
     private final ArrayList<SecurityControllerCallback> mCallbacks = new ArrayList<>();
@@ -99,13 +102,15 @@
     /**
      */
     @Inject
-    public SecurityControllerImpl(Context context) {
-        this(context, null);
+    public SecurityControllerImpl(Context context, @Named(BG_HANDLER_NAME) Handler bgHandler) {
+        this(context, bgHandler, null);
     }
 
-    public SecurityControllerImpl(Context context, SecurityControllerCallback callback) {
+    public SecurityControllerImpl(Context context, Handler bgHandler,
+            SecurityControllerCallback callback) {
         super(context);
         mContext = context;
+        mBgHandler = bgHandler;
         mDevicePolicyManager = (DevicePolicyManager)
                 context.getSystemService(Context.DEVICE_POLICY_SERVICE);
         mConnectivityManager = (ConnectivityManager)
@@ -121,7 +126,7 @@
         IntentFilter filter = new IntentFilter();
         filter.addAction(KeyChain.ACTION_TRUST_STORE_CHANGED);
         context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null,
-                new Handler(Dependency.get(Dependency.BG_LOOPER)));
+                bgHandler);
 
         // TODO: re-register network callback on user change.
         mConnectivityManager.registerNetworkCallback(REQUEST, mNetworkCallback);
@@ -413,7 +418,7 @@
                 return new Pair<Integer, Boolean>(userId[0], hasCACerts);
             } catch (RemoteException | InterruptedException | AssertionError e) {
                 Log.i(TAG, "failed to get CA certs", e);
-                new Handler(Dependency.get(Dependency.BG_LOOPER)).postDelayed(
+                mBgHandler.postDelayed(
                         () -> new CACertLoader().execute(userId[0]),
                         CA_CERT_LOADING_RETRY_TIME_IN_MS);
                 return new Pair<Integer, Boolean>(userId[0], null);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index e412e09..9343bf1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -51,7 +51,6 @@
 import com.android.internal.util.UserIcons;
 import com.android.settingslib.RestrictedLockUtilsInternal;
 import com.android.settingslib.Utils;
-import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
 import com.android.systemui.GuestResumeSessionReceiver;
 import com.android.systemui.Prefs;
@@ -597,7 +596,7 @@
 
         protected BaseUserAdapter(UserSwitcherController controller) {
             mController = controller;
-            mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
+            mKeyguardMonitor = controller.mKeyguardMonitor;
             controller.addAdapter(new WeakReference<>(this));
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
index 693df88..6f63544 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -53,7 +53,9 @@
                 connectivityManager, this::handleStatusUpdated);
         mWifiTracker.setListening(true);
         mHasMobileData = hasMobileData;
-        wifiManager.registerTrafficStateCallback(new WifiTrafficStateCallback(),  null);
+        if (wifiManager != null) {
+            wifiManager.registerTrafficStateCallback(new WifiTrafficStateCallback(), null);
+        }
         // WiFi only has one state.
         mCurrentState.iconGroup = mLastState.iconGroup = new IconGroup(
                 "Wi-Fi Icons",
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunablePadding.java b/packages/SystemUI/src/com/android/systemui/tuner/TunablePadding.java
index 81d77a6..8f3a8f6 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunablePadding.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunablePadding.java
@@ -38,8 +38,9 @@
     private final View mView;
     private final int mDefaultSize;
     private final float mDensity;
+    private final TunerService mTunerService;
 
-    private TunablePadding(String key, int def, int flags, View view) {
+    private TunablePadding(String key, int def, int flags, View view, TunerService tunerService) {
         mDefaultSize = def;
         mFlags = flags;
         mView = view;
@@ -47,7 +48,8 @@
         view.getContext().getSystemService(WindowManager.class)
                 .getDefaultDisplay().getMetrics(metrics);
         mDensity = metrics.density;
-        Dependency.get(TunerService.class).addTunable(this, key);
+        mTunerService = tunerService;
+        mTunerService.addTunable(this, key);
     }
 
     @Override
@@ -69,7 +71,7 @@
     }
 
     public void destroy() {
-        Dependency.get(TunerService.class).removeTunable(this);
+        mTunerService.removeTunable(this);
     }
 
     /**
@@ -78,17 +80,20 @@
     @Singleton
     public static class TunablePaddingService {
 
+        private final TunerService mTunerService;
+
         /**
          */
         @Inject
-        public TunablePaddingService() {
+        public TunablePaddingService(TunerService tunerService) {
+            mTunerService = tunerService;
         }
 
         public TunablePadding add(View view, String key, int defaultSize, int flags) {
             if (view == null) {
                 throw new IllegalArgumentException();
             }
-            return new TunablePadding(key, defaultSize, flags, view);
+            return new TunablePadding(key, defaultSize, flags, view, mTunerService);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
index 0a47f19..6185063 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
@@ -15,6 +15,8 @@
  */
 package com.android.systemui.tuner;
 
+import static com.android.systemui.Dependency.BG_HANDLER_NAME;
+
 import android.app.ActivityManager;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -33,7 +35,6 @@
 
 import com.android.internal.util.ArrayUtils;
 import com.android.systemui.DemoMode;
-import com.android.systemui.Dependency;
 import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.settings.CurrentUserTracker;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -44,6 +45,7 @@
 import java.util.Set;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 import javax.inject.Singleton;
 
 
@@ -71,6 +73,7 @@
     // Set of all tunables, used for leak detection.
     private final HashSet<Tunable> mTunables = LeakDetector.ENABLED ? new HashSet<>() : null;
     private final Context mContext;
+    private final LeakDetector mLeakDetector;
 
     private ContentResolver mContentResolver;
     private int mCurrentUser;
@@ -79,14 +82,16 @@
     /**
      */
     @Inject
-    public TunerServiceImpl(Context context) {
+    public TunerServiceImpl(Context context, @Named(BG_HANDLER_NAME) Handler bgHandler,
+            LeakDetector leakDetector) {
         mContext = context;
         mContentResolver = mContext.getContentResolver();
+        mLeakDetector = leakDetector;
 
         for (UserInfo user : UserManager.get(mContext).getUsers()) {
             mCurrentUser = user.getUserHandle().getIdentifier();
             if (getValue(TUNER_VERSION, 0) != CURRENT_TUNER_VERSION) {
-                upgradeTuner(getValue(TUNER_VERSION, 0), CURRENT_TUNER_VERSION);
+                upgradeTuner(getValue(TUNER_VERSION, 0), CURRENT_TUNER_VERSION, bgHandler);
             }
         }
 
@@ -107,7 +112,7 @@
         mUserTracker.stopTracking();
     }
 
-    private void upgradeTuner(int oldVersion, int newVersion) {
+    private void upgradeTuner(int oldVersion, int newVersion, Handler bgHandler) {
         if (oldVersion < 1) {
             String blacklistStr = getValue(StatusBarIconController.ICON_BLACKLIST);
             if (blacklistStr != null) {
@@ -129,7 +134,7 @@
         if (oldVersion < 4) {
             // Delay this so that we can wait for everything to be registered first.
             final int user = mCurrentUser;
-            new Handler(Dependency.get(Dependency.BG_LOOPER)).postDelayed(
+            bgHandler.postDelayed(
                     () -> clearAllFromUser(user), 5000);
         }
         setValue(TUNER_VERSION, newVersion);
@@ -176,7 +181,7 @@
         mTunableLookup.get(key).add(tunable);
         if (LeakDetector.ENABLED) {
             mTunables.add(tunable);
-            Dependency.get(LeakDetector.class).trackCollection(mTunables, "TunerService.mTunables");
+            mLeakDetector.trackCollection(mTunables, "TunerService.mTunables");
         }
         Uri uri = Settings.Secure.getUriFor(key);
         if (!mListeningUris.containsKey(uri)) {
diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
index e458e63..59aa522 100644
--- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
@@ -24,6 +24,7 @@
 import android.view.View;
 
 import com.android.systemui.SystemUIFactory;
+import com.android.systemui.qs.QSFooterImpl;
 import com.android.systemui.qs.QuickStatusBarHeader;
 
 import java.lang.reflect.InvocationTargetException;
@@ -107,6 +108,10 @@
          * Creates the QuickStatusBarHeader.
          */
         QuickStatusBarHeader createQsHeader();
+        /**
+         * Creates the QSFooterImpl.
+         */
+        QSFooterImpl createQsFooter();
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
index 7bc9626..b590e77 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
@@ -43,9 +43,9 @@
 import android.util.Log;
 import android.util.LongSparseArray;
 
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
+import com.android.systemui.SystemUIFactory;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
@@ -346,9 +346,10 @@
         private final GarbageMonitor gm;
         private ProcessMemInfo pmi;
 
+        @Inject
         public MemoryTile(QSHost host) {
             super(host);
-            gm = Dependency.get(GarbageMonitor.class);
+            gm = SystemUIFactory.getInstance().getRootComponent().createGarbageMonitor();
         }
 
         @Override
@@ -453,7 +454,8 @@
                     Settings.Secure.getInt(
                                     mContext.getContentResolver(), FORCE_ENABLE_LEAK_REPORTING, 0)
                             != 0;
-            mGarbageMonitor = Dependency.get(GarbageMonitor.class);
+            mGarbageMonitor = SystemUIFactory.getInstance().getRootComponent()
+                   .createGarbageMonitor();
             if (LEAK_REPORTING_ENABLED || forceEnable) {
                 mGarbageMonitor.startLeakMonitor();
             }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 16ef63f..8f2b2d0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -144,8 +144,7 @@
 
         TestableBubbleController(Context context,
                 StatusBarWindowController statusBarWindowController) {
-            super(context);
-            mStatusBarWindowController = statusBarWindowController;
+            super(context, statusBarWindowController);
         }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/LockScreenWakeUpControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/LockScreenWakeUpControllerTest.java
deleted file mode 100644
index 8963b59..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/LockScreenWakeUpControllerTest.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * 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.doze;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.os.Handler;
-import android.os.PowerManager;
-import android.support.test.filters.SmallTest;
-
-import com.android.internal.hardware.AmbientDisplayConfiguration;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.plugins.SensorManagerPlugin;
-import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.StatusBarStateController;
-import com.android.systemui.util.AsyncSensorManager;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(JUnit4.class)
-@SmallTest
-public class LockScreenWakeUpControllerTest extends SysuiTestCase {
-
-    @Mock
-    private AsyncSensorManager mAsyncSensorManager;
-    @Mock
-    private SensorManagerPlugin.Sensor mSensor;
-    @Mock
-    private AmbientDisplayConfiguration mAmbientDisplayConfiguration;
-    @Mock
-    private PowerManager mPowerManager;
-    @Mock
-    private DozeHost mDozeHost;
-    @Mock
-    private StatusBarStateController mStatusBarStateController;
-    @Mock
-    private Handler mHandler;
-
-    private LockScreenWakeUpController mLockScreenWakeUpController;
-
-    @Before
-    public void setup() {
-        MockitoAnnotations.initMocks(this);
-        doAnswer(invocation -> {
-            ((Runnable) invocation.getArgument(0)).run();
-            return null;
-        }).when(mHandler).post(any());
-
-        mLockScreenWakeUpController = new LockScreenWakeUpController(mAsyncSensorManager, mSensor,
-                mAmbientDisplayConfiguration, mPowerManager, mDozeHost, mStatusBarStateController,
-                mHandler);
-    }
-
-    @Test
-    public void testOnStateChanged_registersUnregistersListener() {
-        when(mAmbientDisplayConfiguration.wakeLockScreenGestureEnabled(anyInt())).thenReturn(true);
-        mLockScreenWakeUpController.onStateChanged(StatusBarState.KEYGUARD);
-        mLockScreenWakeUpController.onStateChanged(StatusBarState.SHADE);
-
-        verify(mAsyncSensorManager, times(1)).registerPluginListener(eq(mSensor),
-                eq(mLockScreenWakeUpController));
-
-        mLockScreenWakeUpController.onStateChanged(StatusBarState.SHADE);
-        verify(mAsyncSensorManager).unregisterPluginListener(eq(mSensor),
-                eq(mLockScreenWakeUpController));
-    }
-
-    @Test
-    public void testOnStateChanged_disabledSensor() {
-        when(mAmbientDisplayConfiguration.wakeLockScreenGestureEnabled(anyInt()))
-                .thenReturn(false);
-        mLockScreenWakeUpController.onStateChanged(StatusBarState.KEYGUARD);
-        mLockScreenWakeUpController.onStateChanged(StatusBarState.SHADE);
-
-        verify(mAsyncSensorManager, never()).registerPluginListener(eq(mSensor),
-                eq(mLockScreenWakeUpController));
-    }
-
-    @Test
-    public void testOnSensorChanged_postsToMainThread() {
-        SensorManagerPlugin.SensorEvent event = new SensorManagerPlugin.SensorEvent(mSensor, 0);
-        mLockScreenWakeUpController.onSensorChanged(event);
-
-        verify(mHandler).post(any());
-    }
-
-    @Test
-    public void testOnSensorChanged_wakeUpWhenDozing() {
-        SensorManagerPlugin.SensorEvent event =
-                new SensorManagerPlugin.SensorEvent(mSensor, 0, new float[] {1});
-        mLockScreenWakeUpController.onSensorChanged(event);
-        verify(mPowerManager, never()).wakeUp(anyLong(), any());
-
-        mLockScreenWakeUpController.onDozingChanged(true);
-        mLockScreenWakeUpController.onSensorChanged(event);
-        verify(mPowerManager).wakeUp(anyLong(), any());
-    }
-
-    @Test
-    public void testOnSensorChanged_sleepsWhenAwake() {
-        boolean[] goToSleep = new boolean[] {false};
-        doAnswer(invocation -> goToSleep[0] = true)
-                .when(mPowerManager).goToSleep(anyLong(), anyInt(), anyInt());
-        SensorManagerPlugin.SensorEvent event =
-                new SensorManagerPlugin.SensorEvent(mSensor, 0, new float[] {0});
-        mLockScreenWakeUpController.onDozingChanged(true);
-        mLockScreenWakeUpController.onSensorChanged(event);
-        Assert.assertFalse("goToSleep should have never been called.", goToSleep[0]);
-
-        mLockScreenWakeUpController.onDozingChanged(false);
-        mLockScreenWakeUpController.onSensorChanged(event);
-        Assert.assertTrue("goToSleep should have been called.", goToSleep[0]);
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index 45e49df..2cb326e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -21,6 +21,7 @@
 import android.app.Fragment;
 import android.content.Context;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.Looper;
 import android.support.test.filters.SmallTest;
 import android.testing.AndroidTestingRunner;
@@ -36,10 +37,14 @@
 import com.android.systemui.R;
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.SysuiBaseFragmentTest;
+import com.android.systemui.qs.tileimpl.QSFactoryImpl;
+import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.policy.Clock;
+import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.tuner.TunerService;
 import com.android.systemui.util.InjectionInflationController;
 
 import org.junit.Before;
@@ -85,7 +90,9 @@
         QSFragment qs = (QSFragment) mFragment;
         mFragments.dispatchResume();
         processAllMessages();
-        QSTileHost host = new QSTileHost(mContext, null, mock(StatusBarIconController.class));
+        QSTileHost host = new QSTileHost(mContext, mock(StatusBarIconController.class),
+                mock(QSFactoryImpl.class), new Handler(), Looper.myLooper(),
+                mock(PluginManager.class), mock(TunerService.class));
         qs.setHost(host);
 
         qs.setListening(true);
@@ -124,8 +131,10 @@
 
     @Override
     protected Fragment instantiate(Context context, String className, Bundle arguments) {
-        return new QSFragment(new RemoteInputQuickSettingsDisabler(context),
+        return new QSFragment(
+                new RemoteInputQuickSettingsDisabler(context, mock(ConfigurationController.class)),
                 new InjectionInflationController(SystemUIFactory.getInstance().getRootComponent()),
-                context);
+                context,
+                mock(QSTileHost.class));
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
index c6597b9..63f4bbc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
@@ -21,6 +21,7 @@
 import static org.mockito.Mockito.mock;
 
 import android.content.ComponentName;
+import android.os.Handler;
 import android.os.Looper;
 import android.service.quicksettings.Tile;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -30,8 +31,11 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.tileimpl.QSFactoryImpl;
+import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.tuner.TunerService;
 
 import org.junit.After;
 import org.junit.Before;
@@ -55,8 +59,13 @@
     public void setUp() throws Exception {
         mDependency.injectMockDependency(BluetoothController.class);
         mManagers = new ArrayList<>();
-        QSTileHost host = new QSTileHost(mContext, null,
-                mock(StatusBarIconController.class));
+        QSTileHost host = new QSTileHost(mContext,
+                mock(StatusBarIconController.class),
+                mock(QSFactoryImpl.class),
+                new Handler(),
+                Looper.myLooper(),
+                mock(PluginManager.class),
+                mock(TunerService.class));
         mTileService = new TestTileServices(host, Looper.getMainLooper());
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
index d9412ec..efcbb76 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
@@ -15,8 +15,8 @@
 package com.android.systemui.qs.tiles;
 
 import static junit.framework.TestCase.assertEquals;
-import static junit.framework.TestCase.assertTrue;
 
+import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -26,6 +26,8 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import androidx.lifecycle.LifecycleOwner;
+
 import com.android.systemui.Dependency;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.ActivityStarter;
@@ -79,7 +81,8 @@
 
         when(mHost.getContext()).thenReturn(mContext);
 
-        mCastTile = new CastTile(mHost);
+        mCastTile = new CastTile(mHost, mController, mKeyguard, mNetworkController,
+                mActivityStarter);
 
         // We are not setting the mocks to listening, so we trigger a first refresh state to
         // set the initial state
@@ -88,7 +91,8 @@
         mCastTile.handleSetListening(true);
         ArgumentCaptor<NetworkController.SignalCallback> signalCallbackArgumentCaptor =
                 ArgumentCaptor.forClass(NetworkController.SignalCallback.class);
-        verify(mNetworkController).addCallback(signalCallbackArgumentCaptor.capture());
+        verify(mNetworkController).observe(any(LifecycleOwner.class),
+                signalCallbackArgumentCaptor.capture());
         mCallback = signalCallbackArgumentCaptor.getValue();
 
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/SensorPrivacyTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/SensorPrivacyTileTest.java
index 90792e3..751a616 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/SensorPrivacyTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/SensorPrivacyTileTest.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs.tiles;
 
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -27,6 +28,7 @@
 
 import com.android.systemui.Dependency;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 
@@ -64,7 +66,8 @@
 
         when(mHost.getContext()).thenReturn(mContext);
 
-        mSensorPrivacyTile = new SensorPrivacyTile(mHost);
+        mSensorPrivacyTile = new SensorPrivacyTile(mHost, mSensorPrivacyManager, mKeyguard,
+                mock(ActivityStarter.class));
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
index 14e611a..1244310 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
@@ -70,9 +70,9 @@
         MockitoAnnotations.initMocks(this);
         mDependency.injectTestDependency(NotificationEntryManager.class,
                 mNotificationEntryManager);
-        mDependency.injectTestDependency(IStatusBarService.class, mIStatusBarService);
 
-        mSmartReplyController = new SmartReplyController();
+        mSmartReplyController = new SmartReplyController(mNotificationEntryManager,
+                mIStatusBarService);
         mDependency.injectTestDependency(SmartReplyController.class,
                 mSmartReplyController);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
index 512acd0..caa3ca6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
@@ -19,6 +19,7 @@
 import static org.junit.Assert.assertArrayEquals;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -36,9 +37,12 @@
 
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.Dependency;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.UiOffloadThread;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationPresenter;
+import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -91,7 +95,8 @@
         mEntry = new NotificationData.Entry(mSbn);
         mEntry.setRow(mRow);
 
-        mLogger = new TestableNotificationLogger(mBarService);
+        mLogger = new TestableNotificationLogger(mListener, Dependency.get(UiOffloadThread.class),
+                mEntryManager, mock(StatusBarStateController.class), mBarService);
         mLogger.setUpWithContainer(mListContainer);
     }
 
@@ -153,7 +158,12 @@
 
     private class TestableNotificationLogger extends NotificationLogger {
 
-        public TestableNotificationLogger(IStatusBarService barService) {
+        public TestableNotificationLogger(NotificationListener notificationListener,
+                UiOffloadThread uiOffloadThread,
+                NotificationEntryManager entryManager,
+                StatusBarStateController statusBarStateController,
+                IStatusBarService barService) {
+            super(notificationListener, uiOffloadThread, entryManager, statusBarStateController);
             mBarService = barService;
             // Make this on the current thread so we can wait for it during tests.
             mHandler = Handler.createAsync(Looper.myLooper());
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 728723b..babd452 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
@@ -40,7 +40,6 @@
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -105,7 +104,7 @@
     @Override
     protected Fragment instantiate(Context context, String className, Bundle arguments) {
         DeviceProvisionedController deviceProvisionedController =
-                new DeviceProvisionedControllerImpl(context);
+                mock(DeviceProvisionedController.class);
         assertNotNull(mAccessibilityWrapper);
         return new NavigationBarFragment(mAccessibilityWrapper,
                 deviceProvisionedController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 0bc304e..146c5d6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -220,9 +220,9 @@
         mScrimController.transitionTo(ScrimState.PULSING);
         mScrimController.finishAnimationsImmediately();
         // Front scrim should be transparent
-        // Back scrim should be visible with tint
+        // Back scrim should be semi-transparent so the user can see the wallpaper
         // Pulse callback should have been invoked
-        assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_OPAQUE);
+        assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_SEMI_TRANSPARENT);
         assertScrimTint(mScrimBehind, true /* tinted */);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index c584d02..fd795e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -68,6 +68,7 @@
 import com.android.systemui.InitController;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.UiOffloadThread;
 import com.android.systemui.appops.AppOpsController;
 import com.android.systemui.appops.AppOpsControllerImpl;
 import com.android.systemui.assist.AssistManager;
@@ -195,8 +196,10 @@
 
         mMetricsLogger = new FakeMetricsLogger();
         mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
+        mEntryManager = new TestableNotificationEntryManager(mPowerManager, mContext);
+        mNotificationLogger = new NotificationLogger(mNotificationListener,
+                Dependency.get(UiOffloadThread.class), mEntryManager, mStatusBarStateController);
         mDependency.injectTestDependency(NotificationLogger.class, mNotificationLogger);
-        mNotificationLogger = new NotificationLogger();
         DozeLog.traceDozing(mContext, false /* dozing */);
 
         mCommandQueue = mock(CommandQueue.class);
@@ -225,7 +228,6 @@
         mNotificationInterruptionStateProvider.setUpWithPresenter(mNotificationPresenter,
                 mHeadsUpManager, mHeadsUpSuppressor);
 
-        mEntryManager = new TestableNotificationEntryManager(mPowerManager, mContext);
         when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
         mStatusBar = new TestableStatusBar(mStatusBarKeyguardViewManager, mUnlockMethodCache,
                 mKeyguardIndicationController, mStackScroller, mHeadsUpManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java
index d54c295..e626d08 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.policy;
 
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import android.content.Intent;
@@ -26,6 +27,7 @@
 import android.testing.TestableLooper;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.power.EnhancedEstimates;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -47,7 +49,8 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mBatteryController = new BatteryControllerImpl(getContext(), mPowerManager);
+        mBatteryController = new BatteryControllerImpl(getContext(), mock(EnhancedEstimates.class),
+                mPowerManager);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
index d246350..b65b0f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
@@ -74,7 +74,8 @@
                 .thenReturn(mock(LocalBluetoothProfileManager.class));
 
         mBluetoothControllerImpl = new BluetoothControllerImpl(mContext,
-                mTestableLooper.getLooper());
+                mTestableLooper.getLooper(),
+                mMockBluetoothManager);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.java
index 3b47eae..e3a41be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.java
@@ -29,6 +29,7 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.policy.ConfigurationController;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -49,7 +50,8 @@
         mCommandQueue = mock(CommandQueue.class);
         mContext.putComponent(CommandQueue.class, mCommandQueue);
 
-        mRemoteInputQuickSettingsDisabler = new RemoteInputQuickSettingsDisabler(mContext);
+        mRemoteInputQuickSettingsDisabler = new RemoteInputQuickSettingsDisabler(mContext,
+                mock(ConfigurationController.class));
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
index f76de5a..3ac42de 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
@@ -39,6 +39,8 @@
 import android.net.ConnectivityManager.NetworkCallback;
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
+import android.os.Handler;
+import android.os.Looper;
 import android.os.UserManager;
 import android.security.IKeyChainService;
 import android.support.test.runner.AndroidJUnit4;
@@ -98,7 +100,10 @@
         // Wait for callbacks from 1) the CACertLoader and 2) the onUserSwitched() function in the
         // constructor of mSecurityController
         mStateChangedLatch = new CountDownLatch(2);
-        mSecurityController = new SecurityControllerImpl(mContext, this);
+        // TODO: Migrate this test to TestableLooper and use a handler attached
+        // to that.
+        mSecurityController = new SecurityControllerImpl(mContext,
+                new Handler(Looper.getMainLooper()), this);
     }
 
     @After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/tuner/TunablePaddingTest.java b/packages/SystemUI/tests/src/com/android/systemui/tuner/TunablePaddingTest.java
index 3bfefe7..1e27915 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/tuner/TunablePaddingTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/tuner/TunablePaddingTest.java
@@ -48,7 +48,9 @@
         mView = mock(View.class);
         when(mView.getContext()).thenReturn(mContext);
 
-        mTunerService = mDependency.injectMockDependency(TunerService.class);
+        mTunerService = mock(TunerService.class);
+        mDependency.injectTestDependency(TunablePadding.TunablePaddingService.class,
+                new TunablePadding.TunablePaddingService(mTunerService));
         Tracker tracker = mLeakCheck.getTracker("tuner");
         doAnswer(invocation -> {
             tracker.getLeakInfo(invocation.getArguments()[0]).addAllocation(new Throwable());
@@ -118,4 +120,4 @@
 
         mTunablePadding.destroy();
     }
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index dd4afaf..ad08861 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -179,6 +179,7 @@
 import java.security.InvalidParameterException;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Date;
 import java.util.List;
@@ -3077,10 +3078,10 @@
         }
     }
 
-    @Override
-    public void setInputMethod(IBinder token, String id) {
+    @BinderThread
+    private void setInputMethod(IBinder token, String id) {
         synchronized (mMethodMap) {
-            if (!calledFromValidUserLocked()) {
+            if (!calledWithValidTokenLocked(token)) {
                 return;
             }
             setInputMethodWithSubtypeIdLocked(token, id, NOT_A_SUBTYPE_ID);
@@ -4587,6 +4588,25 @@
             @Nullable FileDescriptor err,
             @NonNull String[] args, @Nullable ShellCallback callback,
             @NonNull ResultReceiver resultReceiver) throws RemoteException {
+        final int callingUid = Binder.getCallingUid();
+        // Reject any incoming calls from non-shell users, including ones from the system user.
+        if (callingUid != Process.ROOT_UID && callingUid != Process.SHELL_UID) {
+            // Note that Binder#onTransact() will automatically close "in", "out", and "err" when
+            // returned from this method, hence there is no need to close those FDs.
+            // "resultReceiver" is the only thing that needs to be taken care of here.
+            if (resultReceiver != null) {
+                resultReceiver.send(ShellCommandResult.FAILURE, null);
+            }
+            final String errorMsg = "InputMethodManagerService does not support shell commands from"
+                    + " non-shell users. callingUid=" + callingUid
+                    + " args=" + Arrays.toString(args);
+            if (Process.isCoreUid(callingUid)) {
+                // Let's not crash the calling process if the caller is one of core components.
+                Slog.e(TAG, errorMsg);
+                return;
+            }
+            throw new SecurityException(errorMsg);
+        }
         new ShellCommandImpl(this).exec(
                 this, in, out, err, args, callback, resultReceiver);
     }
@@ -4599,10 +4619,30 @@
             mService = service;
         }
 
+        @RequiresPermission(allOf = {
+                Manifest.permission.WRITE_SECURE_SETTINGS,
+                Manifest.permission.INTERACT_ACROSS_USERS_FULL})
         @BinderThread
         @ShellCommandResult
         @Override
         public int onCommand(@Nullable String cmd) {
+            // For shell command, require all the permissions here in favor of code simplicity.
+            mService.mContext.enforceCallingPermission(
+                    Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
+            mService.mContext.enforceCallingPermission(
+                    Manifest.permission.WRITE_SECURE_SETTINGS, null);
+
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                return onCommandWithSystemIdentity(cmd);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @BinderThread
+        @ShellCommandResult
+        private int onCommandWithSystemIdentity(@Nullable String cmd) {
             if ("refresh_debug_properties".equals(cmd)) {
                 return refreshDebugProperties();
             }
@@ -4747,25 +4787,13 @@
      */
     @BinderThread
     @ShellCommandResult
-    @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
     private int handleShellCommandEnableDisableInputMethod(
             @NonNull ShellCommand shellCommand, boolean enabled) {
         final String id = shellCommand.getNextArgRequired();
 
         final boolean previouslyEnabled;
         synchronized (mMethodMap) {
-            if (!calledFromValidUserLocked()) {
-                shellCommand.getErrPrintWriter().print("Must be called from the foreground user or"
-                        + " with INTERACT_ACROSS_USERS_FULL");
-                return ShellCommandResult.FAILURE;
-            }
-            mContext.enforceCallingPermission(Manifest.permission.WRITE_SECURE_SETTINGS, null);
-            final long ident = Binder.clearCallingIdentity();
-            try {
-                previouslyEnabled = setInputMethodEnabledLocked(id, enabled);
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
+            previouslyEnabled = setInputMethodEnabledLocked(id, enabled);
         }
         final PrintWriter pr = shellCommand.getOutPrintWriter();
         pr.print("Input method ");
@@ -4785,7 +4813,9 @@
     @ShellCommandResult
     private int handleShellCommandSetInputMethod(@NonNull ShellCommand shellCommand) {
         final String id = shellCommand.getNextArgRequired();
-        setInputMethod(null, id);
+        synchronized (mMethodMap) {
+            setInputMethodLocked(id, NOT_A_SUBTYPE_ID);
+        }
         final PrintWriter pr = shellCommand.getOutPrintWriter();
         pr.print("Input method ");
         pr.print(id);
@@ -4800,55 +4830,29 @@
      */
     @BinderThread
     @ShellCommandResult
-    @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
     private int handleShellCommandResetInputMethod(@NonNull ShellCommand shellCommand) {
         synchronized (mMethodMap) {
-            if (!calledFromValidUserLocked()) {
-                shellCommand.getErrPrintWriter().print("Must be called from the foreground user or"
-                        + " with INTERACT_ACROSS_USERS_FULL");
-                return ShellCommandResult.FAILURE;
-            }
-            mContext.enforceCallingPermission(Manifest.permission.WRITE_SECURE_SETTINGS, null);
             final String nextIme;
             final List<InputMethodInfo> nextEnabledImes;
-            final long ident = Binder.clearCallingIdentity();
-            try {
-                synchronized (mMethodMap) {
-                    hideCurrentInputLocked(0, null);
-                    unbindCurrentMethodLocked();
-                    // Reset the current IME
-                    resetSelectedInputMethodAndSubtypeLocked(null);
-                    // Also reset the settings of the current IME
-                    mSettings.putSelectedInputMethod(null);
-                    // Disable all enabled IMEs.
-                    {
-                        final ArrayList<InputMethodInfo> enabledImes =
-                                mSettings.getEnabledInputMethodListLocked();
-                        final int N = enabledImes.size();
-                        for (int i = 0; i < N; ++i) {
-                            setInputMethodEnabledLocked(enabledImes.get(i).getId(), false);
-                        }
-                    }
-                    // Re-enable with default enabled IMEs.
-                    {
-                        final ArrayList<InputMethodInfo> defaultEnabledIme =
-                                InputMethodUtils.getDefaultEnabledImes(mContext, mMethodList);
-                        final int N = defaultEnabledIme.size();
-                        for (int i = 0; i < N; ++i) {
-                            setInputMethodEnabledLocked(defaultEnabledIme.get(i).getId(), true);
-                        }
-                    }
-                    updateInputMethodsFromSettingsLocked(true /* enabledMayChange */);
-                    InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
-                            mSettings.getEnabledInputMethodListLocked(),
-                            mSettings.getCurrentUserId(),
-                            mContext.getBasePackageName());
-                    nextIme = mSettings.getSelectedInputMethod();
-                    nextEnabledImes = getEnabledInputMethodList();
-                }
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
+            hideCurrentInputLocked(0, null);
+            unbindCurrentMethodLocked();
+            // Reset the current IME
+            resetSelectedInputMethodAndSubtypeLocked(null);
+            // Also reset the settings of the current IME
+            mSettings.putSelectedInputMethod(null);
+            // Disable all enabled IMEs.
+            mSettings.getEnabledInputMethodListLocked().forEach(
+                    imi -> setInputMethodEnabledLocked(imi.getId(), false));
+            // Re-enable with default enabled IMEs.
+            InputMethodUtils.getDefaultEnabledImes(mContext, mMethodList).forEach(
+                    imi -> setInputMethodEnabledLocked(imi.getId(), true));
+            updateInputMethodsFromSettingsLocked(true /* enabledMayChange */);
+            InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
+                    mSettings.getEnabledInputMethodListLocked(),
+                    mSettings.getCurrentUserId(),
+                    mContext.getBasePackageName());
+            nextIme = mSettings.getSelectedInputMethod();
+            nextEnabledImes = getEnabledInputMethodList();
             final PrintWriter pr = shellCommand.getOutPrintWriter();
             pr.println("Reset current and enabled IMEs");
             pr.println("Newly selected IME:");
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index ffe14d9..98ed3ea 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -1513,12 +1513,6 @@
 
         @BinderThread
         @Override
-        public void setInputMethod(IBinder token, String id) {
-            reportNotSupported();
-        }
-
-        @BinderThread
-        @Override
         public void registerSuggestionSpansForNotification(SuggestionSpan[] suggestionSpans) {
             reportNotSupported();
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 90619e2..2ef3315 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -15461,10 +15461,15 @@
         return result;
     }
 
+    /**
+     * Compare the newly scanned package with current system state to see which of its declared
+     * shared libraries should be allowed to be added to the system.
+     */
     private static List<SharedLibraryInfo> getAllowedSharedLibInfos(
             ScanResult scanResult,
             Map<String, LongSparseArray<SharedLibraryInfo>> existingSharedLibraries) {
-        final PackageParser.Package pkg = scanResult.pkgSetting.pkg;
+        // Let's used the parsed package as scanResult.pkgSetting may be null
+        final PackageParser.Package pkg = scanResult.request.pkg;
         if (scanResult.staticSharedLibraryInfo == null
                 && scanResult.dynamicSharedLibraryInfos == null) {
             return null;
@@ -15496,8 +15501,12 @@
                 // have allowed apps on the device which aren't compatible
                 // with it.  Better to just have the restriction here, be
                 // conservative, and create many fewer cases that can negatively
-                // impact the user experience.
-                final PackageSetting sysPs = scanResult.request.disabledPkgSetting;
+                // impact the user experience. We may not yet have disabled the
+                // updated package yet, so be sure to grab the current setting if
+                // that's the case.
+                final PackageSetting sysPs = scanResult.request.disabledPkgSetting == null
+                        ? scanResult.request.oldPkgSetting
+                        : scanResult.request.disabledPkgSetting;
                 if (sysPs.pkg != null && sysPs.pkg.libraryNames != null) {
                     for (int j = 0; j < sysPs.pkg.libraryNames.size(); j++) {
                         if (name.equals(sysPs.pkg.libraryNames.get(j))) {
diff --git a/services/core/java/com/android/server/security/VerityUtils.java b/services/core/java/com/android/server/security/VerityUtils.java
index 514dfed..667d21d 100644
--- a/services/core/java/com/android/server/security/VerityUtils.java
+++ b/services/core/java/com/android/server/security/VerityUtils.java
@@ -16,13 +16,11 @@
 
 package com.android.server.security;
 
-import static android.system.OsConstants.PROT_READ;
-import static android.system.OsConstants.PROT_WRITE;
-
 import android.annotation.NonNull;
 import android.os.SharedMemory;
 import android.system.ErrnoException;
 import android.system.Os;
+import android.system.OsConstants;
 import android.util.Pair;
 import android.util.Slog;
 import android.util.apk.ApkSignatureVerifier;
@@ -56,6 +54,21 @@
 
     private static final boolean DEBUG = false;
 
+    /** Returns whether the file has fs-verity enabled. */
+    public static boolean hasFsverity(@NonNull String filePath) {
+        // NB: only measure but not check the actual measurement here. As long as this succeeds,
+        // the file is on readable if the measurement can be verified against a trusted key, and
+        // this is good enough for installed apps.
+        int errno = measureFsverityNative(filePath);
+        if (errno != 0) {
+            if (errno != OsConstants.ENODATA) {
+                Slog.e(TAG, "Failed to measure fs-verity, errno " + errno + ": " + filePath);
+            }
+            return false;
+        }
+        return true;
+    }
+
     /**
      * Generates Merkle tree and fs-verity metadata.
      *
@@ -213,6 +226,7 @@
         return md.digest();
     }
 
+    private static native int measureFsverityNative(@NonNull String filePath);
     private static native byte[] constructFsveritySignedDataNative(@NonNull byte[] measurement);
     private static native byte[] constructFsverityDescriptorNative(long fileSize);
     private static native byte[] constructFsverityExtensionNative(short extensionId,
@@ -249,7 +263,7 @@
         if (shm == null) {
             throw new IllegalStateException("Failed to generate verity tree into shared memory");
         }
-        if (!shm.setProtect(PROT_READ)) {
+        if (!shm.setProtect(OsConstants.PROT_READ)) {
             throw new SecurityException("Failed to set up shared memory correctly");
         }
         return Pair.create(shm, contentSize);
@@ -323,7 +337,7 @@
                     throw new IllegalStateException("Multiple instantiation from this factory");
                 }
                 mShm = SharedMemory.create("apkverity", capacity);
-                if (!mShm.setProtect(PROT_READ | PROT_WRITE)) {
+                if (!mShm.setProtect(OsConstants.PROT_READ | OsConstants.PROT_WRITE)) {
                     throw new SecurityException("Failed to set protection");
                 }
                 mBuffer = mShm.mapReadWrite();
diff --git a/services/core/jni/com_android_server_security_VerityUtils.cpp b/services/core/jni/com_android_server_security_VerityUtils.cpp
index ec94e3c9..3c87e42 100644
--- a/services/core/jni/com_android_server_security_VerityUtils.cpp
+++ b/services/core/jni/com_android_server_security_VerityUtils.cpp
@@ -20,13 +20,22 @@
 #include "jni.h"
 #include <utils/Log.h>
 
+#include <errno.h>
+#include <fcntl.h>
 #include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <android-base/unique_fd.h>
 
 // TODO(112037636): Always include once fsverity.h is upstreamed and backported.
 #define HAS_FSVERITY 0
 
 #if HAS_FSVERITY
 #include <linux/fsverity.h>
+
+const int kSha256Bytes = 32;
 #endif
 
 namespace android {
@@ -66,9 +75,26 @@
     jbyte* mElements;
 };
 
+int measureFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath) {
+#if HAS_FSVERITY
+    auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_digest) + kSha256Bytes);
+    fsverity_digest* data = reinterpret_cast<fsverity_digest*>(raii->getRaw());
+    data->digest_size = kSha256Bytes;  // the only input/output parameter
+
+    const char* path = env->GetStringUTFChars(filePath, nullptr);
+    ::android::base::unique_fd rfd(open(path, O_RDONLY));
+    if (ioctl(rfd.get(), FS_IOC_MEASURE_VERITY, data) < 0) {
+      return errno;
+    }
+    return 0;
+#else
+    LOG_ALWAYS_FATAL("fs-verity is used while not enabled");
+    return -1;
+#endif  // HAS_FSVERITY
+}
+
 jbyteArray constructFsveritySignedData(JNIEnv* env, jobject /* clazz */, jbyteArray digest) {
 #if HAS_FSVERITY
-    const int kSha256Bytes = 32;
     auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_digest_disk) + kSha256Bytes);
     fsverity_digest_disk* data = reinterpret_cast<fsverity_digest_disk*>(raii->getRaw());
 
@@ -146,6 +172,7 @@
 }
 
 const JNINativeMethod sMethods[] = {
+    { "measureFsverityNative", "(Ljava/lang/String;)I", (void *)measureFsverity },
     { "constructFsveritySignedDataNative", "([B)[B", (void *)constructFsveritySignedData },
     { "constructFsverityDescriptorNative", "(J)[B", (void *)constructFsverityDescriptor },
     { "constructFsverityExtensionNative", "(SI)[B", (void *)constructFsverityExtension },
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 1862636..333b3e3 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1264,6 +1264,16 @@
             }
             traceEnd();
 
+            traceBeginAndSlog("StartNetworkStack");
+            try {
+                final android.net.NetworkStack networkStack =
+                        context.getSystemService(android.net.NetworkStack.class);
+                networkStack.start(context);
+            } catch (Throwable e) {
+                reportWtf("starting Network Stack", e);
+            }
+            traceEnd();
+
             traceBeginAndSlog("StartNsdService");
             try {
                 serviceDiscovery = NsdService.create(context);
diff --git a/telephony/java/android/telephony/CellIdentityCdma.java b/telephony/java/android/telephony/CellIdentityCdma.java
index 598f567..fa19867 100644
--- a/telephony/java/android/telephony/CellIdentityCdma.java
+++ b/telephony/java/android/telephony/CellIdentityCdma.java
@@ -16,7 +16,6 @@
 
 package android.telephony;
 
-import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.telephony.cdma.CdmaCellLocation;
 
@@ -71,30 +70,13 @@
      *        to 2592000
      * @param lat Latitude is a decimal number ranges from -1296000
      *        to 1296000
-     *
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public CellIdentityCdma(int nid, int sid, int bid, int lon, int lat) {
-        this(nid, sid, bid, lon, lat, null, null);
-    }
-
-    /**
-     * public constructor
-     * @param nid Network Id 0..65535
-     * @param sid CDMA System Id 0..32767
-     * @param bid Base Station Id 0..65535
-     * @param lon Longitude is a decimal number ranges from -2592000
-     *        to 2592000
-     * @param lat Latitude is a decimal number ranges from -1296000
-     *        to 1296000
      * @param alphal long alpha Operator Name String or Enhanced Operator Name String
      * @param alphas short alpha Operator Name String or Enhanced Operator Name String
      *
      * @hide
      */
-    public CellIdentityCdma(int nid, int sid, int bid, int lon, int lat, String alphal,
-                             String alphas) {
+    public CellIdentityCdma(
+            int nid, int sid, int bid, int lon, int lat, String alphal, String alphas) {
         super(TAG, CellInfo.TYPE_CDMA, null, null, alphal, alphas);
         mNetworkId = nid;
         mSystemId = sid;
@@ -107,6 +89,17 @@
         }
     }
 
+    /** @hide */
+    public CellIdentityCdma(android.hardware.radio.V1_0.CellIdentityCdma cid) {
+        this(cid.networkId, cid.systemId, cid.baseStationId, cid.longitude, cid.latitude, "", "");
+    }
+
+    /** @hide */
+    public CellIdentityCdma(android.hardware.radio.V1_2.CellIdentityCdma cid) {
+        this(cid.base.networkId, cid.base.systemId, cid.base.baseStationId, cid.base.longitude,
+                cid.base.latitude, cid.operatorNames.alphaLong, cid.operatorNames.alphaShort);
+    }
+
     private CellIdentityCdma(CellIdentityCdma cid) {
         this(cid.mNetworkId, cid.mSystemId, cid.mBasestationId, cid.mLongitude, cid.mLatitude,
                 cid.mAlphaLong, cid.mAlphaShort);
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index c8a899b..9a24e47 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -36,10 +36,8 @@
     // 16-bit GSM Cell Identity described in TS 27.007, 0..65535
     private final int mCid;
     // 16-bit GSM Absolute RF Channel Number
-    @UnsupportedAppUsage
     private final int mArfcn;
     // 6-bit Base Station Identity Code
-    @UnsupportedAppUsage
     private final int mBsic;
 
     /**
@@ -53,34 +51,6 @@
         mArfcn = CellInfo.UNAVAILABLE;
         mBsic = CellInfo.UNAVAILABLE;
     }
-    /**
-     * public constructor
-     * @param mcc 3-digit Mobile Country Code, 0..999
-     * @param mnc 2 or 3-digit Mobile Network Code, 0..999
-     * @param lac 16-bit Location Area Code, 0..65535
-     * @param cid 16-bit GSM Cell Identity or 28-bit UMTS Cell Identity
-     *
-     * @hide
-     */
-    public CellIdentityGsm(int mcc, int mnc, int lac, int cid) {
-        this(lac, cid, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
-                String.valueOf(mcc), String.valueOf(mnc), null, null);
-    }
-
-    /**
-     * public constructor
-     * @param mcc 3-digit Mobile Country Code, 0..999
-     * @param mnc 2 or 3-digit Mobile Network Code, 0..999
-     * @param lac 16-bit Location Area Code, 0..65535
-     * @param cid 16-bit GSM Cell Identity or 28-bit UMTS Cell Identity
-     * @param arfcn 16-bit GSM Absolute RF Channel Number
-     * @param bsic 6-bit Base Station Identity Code
-     *
-     * @hide
-     */
-    public CellIdentityGsm(int mcc, int mnc, int lac, int cid, int arfcn, int bsic) {
-        this(lac, cid, arfcn, bsic, String.valueOf(mcc), String.valueOf(mnc), null, null);
-    }
 
     /**
      * public constructor
@@ -101,9 +71,21 @@
         mLac = lac;
         mCid = cid;
         mArfcn = arfcn;
-        // In RIL BSIC is a UINT8, so 0xFF is the 'INVALID' designator
-        // for inbound parcels
-        mBsic = (bsic == 0xFF) ? CellInfo.UNAVAILABLE : bsic;
+        mBsic = bsic;
+    }
+
+    /** @hide */
+    public CellIdentityGsm(android.hardware.radio.V1_0.CellIdentityGsm cid) {
+        this(cid.lac, cid.cid, cid.arfcn,
+                cid.bsic == (byte) 0xFF ? CellInfo.UNAVAILABLE : cid.bsic,
+                cid.mcc, cid.mnc, "", "");
+    }
+
+    /** @hide */
+    public CellIdentityGsm(android.hardware.radio.V1_2.CellIdentityGsm cid) {
+        this(cid.base.lac, cid.base.cid, cid.base.arfcn,
+                cid.base.bsic == (byte) 0xFF ? CellInfo.UNAVAILABLE : cid.base.bsic, cid.base.mcc,
+                cid.base.mnc, cid.operatorNames.alphaLong, cid.operatorNames.alphaShort);
     }
 
     private CellIdentityGsm(CellIdentityGsm cid) {
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index 8e1877d..d957d07 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -38,7 +38,6 @@
     // 16-bit tracking area code
     private final int mTac;
     // 18-bit Absolute RF Channel Number
-    @UnsupportedAppUsage
     private final int mEarfcn;
     // cell bandwidth, in kHz
     private final int mBandwidth;
@@ -74,22 +73,6 @@
 
     /**
      *
-     * @param mcc 3-digit Mobile Country Code, 0..999
-     * @param mnc 2 or 3-digit Mobile Network Code, 0..999
-     * @param ci 28-bit Cell Identity
-     * @param pci Physical Cell Id 0..503
-     * @param tac 16-bit Tracking Area Code
-     * @param earfcn 18-bit LTE Absolute RF Channel Number
-     *
-     * @hide
-     */
-    public CellIdentityLte(int mcc, int mnc, int ci, int pci, int tac, int earfcn) {
-        this(ci, pci, tac, earfcn, CellInfo.UNAVAILABLE, String.valueOf(mcc), String.valueOf(mnc),
-                null, null);
-    }
-
-    /**
-     *
      * @param ci 28-bit Cell Identity
      * @param pci Physical Cell Id 0..503
      * @param tac 16-bit Tracking Area Code
@@ -112,6 +95,18 @@
         mBandwidth = bandwidth;
     }
 
+    /** @hide */
+    public CellIdentityLte(android.hardware.radio.V1_0.CellIdentityLte cid) {
+        this(cid.ci, cid.pci, cid.tac, cid.earfcn, CellInfo.UNAVAILABLE, cid.mcc, cid.mnc, "", "");
+    }
+
+    /** @hide */
+    public CellIdentityLte(android.hardware.radio.V1_2.CellIdentityLte cid) {
+        this(cid.base.ci, cid.base.pci, cid.base.tac, cid.base.earfcn, cid.bandwidth,
+                cid.base.mcc, cid.base.mnc, cid.operatorNames.alphaLong,
+                cid.operatorNames.alphaShort);
+    }
+
     private CellIdentityLte(CellIdentityLte cid) {
         this(cid.mCi, cid.mPci, cid.mTac, cid.mEarfcn, cid.mBandwidth, cid.mMccStr,
                 cid.mMncStr, cid.mAlphaLong, cid.mAlphaShort);
diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java
index f77c468..3814333 100644
--- a/telephony/java/android/telephony/CellIdentityTdscdma.java
+++ b/telephony/java/android/telephony/CellIdentityTdscdma.java
@@ -51,22 +51,6 @@
     }
 
     /**
-     * @param mcc 3-digit Mobile Country Code, 0..999
-     * @param mnc 2 or 3-digit Mobile Network Code, 0..999
-     * @param lac 16-bit Location Area Code, 0..65535, CellInfo.UNAVAILABLE if unknown
-     * @param cid 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, CellInfo.
-     *        UNAVAILABLE if unknown
-     * @param cpid 8-bit Cell Parameters ID described in TS 25.331, 0..127, CellInfo.UNAVAILABLE
-     *        if unknown
-     * @param uarfcn 16-bit UMTS Absolute RF Channel Number described in TS 25.101 sec. 5.4.3
-     *
-     * @hide
-     */
-    public CellIdentityTdscdma(int mcc, int mnc, int lac, int cid, int cpid, int uarfcn) {
-        this(String.valueOf(mcc), String.valueOf(mnc), lac, cid, cpid, uarfcn, null, null);
-    }
-
-    /**
      * @param mcc 3-digit Mobile Country Code in string format
      * @param mnc 2 or 3-digit Mobile Network Code in string format
      * @param lac 16-bit Location Area Code, 0..65535, CellInfo.UNAVAILABLE if unknown
@@ -94,6 +78,17 @@
                 cid.mCpid, cid.mUarfcn, cid.mAlphaLong, cid.mAlphaShort);
     }
 
+    /** @hide */
+    public CellIdentityTdscdma(android.hardware.radio.V1_0.CellIdentityTdscdma cid) {
+        this(cid.mcc, cid.mnc, cid.lac, cid.cid, cid.cpid, CellInfo.UNAVAILABLE, "", "");
+    }
+
+    /** @hide */
+    public CellIdentityTdscdma(android.hardware.radio.V1_2.CellIdentityTdscdma cid) {
+        this(cid.base.mcc, cid.base.mnc, cid.base.lac, cid.base.cid, cid.base.cpid,
+                cid.uarfcn, cid.operatorNames.alphaLong, cid.operatorNames.alphaShort);
+    }
+
     CellIdentityTdscdma copy() {
         return new CellIdentityTdscdma(this);
     }
diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java
index 31f9e6d..6e09784 100644
--- a/telephony/java/android/telephony/CellIdentityWcdma.java
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -51,35 +51,6 @@
         mPsc = CellInfo.UNAVAILABLE;
         mUarfcn = CellInfo.UNAVAILABLE;
     }
-    /**
-     * public constructor
-     * @param mcc 3-digit Mobile Country Code, 0..999
-     * @param mnc 2 or 3-digit Mobile Network Code, 0..999
-     * @param lac 16-bit Location Area Code, 0..65535
-     * @param cid 28-bit UMTS Cell Identity
-     * @param psc 9-bit UMTS Primary Scrambling Code
-     *
-     * @hide
-     */
-    public CellIdentityWcdma (int mcc, int mnc, int lac, int cid, int psc) {
-        this(lac, cid, psc, CellInfo.UNAVAILABLE, String.valueOf(mcc), String.valueOf(mnc),
-                null, null);
-    }
-
-    /**
-     * public constructor
-     * @param mcc 3-digit Mobile Country Code, 0..999
-     * @param mnc 2 or 3-digit Mobile Network Code, 0..999
-     * @param lac 16-bit Location Area Code, 0..65535
-     * @param cid 28-bit UMTS Cell Identity
-     * @param psc 9-bit UMTS Primary Scrambling Code
-     * @param uarfcn 16-bit UMTS Absolute RF Channel Number described in TS 25.101 sec. 5.4.3
-     *
-     * @hide
-     */
-    public CellIdentityWcdma (int mcc, int mnc, int lac, int cid, int psc, int uarfcn) {
-        this(lac, cid, psc, uarfcn, String.valueOf(mcc), String.valueOf(mnc), null, null);
-    }
 
     /**
      * public constructor
@@ -103,6 +74,18 @@
         mUarfcn = uarfcn;
     }
 
+    /** @hide */
+    public CellIdentityWcdma(android.hardware.radio.V1_0.CellIdentityWcdma cid) {
+        this(cid.lac, cid.cid, cid.psc, cid.uarfcn, cid.mcc, cid.mnc, "", "");
+    }
+
+    /** @hide */
+    public CellIdentityWcdma(android.hardware.radio.V1_2.CellIdentityWcdma cid) {
+        this(cid.base.lac, cid.base.cid, cid.base.psc, cid.base.uarfcn,
+                cid.base.mcc, cid.base.mnc, cid.operatorNames.alphaLong,
+                cid.operatorNames.alphaShort);
+    }
+
     private CellIdentityWcdma(CellIdentityWcdma cid) {
         this(cid.mLac, cid.mCid, cid.mPsc, cid.mUarfcn, cid.mMccStr,
                 cid.mMncStr, cid.mAlphaLong, cid.mAlphaShort);
diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java
index d0b2687..b761bd7 100644
--- a/telephony/java/android/telephony/CellInfo.java
+++ b/telephony/java/android/telephony/CellInfo.java
@@ -132,7 +132,8 @@
     /** Connection status is unknown. */
     public static final int CONNECTION_UNKNOWN = Integer.MAX_VALUE;
 
-    private int mCellConnectionStatus = CONNECTION_NONE;
+    /** A cell connection status */
+    private int mCellConnectionStatus;
 
     // True if device is mRegistered to the mobile network
     private boolean mRegistered;
@@ -144,6 +145,7 @@
     protected CellInfo() {
         this.mRegistered = false;
         this.mTimeStamp = Long.MAX_VALUE;
+        mCellConnectionStatus = CONNECTION_NONE;
     }
 
     /** @hide */
@@ -300,4 +302,44 @@
             return new CellInfo[size];
         }
     };
+
+    /** @hide */
+    protected CellInfo(android.hardware.radio.V1_0.CellInfo ci) {
+        this.mRegistered = ci.registered;
+        this.mTimeStamp = ci.timeStamp;
+        this.mCellConnectionStatus = CONNECTION_UNKNOWN;
+    }
+
+    /** @hide */
+    protected CellInfo(android.hardware.radio.V1_2.CellInfo ci) {
+        this.mRegistered = ci.registered;
+        this.mTimeStamp = ci.timeStamp;
+        this.mCellConnectionStatus = ci.connectionStatus;
+    }
+
+    /** @hide */
+    public static CellInfo create(android.hardware.radio.V1_0.CellInfo ci) {
+        if (ci == null) return null;
+        switch(ci.cellInfoType) {
+            case android.hardware.radio.V1_0.CellInfoType.GSM: return new CellInfoGsm(ci);
+            case android.hardware.radio.V1_0.CellInfoType.CDMA: return new CellInfoCdma(ci);
+            case android.hardware.radio.V1_0.CellInfoType.LTE: return new CellInfoLte(ci);
+            case android.hardware.radio.V1_0.CellInfoType.WCDMA: return new CellInfoWcdma(ci);
+            case android.hardware.radio.V1_0.CellInfoType.TD_SCDMA: return new CellInfoTdscdma(ci);
+            default: return null;
+        }
+    }
+
+    /** @hide */
+    public static CellInfo create(android.hardware.radio.V1_2.CellInfo ci) {
+        if (ci == null) return null;
+        switch(ci.cellInfoType) {
+            case android.hardware.radio.V1_0.CellInfoType.GSM: return new CellInfoGsm(ci);
+            case android.hardware.radio.V1_0.CellInfoType.CDMA: return new CellInfoCdma(ci);
+            case android.hardware.radio.V1_0.CellInfoType.LTE: return new CellInfoLte(ci);
+            case android.hardware.radio.V1_0.CellInfoType.WCDMA: return new CellInfoWcdma(ci);
+            case android.hardware.radio.V1_0.CellInfoType.TD_SCDMA: return new CellInfoTdscdma(ci);
+            default: return null;
+        }
+    }
 }
diff --git a/telephony/java/android/telephony/CellInfoCdma.java b/telephony/java/android/telephony/CellInfoCdma.java
index f67733d..8c76eae 100644
--- a/telephony/java/android/telephony/CellInfoCdma.java
+++ b/telephony/java/android/telephony/CellInfoCdma.java
@@ -48,6 +48,24 @@
         this.mCellSignalStrengthCdma = ci.mCellSignalStrengthCdma.copy();
     }
 
+    /** @hide */
+    public CellInfoCdma(android.hardware.radio.V1_0.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_0.CellInfoCdma cic = ci.cdma.get(0);
+        mCellIdentityCdma = new CellIdentityCdma(cic.cellIdentityCdma);
+        mCellSignalStrengthCdma =
+            new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
+    }
+
+    /** @hide */
+    public CellInfoCdma(android.hardware.radio.V1_2.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_2.CellInfoCdma cic = ci.cdma.get(0);
+        mCellIdentityCdma = new CellIdentityCdma(cic.cellIdentityCdma);
+        mCellSignalStrengthCdma =
+            new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
+    }
+
     @Override
     public CellIdentityCdma getCellIdentity() {
         return mCellIdentityCdma;
diff --git a/telephony/java/android/telephony/CellInfoGsm.java b/telephony/java/android/telephony/CellInfoGsm.java
index 7211de1..ad16dfa 100644
--- a/telephony/java/android/telephony/CellInfoGsm.java
+++ b/telephony/java/android/telephony/CellInfoGsm.java
@@ -43,8 +43,24 @@
     /** @hide */
     public CellInfoGsm(CellInfoGsm ci) {
         super(ci);
-        this.mCellIdentityGsm = ci.mCellIdentityGsm.copy();
-        this.mCellSignalStrengthGsm = ci.mCellSignalStrengthGsm.copy();
+        mCellIdentityGsm = ci.mCellIdentityGsm.copy();
+        mCellSignalStrengthGsm = ci.mCellSignalStrengthGsm.copy();
+    }
+
+    /** @hide */
+    public CellInfoGsm(android.hardware.radio.V1_0.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_0.CellInfoGsm cig = ci.gsm.get(0);
+        mCellIdentityGsm = new CellIdentityGsm(cig.cellIdentityGsm);
+        mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
+    }
+
+    /** @hide */
+    public CellInfoGsm(android.hardware.radio.V1_2.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_2.CellInfoGsm cig = ci.gsm.get(0);
+        mCellIdentityGsm = new CellIdentityGsm(cig.cellIdentityGsm);
+        mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
     }
 
     @Override
diff --git a/telephony/java/android/telephony/CellInfoLte.java b/telephony/java/android/telephony/CellInfoLte.java
index 7d5388b..8ca6a1a 100644
--- a/telephony/java/android/telephony/CellInfoLte.java
+++ b/telephony/java/android/telephony/CellInfoLte.java
@@ -51,6 +51,24 @@
         this.mCellConfig = new CellConfigLte(ci.mCellConfig);
     }
 
+    /** @hide */
+    public CellInfoLte(android.hardware.radio.V1_0.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_0.CellInfoLte cil = ci.lte.get(0);
+        mCellIdentityLte = new CellIdentityLte(cil.cellIdentityLte);
+        mCellSignalStrengthLte = new CellSignalStrengthLte(cil.signalStrengthLte);
+        mCellConfig = new CellConfigLte();
+    }
+
+    /** @hide */
+    public CellInfoLte(android.hardware.radio.V1_2.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_2.CellInfoLte cil = ci.lte.get(0);
+        mCellIdentityLte = new CellIdentityLte(cil.cellIdentityLte);
+        mCellSignalStrengthLte = new CellSignalStrengthLte(cil.signalStrengthLte);
+        mCellConfig = new CellConfigLte();
+    }
+
     @Override
     public CellIdentityLte getCellIdentity() {
         if (DBG) log("getCellIdentity: " + mCellIdentityLte);
diff --git a/telephony/java/android/telephony/CellInfoTdscdma.java b/telephony/java/android/telephony/CellInfoTdscdma.java
index 40cadde..a8c49b7 100644
--- a/telephony/java/android/telephony/CellInfoTdscdma.java
+++ b/telephony/java/android/telephony/CellInfoTdscdma.java
@@ -48,8 +48,23 @@
         this.mCellSignalStrengthTdscdma = ci.mCellSignalStrengthTdscdma.copy();
     }
 
-    @Override
-    public CellIdentityTdscdma getCellIdentity() {
+    /** @hide */
+    public CellInfoTdscdma(android.hardware.radio.V1_0.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_0.CellInfoTdscdma cit = ci.tdscdma.get(0);
+        mCellIdentityTdscdma = new CellIdentityTdscdma(cit.cellIdentityTdscdma);
+        mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
+    }
+
+    /** @hide */
+    public CellInfoTdscdma(android.hardware.radio.V1_2.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_2.CellInfoTdscdma cit = ci.tdscdma.get(0);
+        mCellIdentityTdscdma = new CellIdentityTdscdma(cit.cellIdentityTdscdma);
+        mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
+    }
+
+    @Override public CellIdentityTdscdma getCellIdentity() {
         return mCellIdentityTdscdma;
     }
     /** @hide */
diff --git a/telephony/java/android/telephony/CellInfoWcdma.java b/telephony/java/android/telephony/CellInfoWcdma.java
index 4f9dcb1..a427e80 100644
--- a/telephony/java/android/telephony/CellInfoWcdma.java
+++ b/telephony/java/android/telephony/CellInfoWcdma.java
@@ -47,6 +47,22 @@
         this.mCellSignalStrengthWcdma = ci.mCellSignalStrengthWcdma.copy();
     }
 
+    /** @hide */
+    public CellInfoWcdma(android.hardware.radio.V1_0.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_0.CellInfoWcdma ciw = ci.wcdma.get(0);
+        mCellIdentityWcdma = new CellIdentityWcdma(ciw.cellIdentityWcdma);
+        mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
+    }
+
+    /** @hide */
+    public CellInfoWcdma(android.hardware.radio.V1_2.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_2.CellInfoWcdma ciw = ci.wcdma.get(0);
+        mCellIdentityWcdma = new CellIdentityWcdma(ciw.cellIdentityWcdma);
+        mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
+    }
+
     @Override
     public CellIdentityWcdma getCellIdentity() {
         return mCellIdentityWcdma;
diff --git a/telephony/java/android/telephony/ModemInfo.java b/telephony/java/android/telephony/ModemInfo.java
index 564effe..27a5121 100644
--- a/telephony/java/android/telephony/ModemInfo.java
+++ b/telephony/java/android/telephony/ModemInfo.java
@@ -32,6 +32,11 @@
     public final boolean isVoiceSupported;
     public final boolean isDataSupported;
 
+    // TODO b/121394331: Clean up this class after V1_1.PhoneCapability cleanup.
+    public ModemInfo(int modemId) {
+        this(modemId, 0, true, true);
+    }
+
     public ModemInfo(int modemId, int rat, boolean isVoiceSupported, boolean isDataSupported) {
         this.modemId = modemId;
         this.rat = rat;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 3b2a05b..d8b430f 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -3196,6 +3196,29 @@
     }
 
     /**
+     * Gets information about currently inserted UICCs and eUICCs. See {@link UiccCardInfo} for more
+     * details on the kind of information available.
+     *
+     * @return UiccCardInfo an array of UiccCardInfo objects, representing information on the
+     * currently inserted UICCs and eUICCs.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public UiccCardInfo[] getUiccCardsInfo() {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony == null) {
+                return null;
+            }
+            return telephony.getUiccCardsInfo();
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
      * Gets all the UICC slots. The objects in the array can be null if the slot info is not
      * available, which is possible between phone process starting and getting slot info from modem.
      *
diff --git a/telephony/java/android/telephony/UiccCardInfo.aidl b/telephony/java/android/telephony/UiccCardInfo.aidl
new file mode 100644
index 0000000..882c233
--- /dev/null
+++ b/telephony/java/android/telephony/UiccCardInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.telephony;
+
+parcelable UiccCardInfo;
diff --git a/telephony/java/android/telephony/UiccCardInfo.java b/telephony/java/android/telephony/UiccCardInfo.java
new file mode 100644
index 0000000..45e4704
--- /dev/null
+++ b/telephony/java/android/telephony/UiccCardInfo.java
@@ -0,0 +1,156 @@
+/*
+ * 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.telephony;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * The UiccCardInfo represents information about a currently inserted UICC or embedded eUICC.
+ * @hide
+ */
+@SystemApi
+public class UiccCardInfo implements Parcelable {
+
+    private final boolean mIsEuicc;
+    private final int mCardId;
+    private final String mEid;
+    private final String mIccId;
+    private final int mSlotIndex;
+
+    public static final Creator<UiccCardInfo> CREATOR = new Creator<UiccCardInfo>() {
+        @Override
+        public UiccCardInfo createFromParcel(Parcel in) {
+            return new UiccCardInfo(in);
+        }
+
+        @Override
+        public UiccCardInfo[] newArray(int size) {
+            return new UiccCardInfo[size];
+        }
+    };
+
+    private UiccCardInfo(Parcel in) {
+        mIsEuicc = in.readByte() != 0;
+        mCardId = in.readInt();
+        mEid = in.readString();
+        mIccId = in.readString();
+        mSlotIndex = in.readInt();
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeByte((byte) (mIsEuicc ? 1 : 0));
+        dest.writeInt(mCardId);
+        dest.writeString(mEid);
+        dest.writeString(mIccId);
+        dest.writeInt(mSlotIndex);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public UiccCardInfo(boolean isEuicc, int cardId, String eid, String iccId, int slotIndex) {
+        this.mIsEuicc = isEuicc;
+        this.mCardId = cardId;
+        this.mEid = eid;
+        this.mIccId = iccId;
+        this.mSlotIndex = slotIndex;
+    }
+
+    /**
+     * Return whether the UiccCardInfo is an eUICC.
+     * @return true if the UICC is an eUICC.
+     */
+    public boolean isEuicc() {
+        return mIsEuicc;
+    }
+
+    /**
+     * Get the card ID of the UICC. See {@link TelephonyManager#getCardIdForDefaultEuicc()} for more
+     * details on card ID.
+     */
+    public int getCardId() {
+        return mCardId;
+    }
+
+    /**
+     * Get the embedded ID (EID) of the eUICC. If the UiccCardInfo is not an eUICC
+     * (see {@link #isEuicc()}), returns null.
+     */
+    public String getEid() {
+        if (!mIsEuicc) {
+            return null;
+        }
+        return mEid;
+    }
+
+    /**
+     * Get the ICCID of the UICC.
+     */
+    public String getIccId() {
+        return mIccId;
+    }
+
+    /**
+     * Gets the slot index for the slot that the UICC is currently inserted in.
+     */
+    public int getSlotIndex() {
+        return mSlotIndex;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        }
+
+        UiccCardInfo that = (UiccCardInfo) obj;
+        return ((mIsEuicc == that.mIsEuicc)
+                && (mCardId == that.mCardId)
+                && (Objects.equals(mEid, that.mEid))
+                && (Objects.equals(mIccId, that.mIccId))
+                && (mSlotIndex == that.mSlotIndex));
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mIsEuicc, mCardId, mEid, mIccId, mSlotIndex);
+    }
+
+    @Override
+    public String toString() {
+        return "UiccCardInfo (mIsEuicc="
+                + mIsEuicc
+                + ", mCardId="
+                + mCardId
+                + ", mEid="
+                + mEid
+                + ", mIccId="
+                + mIccId
+                + ", mSlotIndex="
+                + mSlotIndex
+                + ")";
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index 0fdca5d..96f7a1b 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -24,7 +24,7 @@
     /**
      * IDLE: ready to start data connection setup, default state
      * CONNECTING: state of issued startPppd() but not finish yet
-     * SCANNING: data connection fails with one apn but other apns are available
+     * RETRYING: data connection fails with one apn but other apns are available
      *           ready to start data connection on other apns (before INITING)
      * CONNECTED: IP connection is setup
      * DISCONNECTING: Connection.disconnect() has been called, but PDP
@@ -34,19 +34,16 @@
      *
      * getDataConnectionState() maps State to DataState
      *      FAILED or IDLE : DISCONNECTED
-     *      RETRYING or CONNECTING or SCANNING: CONNECTING
+     *      RETRYING or CONNECTING: CONNECTING
      *      CONNECTED : CONNECTED or DISCONNECTING
      */
     public enum State {
         IDLE,
         CONNECTING,
-        SCANNING,
+        RETRYING,
         CONNECTED,
         DISCONNECTING,
         FAILED,
-        RETRYING        // After moving retry manager to ApnContext, we'll never enter this state!
-                        // Todo: Remove this state and other places that use this state and then
-                        // rename SCANNING to RETRYING.
     }
 
     public enum Activity {
@@ -81,7 +78,6 @@
     public static final int EVENT_RESTART_RADIO = BASE + 26;
     public static final int EVENT_CLEAN_UP_ALL_CONNECTIONS = BASE + 29;
     public static final int EVENT_ICC_CHANGED = BASE + 33;
-    public static final int EVENT_DISCONNECT_DC_RETRYING = BASE + 34;
     public static final int EVENT_DATA_SETUP_COMPLETE_ERROR = BASE + 35;
     public static final int CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA = BASE + 36;
     public static final int CMD_ENABLE_MOBILE_PROVISIONING = BASE + 37;
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 399e255..c5d82c5 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -56,6 +56,7 @@
 import java.util.List;
 import java.util.Map;
 
+import android.telephony.UiccCardInfo;
 import android.telephony.UiccSlotInfo;
 
 /**
@@ -1494,6 +1495,17 @@
     int getCardIdForDefaultEuicc(int subId, String callingPackage); 
 
     /**
+     * Gets information about currently inserted UICCs and eUICCs. See {@link UiccCardInfo} for more
+     * details on the kind of information available.
+     *
+     * @return UiccCardInfo an array of UiccCardInfo objects, representing information on the
+     * currently inserted UICCs and eUICCs.
+     *
+     * @hide
+     */
+    UiccCardInfo[] getUiccCardsInfo();
+
+    /**
      * Get slot info for all the UICC slots.
      * @return UiccSlotInfo array.
      * @hide
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index f2cb653..1c103a9 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -498,6 +498,7 @@
     int RIL_REQUEST_SET_LINK_CAPACITY_REPORTING_CRITERIA = 203;
     int RIL_REQUEST_SET_PREFERRED_DATA_MODEM = 204;
     int RIL_REQUEST_EMERGENCY_DIAL = 205;
+    int RIL_REQUEST_GET_PHONE_CAPABILITY = 206;
 
     /* Responses begin */
     int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;