Merge "Fix system crash in certain jobs-removed cases"
diff --git a/Android.mk b/Android.mk
index 10d11f3..9676958 100644
--- a/Android.mk
+++ b/Android.mk
@@ -486,6 +486,10 @@
 
 include $(BUILD_APIDIFF)
 
+# Hack to get diffs included in docs output
+out_zip := $(OUT_DOCS)/$(LOCAL_MODULE)-docs.zip
+$(out_zip): $(full_target)
+
 # ====  System API diff ===========================
 include $(CLEAR_VARS)
 
@@ -512,6 +516,10 @@
 
 include $(BUILD_APIDIFF)
 
+# Hack to get diffs included in docs output
+out_zip := $(OUT_DOCS)/$(LOCAL_MODULE)-docs.zip
+$(out_zip): $(full_target)
+
 # ====  the api stubs and current.xml ===========================
 include $(CLEAR_VARS)
 
@@ -656,10 +664,6 @@
 # Check comment when you are updating the API
 update-api: doc-comment-check-docs
 
-# Generate API diffs as part of docs builds
-docs: offline-sdk-referenceonly-diff
-docs: offline-system-sdk-referenceonly-diff
-
 # ====  static html in the sdk ==================================
 include $(CLEAR_VARS)
 
diff --git a/api/current.txt b/api/current.txt
index 0d55ddf..c3dbee0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6394,7 +6394,7 @@
     method public deprecated boolean isCallerApplicationRestrictionsManagingPackage();
     method public boolean isDeviceOwnerApp(java.lang.String);
     method public boolean isLockTaskPermitted(java.lang.String);
-    method public boolean isLogoutButtonEnabled();
+    method public boolean isLogoutEnabled();
     method public boolean isManagedProfile(android.content.ComponentName);
     method public boolean isMasterVolumeMuted(android.content.ComponentName);
     method public boolean isNetworkLoggingEnabled(android.content.ComponentName);
@@ -6438,7 +6438,7 @@
     method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
     method public void setLockTaskFeatures(android.content.ComponentName, int);
     method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
-    method public void setLogoutButtonEnabled(android.content.ComponentName, boolean);
+    method public void setLogoutEnabled(android.content.ComponentName, boolean);
     method public void setLongSupportMessage(android.content.ComponentName, java.lang.CharSequence);
     method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
@@ -20559,6 +20559,7 @@
     method public int getMaxWidth();
     method public java.lang.CharSequence getTextForImeAction(int);
     method public android.app.Dialog getWindow();
+    method public void hideSoftInputFromInputMethod(int);
     method public void hideStatusIcon();
     method public void hideWindow();
     method public boolean isExtractViewShown();
@@ -20614,10 +20615,16 @@
     method public void setCandidatesViewShown(boolean);
     method public void setExtractView(android.view.View);
     method public void setExtractViewShown(boolean);
+    method public void setInputMethod(java.lang.String);
+    method public void setInputMethodAndSubtype(java.lang.String, android.view.inputmethod.InputMethodSubtype);
     method public void setInputView(android.view.View);
+    method public boolean shouldOfferSwitchingToNextInputMethod();
+    method public void showSoftInputFromInputMethod(int);
     method public void showStatusIcon(int);
     method public void showWindow(boolean);
     method public void switchInputMethod(java.lang.String);
+    method public boolean switchToLastInputMethod();
+    method public boolean switchToNextInputMethod(boolean);
     method public void updateFullscreenMode();
     method public void updateInputViewShown();
     field public static final int BACK_DISPOSITION_DEFAULT = 0; // 0x0
@@ -49035,10 +49042,10 @@
     method public java.util.List<android.view.inputmethod.InputMethodInfo> getInputMethodList();
     method public android.view.inputmethod.InputMethodSubtype getLastInputMethodSubtype();
     method public java.util.Map<android.view.inputmethod.InputMethodInfo, java.util.List<android.view.inputmethod.InputMethodSubtype>> getShortcutInputMethodsAndSubtypes();
-    method public void hideSoftInputFromInputMethod(android.os.IBinder, int);
+    method public deprecated void hideSoftInputFromInputMethod(android.os.IBinder, int);
     method public boolean hideSoftInputFromWindow(android.os.IBinder, int);
     method public boolean hideSoftInputFromWindow(android.os.IBinder, int, android.os.ResultReceiver);
-    method public void hideStatusIcon(android.os.IBinder);
+    method public deprecated void hideStatusIcon(android.os.IBinder);
     method public boolean isAcceptingText();
     method public boolean isActive(android.view.View);
     method public boolean isActive();
@@ -49048,17 +49055,17 @@
     method public void sendAppPrivateCommand(android.view.View, java.lang.String, android.os.Bundle);
     method public void setAdditionalInputMethodSubtypes(java.lang.String, android.view.inputmethod.InputMethodSubtype[]);
     method public boolean setCurrentInputMethodSubtype(android.view.inputmethod.InputMethodSubtype);
-    method public void setInputMethod(android.os.IBinder, java.lang.String);
-    method public void setInputMethodAndSubtype(android.os.IBinder, java.lang.String, android.view.inputmethod.InputMethodSubtype);
-    method public boolean shouldOfferSwitchingToNextInputMethod(android.os.IBinder);
+    method public deprecated void setInputMethod(android.os.IBinder, java.lang.String);
+    method public deprecated void setInputMethodAndSubtype(android.os.IBinder, java.lang.String, android.view.inputmethod.InputMethodSubtype);
+    method public deprecated boolean shouldOfferSwitchingToNextInputMethod(android.os.IBinder);
     method public void showInputMethodAndSubtypeEnabler(java.lang.String);
     method public void showInputMethodPicker();
     method public boolean showSoftInput(android.view.View, int);
     method public boolean showSoftInput(android.view.View, int, android.os.ResultReceiver);
-    method public void showSoftInputFromInputMethod(android.os.IBinder, int);
-    method public void showStatusIcon(android.os.IBinder, java.lang.String, int);
-    method public boolean switchToLastInputMethod(android.os.IBinder);
-    method public boolean switchToNextInputMethod(android.os.IBinder, boolean);
+    method public deprecated void showSoftInputFromInputMethod(android.os.IBinder, int);
+    method public deprecated void showStatusIcon(android.os.IBinder, java.lang.String, int);
+    method public deprecated boolean switchToLastInputMethod(android.os.IBinder);
+    method public deprecated boolean switchToNextInputMethod(android.os.IBinder, boolean);
     method public void toggleSoftInput(int, int);
     method public void toggleSoftInputFromWindow(android.os.IBinder, int, int);
     method public deprecated void updateCursor(android.view.View, int, int, int, int);
diff --git a/api/test-current.txt b/api/test-current.txt
index 3c3521f..27e585d 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -162,6 +162,10 @@
     method public abstract boolean isPermissionReviewModeEnabled();
   }
 
+  public class PermissionInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
+    field public static final int PROTECTION_FLAG_VENDOR_PRIVILEGED = 32768; // 0x8000
+  }
+
   public final class ShortcutInfo implements android.os.Parcelable {
     method public boolean isVisibleToPublisher();
   }
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index 7a1931718..037aeb0 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -35,23 +35,23 @@
 
     void setServiceInfo(in AccessibilityServiceInfo info);
 
-    boolean findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
+    String[] findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
         long accessibilityNodeId, int interactionId,
         IAccessibilityInteractionConnectionCallback callback, int flags, long threadId,
         in Bundle arguments);
 
-    boolean findAccessibilityNodeInfosByText(int accessibilityWindowId, long accessibilityNodeId,
+    String[] findAccessibilityNodeInfosByText(int accessibilityWindowId, long accessibilityNodeId,
         String text, int interactionId, IAccessibilityInteractionConnectionCallback callback,
         long threadId);
 
-    boolean findAccessibilityNodeInfosByViewId(int accessibilityWindowId,
+    String[] findAccessibilityNodeInfosByViewId(int accessibilityWindowId,
         long accessibilityNodeId, String viewId, int interactionId,
         IAccessibilityInteractionConnectionCallback callback, long threadId);
 
-    boolean findFocus(int accessibilityWindowId, long accessibilityNodeId, int focusType,
+    String[] findFocus(int accessibilityWindowId, long accessibilityNodeId, int focusType,
         int interactionId, IAccessibilityInteractionConnectionCallback callback, long threadId);
 
-    boolean focusSearch(int accessibilityWindowId, long accessibilityNodeId, int direction,
+    String[] focusSearch(int accessibilityWindowId, long accessibilityNodeId, int direction,
         int interactionId, IAccessibilityInteractionConnectionCallback callback, long threadId);
 
     boolean performAccessibilityAction(int accessibilityWindowId, long accessibilityNodeId,
diff --git a/core/java/android/annotation/IntDef.java b/core/java/android/annotation/IntDef.java
index 3f9064e..f84a676 100644
--- a/core/java/android/annotation/IntDef.java
+++ b/core/java/android/annotation/IntDef.java
@@ -52,10 +52,12 @@
 @Target({ANNOTATION_TYPE})
 public @interface IntDef {
     /** Defines the constant prefix for this element */
-    String[] prefix() default "";
+    String[] prefix() default {};
+    /** Defines the constant suffix for this element */
+    String[] suffix() default {};
 
     /** Defines the allowed constants for this element */
-    long[] value() default {};
+    int[] value() default {};
 
     /** Defines whether the constants can be used as a flag, or just as an enum (the default) */
     boolean flag() default false;
diff --git a/core/java/android/annotation/LongDef.java b/core/java/android/annotation/LongDef.java
new file mode 100644
index 0000000..8723eef8
--- /dev/null
+++ b/core/java/android/annotation/LongDef.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Denotes that the annotated long element represents
+ * a logical type and that its value should be one of the explicitly
+ * named constants. If the {@link #flag()} attribute is set to true,
+ * multiple constants can be combined.
+ * <p>
+ * <pre><code>
+ *  &#64;Retention(SOURCE)
+ *  &#64;LongDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
+ *  public @interface NavigationMode {}
+ *  public static final long NAVIGATION_MODE_STANDARD = 0;
+ *  public static final long NAVIGATION_MODE_LIST = 1;
+ *  public static final long NAVIGATION_MODE_TABS = 2;
+ *  ...
+ *  public abstract void setNavigationMode(@NavigationMode long mode);
+ *  &#64;NavigationMode
+ *  public abstract long getNavigationMode();
+ * </code></pre>
+ * For a flag, set the flag attribute:
+ * <pre><code>
+ *  &#64;LongDef(
+ *      flag = true,
+ *      value = {NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
+ * </code></pre>
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({ANNOTATION_TYPE})
+public @interface LongDef {
+    /** Defines the constant prefix for this element */
+    String[] prefix() default "";
+
+    /** Defines the allowed constants for this element */
+    long[] value() default {};
+
+    /** Defines whether the constants can be used as a flag, or just as an enum (the default) */
+    boolean flag() default false;
+}
diff --git a/core/java/android/annotation/StringDef.java b/core/java/android/annotation/StringDef.java
index d5157c3..a37535b 100644
--- a/core/java/android/annotation/StringDef.java
+++ b/core/java/android/annotation/StringDef.java
@@ -46,6 +46,11 @@
 @Retention(SOURCE)
 @Target({ANNOTATION_TYPE})
 public @interface StringDef {
+    /** Defines the constant prefix for this element */
+    String[] prefix() default {};
+    /** Defines the constant suffix for this element */
+    String[] suffix() default {};
+
     /** Defines the allowed constants for this element */
     String[] value() default {};
 }
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index f831ae2..495fd3c 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -618,12 +618,13 @@
                         ConnectivityThread.getInstanceLooper());
             }});
 
-        registerService(Context.WIFI_RTT2_SERVICE, WifiRttManager.class,
+        registerService(Context.WIFI_RTT_RANGING_SERVICE, WifiRttManager.class,
                 new CachedServiceFetcher<WifiRttManager>() {
                     @Override
                     public WifiRttManager createService(ContextImpl ctx)
                             throws ServiceNotFoundException {
-                        IBinder b = ServiceManager.getServiceOrThrow(Context.WIFI_RTT2_SERVICE);
+                        IBinder b = ServiceManager.getServiceOrThrow(
+                                Context.WIFI_RTT_RANGING_SERVICE);
                         IWifiRttManager service = IWifiRttManager.Stub.asInterface(b);
                         return new WifiRttManager(ctx.getOuterContext(), service);
                     }});
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 562b981..ad21983 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -8585,32 +8585,31 @@
     }
 
     /**
-     * Called by a device owner to specify whether a logout button is enabled for all secondary
-     * users. The system may show a logout button that stops the user and switches back to the
-     * primary user.
+     * Called by a device owner to specify whether logout is enabled for all secondary users. The
+     * system may show a logout button that stops the user and switches back to the primary user.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
-     * @param enabled whether logout button should be enabled or not.
+     * @param enabled whether logout should be enabled or not.
      * @throws SecurityException if {@code admin} is not a device owner.
      */
-    public void setLogoutButtonEnabled(@NonNull ComponentName admin, boolean enabled) {
-        throwIfParentInstance("setLogoutButtonEnabled");
+    public void setLogoutEnabled(@NonNull ComponentName admin, boolean enabled) {
+        throwIfParentInstance("setLogoutEnabled");
         try {
-            mService.setLogoutButtonEnabled(admin, enabled);
+            mService.setLogoutEnabled(admin, enabled);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Returns whether logout button is enabled by a device owner.
+     * Returns whether logout is enabled by a device owner.
      *
-     * @return {@code true} if logout button is enabled by device owner, {@code false} otherwise.
+     * @return {@code true} if logout is enabled by device owner, {@code false} otherwise.
      */
-    public boolean isLogoutButtonEnabled() {
-        throwIfParentInstance("isLogoutButtonEnabled");
+    public boolean isLogoutEnabled() {
+        throwIfParentInstance("isLogoutEnabled");
         try {
-            return mService.isLogoutButtonEnabled();
+            return mService.isLogoutEnabled();
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index c525df7..ff869d2 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -372,6 +372,6 @@
 
     boolean clearApplicationUserData(in ComponentName admin, in String packageName, in IPackageDataObserver callback);
 
-    void setLogoutButtonEnabled(in ComponentName admin, boolean enabled);
-    boolean isLogoutButtonEnabled();
+    void setLogoutEnabled(in ComponentName admin, boolean enabled);
+    boolean isLogoutEnabled();
 }
diff --git a/core/java/android/app/slice/Slice.java b/core/java/android/app/slice/Slice.java
index ddc5760..807c47d 100644
--- a/core/java/android/app/slice/Slice.java
+++ b/core/java/android/app/slice/Slice.java
@@ -37,6 +37,8 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -53,9 +55,21 @@
     /**
      * @hide
      */
-    @StringDef({HINT_TITLE, HINT_LIST, HINT_LIST_ITEM, HINT_LARGE, HINT_ACTIONS, HINT_SELECTED,
-            HINT_NO_TINT, HINT_PARTIAL})
-    public @interface SliceHint{ }
+    @StringDef(prefix = { "HINT_" }, value = {
+            HINT_TITLE,
+            HINT_LIST,
+            HINT_LIST_ITEM,
+            HINT_LARGE,
+            HINT_ACTIONS,
+            HINT_SELECTED,
+            HINT_NO_TINT,
+            HINT_HIDDEN,
+            HINT_TOGGLE,
+            HINT_HORIZONTAL,
+            HINT_PARTIAL,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SliceHint {}
 
     /**
      * The meta-data key that allows an activity to easily be linked directly to a slice.
diff --git a/core/java/android/app/slice/SliceItem.java b/core/java/android/app/slice/SliceItem.java
index cdeee35..743d6b7 100644
--- a/core/java/android/app/slice/SliceItem.java
+++ b/core/java/android/app/slice/SliceItem.java
@@ -29,6 +29,8 @@
 
 import com.android.internal.util.ArrayUtils;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
 import java.util.List;
 
@@ -55,8 +57,16 @@
     /**
      * @hide
      */
-    @StringDef({FORMAT_SLICE, FORMAT_TEXT, FORMAT_IMAGE, FORMAT_ACTION, FORMAT_COLOR,
-            FORMAT_TIMESTAMP, FORMAT_REMOTE_INPUT})
+    @StringDef(prefix = { "FORMAT_" }, value = {
+            FORMAT_SLICE,
+            FORMAT_TEXT,
+            FORMAT_IMAGE,
+            FORMAT_ACTION,
+            FORMAT_COLOR,
+            FORMAT_TIMESTAMP,
+            FORMAT_REMOTE_INPUT,
+    })
+    @Retention(RetentionPolicy.SOURCE)
     public @interface SliceType {}
 
     /**
diff --git a/core/java/android/app/timezone/RulesManager.java b/core/java/android/app/timezone/RulesManager.java
index ad9b698..417e7d2 100644
--- a/core/java/android/app/timezone/RulesManager.java
+++ b/core/java/android/app/timezone/RulesManager.java
@@ -105,9 +105,9 @@
      */
     public RulesState getRulesState() {
         try {
-            logDebug("sIRulesManager.getRulesState()");
+            logDebug("mIRulesManager.getRulesState()");
             RulesState rulesState = mIRulesManager.getRulesState();
-            logDebug("sIRulesManager.getRulesState() returned " + rulesState);
+            logDebug("mIRulesManager.getRulesState() returned " + rulesState);
             return rulesState;
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -131,7 +131,7 @@
 
         ICallback iCallback = new CallbackWrapper(mContext, callback);
         try {
-            logDebug("sIRulesManager.requestInstall()");
+            logDebug("mIRulesManager.requestInstall()");
             return mIRulesManager.requestInstall(distroFileDescriptor, checkToken, iCallback);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -151,7 +151,7 @@
     public int requestUninstall(byte[] checkToken, Callback callback) {
         ICallback iCallback = new CallbackWrapper(mContext, callback);
         try {
-            logDebug("sIRulesManager.requestUninstall()");
+            logDebug("mIRulesManager.requestUninstall()");
             return mIRulesManager.requestUninstall(checkToken, iCallback);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -196,7 +196,7 @@
      */
     public void requestNothing(byte[] checkToken, boolean succeeded) {
         try {
-            logDebug("sIRulesManager.requestNothing() with token=" + Arrays.toString(checkToken));
+            logDebug("mIRulesManager.requestNothing() with token=" + Arrays.toString(checkToken));
             mIRulesManager.requestNothing(checkToken, succeeded);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
diff --git a/core/java/android/appwidget/AppWidgetManagerInternal.java b/core/java/android/appwidget/AppWidgetManagerInternal.java
new file mode 100644
index 0000000..7ab3d8b
--- /dev/null
+++ b/core/java/android/appwidget/AppWidgetManagerInternal.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.appwidget;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.ArraySet;
+
+import java.util.Set;
+
+/**
+ * App widget manager local system service interface.
+ *
+ * @hide Only for use within the system server.
+ */
+public abstract class AppWidgetManagerInternal {
+
+    /**
+     * Gets the packages from which the uid hosts widgets.
+     *
+     * @param uid The potential host UID.
+     * @return Whether the UID hosts widgets from the package.
+     */
+    public abstract @Nullable ArraySet<String> getHostedWidgetPackages(int uid);
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 9800ab0..a474330 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2913,7 +2913,7 @@
             @Nullable String profileFile, @Nullable Bundle arguments);
 
     /** @hide */
-    @StringDef({
+    @StringDef(suffix = { "_SERVICE" }, value = {
             POWER_SERVICE,
             WINDOW_SERVICE,
             LAYOUT_INFLATER_SERVICE,
@@ -2947,7 +2947,7 @@
             //@hide: LOWPAN_SERVICE,
             //@hide: WIFI_RTT_SERVICE,
             //@hide: ETHERNET_SERVICE,
-            WIFI_RTT_SERVICE,
+            WIFI_RTT_RANGING_SERVICE,
             NSD_SERVICE,
             AUDIO_SERVICE,
             FINGERPRINT_SERVICE,
@@ -3496,7 +3496,7 @@
      * @see android.net.wifi.rtt.WifiRttManager
      * @hide
      */
-    public static final String WIFI_RTT2_SERVICE = "rttmanager2";
+    public static final String WIFI_RTT_RANGING_SERVICE = "rttmanager2";
 
     /**
      * Use with {@link #getSystemService} to retrieve a {@link
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index 551d53b..21bd7f0 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -17,6 +17,7 @@
 package android.content.pm;
 
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -150,6 +151,7 @@
      *
      * @hide
      */
+    @TestApi
     public static final int PROTECTION_FLAG_VENDOR_PRIVILEGED = 0x8000;
 
     /**
diff --git a/core/java/android/hardware/HardwareBuffer.java b/core/java/android/hardware/HardwareBuffer.java
index 7049628..b111ad3 100644
--- a/core/java/android/hardware/HardwareBuffer.java
+++ b/core/java/android/hardware/HardwareBuffer.java
@@ -17,6 +17,7 @@
 package android.hardware;
 
 import android.annotation.IntDef;
+import android.annotation.LongDef;
 import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -70,7 +71,7 @@
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag = true, value = {USAGE_CPU_READ_RARELY, USAGE_CPU_READ_OFTEN,
+    @LongDef(flag = true, value = {USAGE_CPU_READ_RARELY, USAGE_CPU_READ_OFTEN,
             USAGE_CPU_WRITE_RARELY, USAGE_CPU_WRITE_OFTEN, USAGE_GPU_SAMPLED_IMAGE,
             USAGE_GPU_COLOR_OUTPUT, USAGE_PROTECTED_CONTENT, USAGE_VIDEO_ENCODE,
             USAGE_GPU_DATA_BUFFER, USAGE_SENSOR_DIRECT_DATA})
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 223ed73..02b1c65 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -392,7 +392,7 @@
                 mWindow.setToken(token);
             }
         }
-        
+
         /**
          * {@inheritDoc}
          *
@@ -1064,7 +1064,89 @@
         }
         return mInputConnection;
     }
-    
+
+    /**
+     * 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.
+     * @param id The unique identifier for the new input method to be switched to.
+     */
+    public void setInputMethod(String id) {
+        mImm.setInputMethodInternal(mToken, id);
+    }
+
+    /**
+     * Force switch to a new input method and subtype. This can only be called
+     * from an application or a service which has a token of the currently active input method.
+     * @param id The unique identifier for the new input method to be switched to.
+     * @param subtype The new subtype of the new input method to be switched to.
+     */
+    public void setInputMethodAndSubtype(String id, InputMethodSubtype subtype) {
+        mImm.setInputMethodAndSubtypeInternal(mToken, id, subtype);
+    }
+
+    /**
+     * Close/hide the input method's soft input area, so the user no longer
+     * sees it or can interact with it.  This can only be called
+     * from the currently active input method, as validated by the given token.
+     *
+     * @param flags Provides additional operating flags.  Currently may be
+     * 0 or have the {@link InputMethodManager#HIDE_IMPLICIT_ONLY},
+     * {@link InputMethodManager#HIDE_NOT_ALWAYS} bit set.
+     */
+    public void hideSoftInputFromInputMethod(int flags) {
+        mImm.hideSoftInputFromInputMethodInternal(mToken, flags);
+    }
+
+    /**
+     * Show the input method's soft input area, so the user
+     * sees the input method window and can interact with it.
+     * This can only be called from the currently active input method,
+     * as validated by the given token.
+     *
+     * @param flags Provides additional operating flags.  Currently may be
+     * 0 or have the {@link InputMethodManager#SHOW_IMPLICIT} or
+     * {@link InputMethodManager#SHOW_FORCED} bit set.
+     */
+    public void showSoftInputFromInputMethod(int flags) {
+        mImm.showSoftInputFromInputMethodInternal(mToken, flags);
+    }
+
+    /**
+     * Force switch to the last used input method and subtype. If the last input method didn't have
+     * any subtypes, the framework will simply switch to the last input method with no subtype
+     * specified.
+     * @return true if the current input method and subtype was successfully switched to the last
+     * used input method and subtype.
+     */
+    public boolean switchToLastInputMethod() {
+        return mImm.switchToLastInputMethodInternal(mToken);
+    }
+
+    /**
+     * Force switch to the next input method and subtype. If there is no IME enabled except
+     * current IME and subtype, do nothing.
+     * @param onlyCurrentIme if true, the framework will find the next subtype which
+     * belongs to the current IME
+     * @return true if the current input method and subtype was successfully switched to the next
+     * input method and subtype.
+     */
+    public boolean switchToNextInputMethod(boolean onlyCurrentIme) {
+        return mImm.switchToNextInputMethodInternal(mToken, onlyCurrentIme);
+    }
+
+    /**
+     * Returns true if the current IME needs to offer the users ways to switch to a next input
+     * method (e.g. a globe key.).
+     * When an IME sets supportsSwitchingToNextInputMethod and this method returns true,
+     * the IME has to offer ways to to invoke {@link #switchToNextInputMethod} accordingly.
+     * <p> Note that the system determines the most appropriate next input method
+     * and subtype in order to provide the consistent user experience in switching
+     * between IMEs and subtypes.
+     */
+    public boolean shouldOfferSwitchingToNextInputMethod() {
+        return mImm.shouldOfferSwitchingToNextInputMethodInternal(mToken);
+    }
+
     public boolean getCurrentInputStarted() {
         return mInputStarted;
     }
diff --git a/core/java/android/net/metrics/DefaultNetworkEvent.java b/core/java/android/net/metrics/DefaultNetworkEvent.java
index 8ff8e4f..6f383b4 100644
--- a/core/java/android/net/metrics/DefaultNetworkEvent.java
+++ b/core/java/android/net/metrics/DefaultNetworkEvent.java
@@ -74,7 +74,7 @@
             j.add("final_score=" + finalScore);
         }
         j.add(String.format("duration=%.0fs", durationMs / 1000.0));
-        j.add(String.format("validation=%4.1f%%", (validatedMs * 100.0) / durationMs));
+        j.add(String.format("validation=%04.1f%%", (validatedMs * 100.0) / durationMs));
         return j.toString();
     }
 
diff --git a/core/java/android/security/recoverablekeystore/RecoverableKeyGenerator.java b/core/java/android/security/recoverablekeystore/RecoverableKeyGenerator.java
new file mode 100644
index 0000000..4125f0ba
--- /dev/null
+++ b/core/java/android/security/recoverablekeystore/RecoverableKeyGenerator.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.recoverablekeystore;
+
+import android.security.keystore.AndroidKeyStoreSecretKey;
+import android.security.keystore.KeyProperties;
+import android.security.keystore.KeyProtection;
+import android.util.Log;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableEntryException;
+
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+import javax.security.auth.DestroyFailedException;
+
+/**
+ * Generates keys and stores them both in AndroidKeyStore and on disk, in wrapped form.
+ *
+ * <p>Generates 256-bit AES keys, which can be used for encrypt / decrypt with AES/GCM/NoPadding.
+ * They are synced to disk wrapped by a platform key. This allows them to be exported to a remote
+ * service.
+ *
+ * @hide
+ */
+public class RecoverableKeyGenerator {
+    private static final String TAG = "RecoverableKeyGenerator";
+    private static final String KEY_GENERATOR_ALGORITHM = "AES";
+    private static final int KEY_SIZE_BITS = 256;
+
+    /**
+     * A new {@link RecoverableKeyGenerator} instance.
+     *
+     * @param platformKey Secret key used to wrap generated keys before persisting to disk.
+     * @param recoverableKeyStorage Class that manages persisting wrapped keys to disk.
+     * @throws NoSuchAlgorithmException if "AES" key generation or "AES/GCM/NoPadding" cipher is
+     *     unavailable. Should never happen.
+     *
+     * @hide
+     */
+    public static RecoverableKeyGenerator newInstance(
+            AndroidKeyStoreSecretKey platformKey, RecoverableKeyStorage recoverableKeyStorage)
+            throws NoSuchAlgorithmException {
+        // NB: This cannot use AndroidKeyStore as the provider, as we need access to the raw key
+        // material, so that it can be synced to disk in encrypted form.
+        KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_GENERATOR_ALGORITHM);
+        return new RecoverableKeyGenerator(keyGenerator, platformKey, recoverableKeyStorage);
+    }
+
+    private final KeyGenerator mKeyGenerator;
+    private final RecoverableKeyStorage mRecoverableKeyStorage;
+    private final AndroidKeyStoreSecretKey mPlatformKey;
+
+    private RecoverableKeyGenerator(
+            KeyGenerator keyGenerator,
+            AndroidKeyStoreSecretKey platformKey,
+            RecoverableKeyStorage recoverableKeyStorage) {
+        mKeyGenerator = keyGenerator;
+        mRecoverableKeyStorage = recoverableKeyStorage;
+        mPlatformKey = platformKey;
+    }
+
+    /**
+     * Generates a 256-bit AES key with the given alias.
+     *
+     * <p>Stores in the AndroidKeyStore, as well as persisting in wrapped form to disk. It is
+     * persisted to disk so that it can be synced remotely, and then recovered on another device.
+     * The generated key allows encrypt/decrypt only using AES/GCM/NoPadding.
+     *
+     * <p>The key handle returned to the caller is a reference to the AndroidKeyStore key,
+     * meaning that the caller is never able to access the raw, unencrypted key.
+     *
+     * @param alias The alias by which the key will be known in AndroidKeyStore.
+     * @throws InvalidKeyException if the platform key cannot be used to wrap keys.
+     * @throws IOException if there was an issue writing the wrapped key to the wrapped key store.
+     * @throws UnrecoverableEntryException if could not retrieve key after putting it in
+     *     AndroidKeyStore. This should not happen.
+     * @return A handle to the AndroidKeyStore key.
+     *
+     * @hide
+     */
+    public SecretKey generateAndStoreKey(String alias) throws KeyStoreException,
+            InvalidKeyException, IOException, UnrecoverableEntryException {
+        mKeyGenerator.init(KEY_SIZE_BITS);
+        SecretKey key = mKeyGenerator.generateKey();
+
+        mRecoverableKeyStorage.importIntoAndroidKeyStore(
+                alias,
+                key,
+                new KeyProtection.Builder(
+                        KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+                        .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
+                        .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+                        .build());
+        WrappedKey wrappedKey = WrappedKey.fromSecretKey(mPlatformKey, key);
+
+        try {
+            // Keep raw key material in memory for minimum possible time.
+            key.destroy();
+        } catch (DestroyFailedException e) {
+            Log.w(TAG, "Could not destroy SecretKey.");
+        }
+
+        mRecoverableKeyStorage.persistToDisk(alias, wrappedKey);
+
+        try {
+            // Reload from the keystore, so that the caller is only provided with the handle of the
+            // key, not the raw key material.
+            return mRecoverableKeyStorage.loadFromAndroidKeyStore(alias);
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException(
+                    "Impossible: NoSuchAlgorithmException when attempting to retrieve a key "
+                            + "that has only just been stored in AndroidKeyStore.", e);
+        }
+    }
+}
diff --git a/core/java/android/security/recoverablekeystore/RecoverableKeyStorage.java b/core/java/android/security/recoverablekeystore/RecoverableKeyStorage.java
new file mode 100644
index 0000000..c239e00
--- /dev/null
+++ b/core/java/android/security/recoverablekeystore/RecoverableKeyStorage.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.recoverablekeystore;
+
+import android.security.keystore.KeyProtection;
+
+import java.io.IOException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableEntryException;
+
+import javax.crypto.SecretKey;
+
+/**
+ * Stores wrapped keys to disk, so they can be synced on the next screen unlock event.
+ *
+ * @hide
+ */
+public interface RecoverableKeyStorage {
+
+    /**
+     * Writes {@code wrappedKey} to disk, keyed by the application's uid and the {@code alias}.
+     *
+     * @throws IOException if an error occurred writing to disk.
+     *
+     * @hide
+     */
+    void persistToDisk(String alias, WrappedKey wrappedKey) throws IOException;
+
+    /**
+     * Imports {@code key} into AndroidKeyStore, keyed by the application's uid and
+     * the {@code alias}.
+     *
+     * @param alias The alias of the key.
+     * @param key The key.
+     * @param keyProtection Protection params denoting what the key can be used for. (e.g., what
+     *                      Cipher modes, whether for encrpyt/decrypt or signing, etc.)
+     * @throws KeyStoreException if an error occurred loading the key into the AndroidKeyStore.
+     *
+     * @hide
+     */
+    void importIntoAndroidKeyStore(String alias, SecretKey key, KeyProtection keyProtection) throws
+            KeyStoreException;
+
+    /**
+     * Loads a key handle from AndroidKeyStore.
+     *
+     * @param alias Alias of the key to load.
+     * @return The key handle.
+     * @throws KeyStoreException if an error occurred loading the key from AndroidKeyStore.
+     *
+     * @hide
+     */
+    SecretKey loadFromAndroidKeyStore(String alias) throws KeyStoreException,
+            NoSuchAlgorithmException,
+            UnrecoverableEntryException;
+}
diff --git a/core/java/android/security/recoverablekeystore/RecoverableKeyStorageImpl.java b/core/java/android/security/recoverablekeystore/RecoverableKeyStorageImpl.java
new file mode 100644
index 0000000..b9926dd
--- /dev/null
+++ b/core/java/android/security/recoverablekeystore/RecoverableKeyStorageImpl.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.recoverablekeystore;
+
+import android.security.keystore.KeyProtection;
+
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableEntryException;
+import java.security.cert.CertificateException;
+
+import javax.crypto.SecretKey;
+
+/**
+ * Implementation of {@link RecoverableKeyStorage}.
+ *
+ * <p>Persists wrapped keys to disk, and loads raw keys into AndroidKeyStore.
+ *
+ * @hide
+ */
+public class RecoverableKeyStorageImpl implements RecoverableKeyStorage {
+    private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore";
+
+    private final KeyStore mKeyStore;
+
+    /**
+     * A new instance.
+     *
+     * @throws KeyStoreException if unable to load AndroidKeyStore.
+     *
+     * @hide
+     */
+    public static RecoverableKeyStorageImpl newInstance() throws KeyStoreException {
+        KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER);
+        try {
+            keyStore.load(/*param=*/ null);
+        } catch (CertificateException | IOException | NoSuchAlgorithmException e) {
+            // Should never happen.
+            throw new KeyStoreException("Unable to load keystore.", e);
+        }
+        return new RecoverableKeyStorageImpl(keyStore);
+    }
+
+    private RecoverableKeyStorageImpl(KeyStore keyStore) {
+        mKeyStore = keyStore;
+    }
+
+    /**
+     * Writes {@code wrappedKey} to disk, keyed by the application's uid and the {@code alias}.
+     *
+     * @throws IOException if an error occurred writing to disk.
+     *
+     * @hide
+     */
+    @Override
+    public void persistToDisk(String alias, WrappedKey wrappedKey) throws IOException {
+        // TODO(robertberry) Add implementation.
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Imports {@code key} into AndroidKeyStore, keyed by the application's uid and the
+     * {@code alias}.
+     *
+     * @param alias The alias of the key.
+     * @param key The key.
+     * @param keyProtection Protection params denoting what the key can be used for. (e.g., what
+     *                      Cipher modes, whether for encrpyt/decrypt or signing, etc.)
+     * @throws KeyStoreException if an error occurred loading the key into the AndroidKeyStore.
+     *
+     * @hide
+     */
+    @Override
+    public void importIntoAndroidKeyStore(String alias, SecretKey key, KeyProtection keyProtection)
+            throws KeyStoreException {
+        mKeyStore.setEntry(alias, new KeyStore.SecretKeyEntry(key), keyProtection);
+    }
+
+    /**
+     * Loads a key handle from AndroidKeyStore.
+     *
+     * @param alias Alias of the key to load.
+     * @return The key handle.
+     * @throws KeyStoreException if an error occurred loading the key from AndroidKeyStore.
+     *
+     * @hide
+     */
+    @Override
+    public SecretKey loadFromAndroidKeyStore(String alias)
+            throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableEntryException {
+        return ((KeyStore.SecretKeyEntry) mKeyStore.getEntry(alias, /*protParam=*/ null))
+                .getSecretKey();
+    }
+}
diff --git a/core/java/android/security/recoverablekeystore/WrappedKey.java b/core/java/android/security/recoverablekeystore/WrappedKey.java
new file mode 100644
index 0000000..51665ae
--- /dev/null
+++ b/core/java/android/security/recoverablekeystore/WrappedKey.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.recoverablekeystore;
+
+import java.security.InvalidKeyException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+
+/**
+ * A {@link javax.crypto.SecretKey} wrapped with AES/GCM/NoPadding.
+ *
+ * @hide
+ */
+public class WrappedKey {
+    private static final String KEY_WRAP_CIPHER_ALGORITHM = "AES/GCM/NoPadding";
+
+    private final byte[] mNonce;
+    private final byte[] mKeyMaterial;
+
+    /**
+     * Returns a wrapped form of {@code key}, using {@code wrappingKey} to encrypt the key material.
+     *
+     * @throws InvalidKeyException if {@code wrappingKey} cannot be used to encrypt {@code key}, or
+     *     if {@code key} does not expose its key material. See
+     *     {@link android.security.keystore.AndroidKeyStoreKey} for an example of a key that does
+     *     not expose its key material.
+     */
+    public static WrappedKey fromSecretKey(
+            SecretKey wrappingKey, SecretKey key) throws InvalidKeyException, KeyStoreException {
+        if (key.getEncoded() == null) {
+            throw new InvalidKeyException(
+                    "key does not expose encoded material. It cannot be wrapped.");
+        }
+
+        Cipher cipher;
+        try {
+            cipher = Cipher.getInstance(KEY_WRAP_CIPHER_ALGORITHM);
+        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
+            throw new RuntimeException(
+                    "Android does not support AES/GCM/NoPadding. This should never happen.");
+        }
+
+        cipher.init(Cipher.WRAP_MODE, wrappingKey);
+        byte[] encryptedKeyMaterial;
+        try {
+            encryptedKeyMaterial = cipher.wrap(key);
+        } catch (IllegalBlockSizeException e) {
+            Throwable cause = e.getCause();
+            if (cause instanceof KeyStoreException) {
+                // If AndroidKeyStore encounters any error here, it throws IllegalBlockSizeException
+                // with KeyStoreException as the cause. This is due to there being no better option
+                // here, as the Cipher#wrap only checked throws InvalidKeyException or
+                // IllegalBlockSizeException. If this is the case, we want to propagate it to the
+                // caller, so rethrow the cause.
+                throw (KeyStoreException) cause;
+            } else {
+                throw new RuntimeException(
+                        "IllegalBlockSizeException should not be thrown by AES/GCM/NoPadding mode.",
+                        e);
+            }
+        }
+
+        return new WrappedKey(/*mNonce=*/ cipher.getIV(), /*mKeyMaterial=*/ encryptedKeyMaterial);
+    }
+
+    /**
+     * A new instance.
+     *
+     * @param nonce The nonce with which the key material was encrypted.
+     * @param keyMaterial The encrypted bytes of the key material.
+     *
+     * @hide
+     */
+    public WrappedKey(byte[] nonce, byte[] keyMaterial) {
+        mNonce = nonce;
+        mKeyMaterial = keyMaterial;
+    }
+
+    /**
+     * Returns the nonce with which the key material was encrypted.
+     *
+     * @hide
+     */
+    public byte[] getNonce() {
+        return mNonce;
+    }
+
+    /**
+     * Returns the encrypted key material.
+     *
+     * @hide
+     */
+    public byte[] getKeyMaterial() {
+        return mKeyMaterial;
+    }
+}
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 80785fd..54b48b6 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -43,6 +43,7 @@
         DEFAULT_FLAGS.put("settings_app_info_v2", "false");
         DEFAULT_FLAGS.put("settings_connected_device_v2", "false");
         DEFAULT_FLAGS.put("settings_battery_v2", "false");
+        DEFAULT_FLAGS.put("settings_battery_display_app_list", "false");
     }
 
     /**
diff --git a/core/java/android/view/FrameInfo.java b/core/java/android/view/FrameInfo.java
index c79547c..6c5e048 100644
--- a/core/java/android/view/FrameInfo.java
+++ b/core/java/android/view/FrameInfo.java
@@ -16,7 +16,7 @@
 
 package android.view;
 
-import android.annotation.IntDef;
+import android.annotation.LongDef;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -48,7 +48,7 @@
     // Is this the first-draw following a window layout?
     public static final long FLAG_WINDOW_LAYOUT_CHANGED = 1;
 
-    @IntDef(flag = true, value = {
+    @LongDef(flag = true, value = {
             FLAG_WINDOW_LAYOUT_CHANGED })
     @Retention(RetentionPolicy.SOURCE)
     public @interface FrameInfoFlags {}
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 420a1bb..8a7b441 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -18,11 +18,18 @@
 
 import static android.view.Surface.ROTATION_270;
 import static android.view.Surface.ROTATION_90;
+import static android.graphics.Matrix.MSCALE_X;
+import static android.graphics.Matrix.MSCALE_Y;
+import static android.graphics.Matrix.MSKEW_X;
+import static android.graphics.Matrix.MSKEW_Y;
+import static android.graphics.Matrix.MTRANS_X;
+import static android.graphics.Matrix.MTRANS_Y;
 
 import android.annotation.Size;
 import android.graphics.Bitmap;
 import android.graphics.GraphicBuffer;
 import android.graphics.PixelFormat;
+import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.os.IBinder;
@@ -862,6 +869,22 @@
         }
     }
 
+    /**
+     * Sets the transform and position of a {@link SurfaceControl} from a 3x3 transformation matrix.
+     *
+     * @param matrix The matrix to apply.
+     * @param float9 An array of 9 floats to be used to extract the values from the matrix.
+     */
+    public void setMatrix(Matrix matrix, float[] float9) {
+        checkNotReleased();
+        matrix.getValues(float9);
+        synchronized (SurfaceControl.class) {
+            sGlobalTransaction.setMatrix(this, float9[MSCALE_X], float9[MSKEW_Y],
+                    float9[MSKEW_X], float9[MSCALE_Y]);
+            sGlobalTransaction.setPosition(this, float9[MTRANS_X], float9[MTRANS_Y]);
+        }
+    }
+
     public void setWindowCrop(Rect crop) {
         checkNotReleased();
         synchronized (SurfaceControl.class) {
@@ -1348,6 +1371,14 @@
             return this;
         }
 
+        public Transaction setMatrix(SurfaceControl sc, Matrix matrix, float[] float9) {
+            matrix.getValues(float9);
+            setMatrix(sc, float9[MSCALE_X], float9[MSKEW_Y],
+                    float9[MSKEW_X], float9[MSCALE_Y]);
+            setPosition(sc, float9[MTRANS_X], float9[MTRANS_Y]);
+            return this;
+        }
+
         public Transaction setWindowCrop(SurfaceControl sc, Rect crop) {
             sc.checkNotReleased();
             if (crop != null) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 0bae36b..6d4998b 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -7907,6 +7907,7 @@
             if (!registered) {
                 mAttachInfo.mAccessibilityWindowId =
                         mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
+                                mContext.getPackageName(),
                                 new AccessibilityInteractionConnection(ViewRootImpl.this));
             }
         }
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 7c2c12f..500701d 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -20,6 +20,7 @@
 
 import android.Manifest.permission;
 import android.annotation.IntDef;
+import android.annotation.LongDef;
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
@@ -1270,7 +1271,7 @@
 
         /** @hide */
         @Retention(RetentionPolicy.SOURCE)
-        @IntDef(
+        @LongDef(
             flag = true,
             value = {
                     LayoutParams.FLAG2_LAYOUT_IN_DISPLAY_CUTOUT_AREA,
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index d890f32..e146555 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -29,6 +29,7 @@
 import android.util.SparseArray;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -213,7 +214,7 @@
      *
      * @param connectionId The id of a connection for interacting with the system.
      * @param accessibilityWindowId A unique window id. Use
-     *     {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID}
+     *     {@link android.view.accessibility.AccessibilityWindowInfo#ACTIVE_WINDOW_ID}
      *     to query the currently active window.
      * @return The {@link AccessibilityWindowInfo}.
      */
@@ -299,7 +300,7 @@
      *
      * @param connectionId The id of a connection for interacting with the system.
      * @param accessibilityWindowId A unique window id. Use
-     *     {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID}
+     *     {@link android.view.accessibility.AccessibilityWindowInfo#ACTIVE_WINDOW_ID}
      *     to query the currently active window.
      * @param accessibilityNodeId A unique view id or virtual descendant id from
      *     where to start the search. Use
@@ -335,18 +336,19 @@
                 }
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
                 final long identityToken = Binder.clearCallingIdentity();
-                final boolean success;
+                final String[] packageNames;
                 try {
-                    success = connection.findAccessibilityNodeInfoByAccessibilityId(
+                    packageNames = connection.findAccessibilityNodeInfoByAccessibilityId(
                             accessibilityWindowId, accessibilityNodeId, interactionId, this,
                             prefetchFlags, Thread.currentThread().getId(), arguments);
                 } finally {
                     Binder.restoreCallingIdentity(identityToken);
                 }
-                if (success) {
+                if (packageNames != null) {
                     List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
                             interactionId);
-                    finalizeAndCacheAccessibilityNodeInfos(infos, connectionId, bypassCache);
+                    finalizeAndCacheAccessibilityNodeInfos(infos, connectionId,
+                            bypassCache, packageNames);
                     if (infos != null && !infos.isEmpty()) {
                         for (int i = 1; i < infos.size(); i++) {
                             infos.get(i).recycle();
@@ -373,7 +375,7 @@
      *
      * @param connectionId The id of a connection for interacting with the system.
      * @param accessibilityWindowId A unique window id. Use
-     *     {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID}
+     *     {@link android.view.accessibility.AccessibilityWindowInfo#ACTIVE_WINDOW_ID}
      *     to query the currently active window.
      * @param accessibilityNodeId A unique view id or virtual descendant id from
      *     where to start the search. Use
@@ -389,20 +391,21 @@
             if (connection != null) {
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
                 final long identityToken = Binder.clearCallingIdentity();
-                final boolean success;
+                final String[] packageNames;
                 try {
-                    success = connection.findAccessibilityNodeInfosByViewId(
+                    packageNames = connection.findAccessibilityNodeInfosByViewId(
                             accessibilityWindowId, accessibilityNodeId, viewId, interactionId, this,
                             Thread.currentThread().getId());
                 } finally {
                     Binder.restoreCallingIdentity(identityToken);
                 }
 
-                if (success) {
+                if (packageNames != null) {
                     List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
                             interactionId);
                     if (infos != null) {
-                        finalizeAndCacheAccessibilityNodeInfos(infos, connectionId, false);
+                        finalizeAndCacheAccessibilityNodeInfos(infos, connectionId,
+                                false, packageNames);
                         return infos;
                     }
                 }
@@ -426,7 +429,7 @@
      *
      * @param connectionId The id of a connection for interacting with the system.
      * @param accessibilityWindowId A unique window id. Use
-     *     {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID}
+     *     {@link android.view.accessibility.AccessibilityWindowInfo#ACTIVE_WINDOW_ID}
      *     to query the currently active window.
      * @param accessibilityNodeId A unique view id or virtual descendant id from
      *     where to start the search. Use
@@ -442,20 +445,21 @@
             if (connection != null) {
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
                 final long identityToken = Binder.clearCallingIdentity();
-                final boolean success;
+                final String[] packageNames;
                 try {
-                    success = connection.findAccessibilityNodeInfosByText(
+                    packageNames = connection.findAccessibilityNodeInfosByText(
                             accessibilityWindowId, accessibilityNodeId, text, interactionId, this,
                             Thread.currentThread().getId());
                 } finally {
                     Binder.restoreCallingIdentity(identityToken);
                 }
 
-                if (success) {
+                if (packageNames != null) {
                     List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
                             interactionId);
                     if (infos != null) {
-                        finalizeAndCacheAccessibilityNodeInfos(infos, connectionId, false);
+                        finalizeAndCacheAccessibilityNodeInfos(infos, connectionId,
+                                false, packageNames);
                         return infos;
                     }
                 }
@@ -478,7 +482,7 @@
      *
      * @param connectionId The id of a connection for interacting with the system.
      * @param accessibilityWindowId A unique window id. Use
-     *     {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID}
+     *     {@link android.view.accessibility.AccessibilityWindowInfo#ACTIVE_WINDOW_ID}
      *     to query the currently active window.
      * @param accessibilityNodeId A unique view id or virtual descendant id from
      *     where to start the search. Use
@@ -494,19 +498,19 @@
             if (connection != null) {
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
                 final long identityToken = Binder.clearCallingIdentity();
-                final boolean success;
+                final String[] packageNames;
                 try {
-                    success = connection.findFocus(accessibilityWindowId,
+                    packageNames = connection.findFocus(accessibilityWindowId,
                             accessibilityNodeId, focusType, interactionId, this,
                             Thread.currentThread().getId());
                 } finally {
                     Binder.restoreCallingIdentity(identityToken);
                 }
 
-                if (success) {
+                if (packageNames != null) {
                     AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
                             interactionId);
-                    finalizeAndCacheAccessibilityNodeInfo(info, connectionId, false);
+                    finalizeAndCacheAccessibilityNodeInfo(info, connectionId, false, packageNames);
                     return info;
                 }
             } else {
@@ -527,7 +531,7 @@
      *
      * @param connectionId The id of a connection for interacting with the system.
      * @param accessibilityWindowId A unique window id. Use
-     *     {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID}
+     *     {@link android.view.accessibility.AccessibilityWindowInfo#ACTIVE_WINDOW_ID}
      *     to query the currently active window.
      * @param accessibilityNodeId A unique view id or virtual descendant id from
      *     where to start the search. Use
@@ -543,19 +547,19 @@
             if (connection != null) {
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
                 final long identityToken = Binder.clearCallingIdentity();
-                final boolean success;
+                final String[] packageNames;
                 try {
-                    success = connection.focusSearch(accessibilityWindowId,
+                    packageNames = connection.focusSearch(accessibilityWindowId,
                             accessibilityNodeId, direction, interactionId, this,
                             Thread.currentThread().getId());
                 } finally {
                     Binder.restoreCallingIdentity(identityToken);
                 }
 
-                if (success) {
+                if (packageNames != null) {
                     AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
                             interactionId);
-                    finalizeAndCacheAccessibilityNodeInfo(info, connectionId, false);
+                    finalizeAndCacheAccessibilityNodeInfo(info, connectionId, false, packageNames);
                     return info;
                 }
             } else {
@@ -574,7 +578,7 @@
      *
      * @param connectionId The id of a connection for interacting with the system.
      * @param accessibilityWindowId A unique window id. Use
-     *     {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID}
+     *     {@link android.view.accessibility.AccessibilityWindowInfo#ACTIVE_WINDOW_ID}
      *     to query the currently active window.
      * @param accessibilityNodeId A unique view id or virtual descendant id from
      *     where to start the search. Use
@@ -661,7 +665,7 @@
                 int interactionId) {
         synchronized (mInstanceLock) {
             final boolean success = waitForResultTimedLocked(interactionId);
-            List<AccessibilityNodeInfo> result = null;
+            final List<AccessibilityNodeInfo> result;
             if (success) {
                 result = mFindAccessibilityNodeInfosResult;
             } else {
@@ -779,11 +783,19 @@
      * @param connectionId The id of the connection to the system.
      * @param bypassCache Whether or not to bypass the cache. The node is added to the cache if
      *                    this value is {@code false}
+     * @param packageNames The valid package names a node can come from.
      */
     private void finalizeAndCacheAccessibilityNodeInfo(AccessibilityNodeInfo info,
-            int connectionId, boolean bypassCache) {
+            int connectionId, boolean bypassCache, String[] packageNames) {
         if (info != null) {
             info.setConnectionId(connectionId);
+            // Empty array means any package name is Okay
+            if (!ArrayUtils.isEmpty(packageNames)
+                    && !ArrayUtils.contains(packageNames, info.getPackageName().toString())) {
+                // If the node package not one of the valid ones, pick the top one - this
+                // is one of the packages running in the introspected UID.
+                info.setPackageName(packageNames[0]);
+            }
             info.setSealed(true);
             if (!bypassCache) {
                 sAccessibilityCache.add(info);
@@ -798,14 +810,16 @@
      * @param connectionId The id of the connection to the system.
      * @param bypassCache Whether or not to bypass the cache. The nodes are added to the cache if
      *                    this value is {@code false}
+     * @param packageNames The valid package names a node can come from.
      */
     private void finalizeAndCacheAccessibilityNodeInfos(List<AccessibilityNodeInfo> infos,
-            int connectionId, boolean bypassCache) {
+            int connectionId, boolean bypassCache, String[] packageNames) {
         if (infos != null) {
             final int infosCount = infos.size();
             for (int i = 0; i < infosCount; i++) {
                 AccessibilityNodeInfo info = infos.get(i);
-                finalizeAndCacheAccessibilityNodeInfo(info, connectionId, bypassCache);
+                finalizeAndCacheAccessibilityNodeInfo(info, connectionId,
+                        bypassCache, packageNames);
             }
         }
     }
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 35f6acb..b4499d1 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -888,7 +888,7 @@
      * @hide
      */
     public int addAccessibilityInteractionConnection(IWindow windowToken,
-            IAccessibilityInteractionConnection connection) {
+            String packageName, IAccessibilityInteractionConnection connection) {
         final IAccessibilityManager service;
         final int userId;
         synchronized (mLock) {
@@ -899,7 +899,8 @@
             userId = mUserId;
         }
         try {
-            return service.addAccessibilityInteractionConnection(windowToken, connection, userId);
+            return service.addAccessibilityInteractionConnection(windowToken, connection,
+                    packageName, userId);
         } catch (RemoteException re) {
             Log.e(LOG_TAG, "Error while adding an accessibility interaction connection. ", re);
         }
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index faea920..9c2f6bb 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -3695,8 +3695,9 @@
 
         if (DEBUG) {
             builder.append("; sourceNodeId: " + mSourceNodeId);
-            builder.append("; accessibilityViewId: " + getAccessibilityViewId(mSourceNodeId));
-            builder.append("; virtualDescendantId: " + getVirtualDescendantId(mSourceNodeId));
+            builder.append("; windowId: " + mWindowId);
+            builder.append("; accessibilityViewId: ").append(getAccessibilityViewId(mSourceNodeId));
+            builder.append("; virtualDescendantId: ").append(getVirtualDescendantId(mSourceNodeId));
             builder.append("; mParentNodeId: " + mParentNodeId);
             builder.append("; traversalBefore: ").append(mTraversalBefore);
             builder.append("; traversalAfter: ").append(mTraversalAfter);
@@ -3726,8 +3727,8 @@
             builder.append("]");
         }
 
-        builder.append("; boundsInParent: " + mBoundsInParent);
-        builder.append("; boundsInScreen: " + mBoundsInScreen);
+        builder.append("; boundsInParent: ").append(mBoundsInParent);
+        builder.append("; boundsInScreen: ").append(mBoundsInScreen);
 
         builder.append("; packageName: ").append(mPackageName);
         builder.append("; className: ").append(mClassName);
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 3f499ab..c93e2c1 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -45,7 +45,8 @@
     List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType, int userId);
 
     int addAccessibilityInteractionConnection(IWindow windowToken,
-            in IAccessibilityInteractionConnection connection, int userId);
+            in IAccessibilityInteractionConnection connection,
+            String packageName, int userId);
 
     void removeAccessibilityInteractionConnection(IWindow windowToken);
 
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 4d96733..3cd8d4a 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -24,6 +24,7 @@
 import android.annotation.SystemService;
 import android.content.Context;
 import android.graphics.Rect;
+import android.inputmethodservice.InputMethodService;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -735,7 +736,20 @@
         }
     }
 
+    /**
+     * @deprecated Use {@link InputMethodService#showStatusIcon(int)} instead. This method was
+     * intended for IME developers who should be accessing APIs through the service. APIs in this
+     * class are intended for app developers interacting with the IME.
+     */
+    @Deprecated
     public void showStatusIcon(IBinder imeToken, String packageName, int iconId) {
+        showStatusIconInternal(imeToken, packageName, iconId);
+    }
+
+    /**
+     * @hide
+     */
+    public void showStatusIconInternal(IBinder imeToken, String packageName, int iconId) {
         try {
             mService.updateStatusIcon(imeToken, packageName, iconId);
         } catch (RemoteException e) {
@@ -743,7 +757,20 @@
         }
     }
 
+    /**
+     * @deprecated Use {@link InputMethodService#hideStatusIcon()} instead. This method was
+     * intended for IME developers who should be accessing APIs through the service. APIs in
+     * this class are intended for app developers interacting with the IME.
+     */
+    @Deprecated
     public void hideStatusIcon(IBinder imeToken) {
+        hideStatusIconInternal(imeToken);
+    }
+
+    /**
+     * @hide
+     */
+    public void hideStatusIconInternal(IBinder imeToken) {
         try {
             mService.updateStatusIcon(imeToken, null, 0);
         } catch (RemoteException e) {
@@ -1121,7 +1148,6 @@
         }
     }
 
-
     /**
      * This method toggles the input method window display.
      * If the input window is already displayed, it gets hidden.
@@ -1800,8 +1826,19 @@
      * when it was started, which allows it to perform this operation on
      * itself.
      * @param id The unique identifier for the new input method to be switched to.
+     * @deprecated Use {@link InputMethodService#setInputMethod(String)} instead. This method
+     * was intended for IME developers who should be accessing APIs through the service. APIs in
+     * this class are intended for app developers interacting with the IME.
      */
+    @Deprecated
     public void setInputMethod(IBinder token, String id) {
+        setInputMethodInternal(token, id);
+    }
+
+    /**
+     * @hide
+     */
+    public void setInputMethodInternal(IBinder token, String id) {
         try {
             mService.setInputMethod(token, id);
         } catch (RemoteException e) {
@@ -1817,8 +1854,21 @@
      * itself.
      * @param id The unique identifier for the new input method to be switched to.
      * @param subtype The new subtype of the new input method to be switched to.
+     * @deprecated Use
+     * {@link InputMethodService#setInputMethodAndSubtype(String, InputMethodSubtype)}
+     * instead. This method was intended for IME developers who should be accessing APIs through
+     * the service. APIs in this class are intended for app developers interacting with the IME.
      */
+    @Deprecated
     public void setInputMethodAndSubtype(IBinder token, String id, InputMethodSubtype subtype) {
+        setInputMethodAndSubtypeInternal(token, id, subtype);
+    }
+
+    /**
+     * @hide
+     */
+    public void setInputMethodAndSubtypeInternal(
+            IBinder token, String id, InputMethodSubtype subtype) {
         try {
             mService.setInputMethodAndSubtype(token, id, subtype);
         } catch (RemoteException e) {
@@ -1837,8 +1887,19 @@
      * @param flags Provides additional operating flags.  Currently may be
      * 0 or have the {@link #HIDE_IMPLICIT_ONLY},
      * {@link #HIDE_NOT_ALWAYS} bit set.
+     * @deprecated Use {@link InputMethodService#hideSoftInputFromInputMethod(int)}
+     * instead. This method was intended for IME developers who should be accessing APIs through
+     * the service. APIs in this class are intended for app developers interacting with the IME.
      */
+    @Deprecated
     public void hideSoftInputFromInputMethod(IBinder token, int flags) {
+        hideSoftInputFromInputMethodInternal(token, flags);
+    }
+
+    /**
+     * @hide
+     */
+    public void hideSoftInputFromInputMethodInternal(IBinder token, int flags) {
         try {
             mService.hideMySoftInput(token, flags);
         } catch (RemoteException e) {
@@ -1858,8 +1919,19 @@
      * @param flags Provides additional operating flags.  Currently may be
      * 0 or have the {@link #SHOW_IMPLICIT} or
      * {@link #SHOW_FORCED} bit set.
+     * @deprecated Use {@link InputMethodService#showSoftInputFromInputMethod(int)}
+     * instead. This method was intended for IME developers who should be accessing APIs through
+     * the service. APIs in this class are intended for app developers interacting with the IME.
      */
+    @Deprecated
     public void showSoftInputFromInputMethod(IBinder token, int flags) {
+        showSoftInputFromInputMethodInternal(token, flags);
+    }
+
+    /**
+     * @hide
+     */
+    public void showSoftInputFromInputMethodInternal(IBinder token, int flags) {
         try {
             mService.showMySoftInput(token, flags);
         } catch (RemoteException e) {
@@ -2239,8 +2311,19 @@
      * which allows it to perform this operation on itself.
      * @return true if the current input method and subtype was successfully switched to the last
      * used input method and subtype.
+     * @deprecated Use {@link InputMethodService#switchToLastInputMethod()} instead. This method
+     * was intended for IME developers who should be accessing APIs through the service. APIs in
+     * this class are intended for app developers interacting with the IME.
      */
+    @Deprecated
     public boolean switchToLastInputMethod(IBinder imeToken) {
+        return switchToLastInputMethodInternal(imeToken);
+    }
+
+    /**
+     * @hide
+     */
+    public boolean switchToLastInputMethodInternal(IBinder imeToken) {
         synchronized (mH) {
             try {
                 return mService.switchToLastInputMethod(imeToken);
@@ -2259,8 +2342,19 @@
      * belongs to the current IME
      * @return true if the current input method and subtype was successfully switched to the next
      * input method and subtype.
+     * @deprecated Use {@link InputMethodService#switchToNextInputMethod(boolean)} instead. This
+     * method was intended for IME developers who should be accessing APIs through the service.
+     * APIs in this class are intended for app developers interacting with the IME.
      */
+    @Deprecated
     public boolean switchToNextInputMethod(IBinder imeToken, boolean onlyCurrentIme) {
+        return switchToNextInputMethodInternal(imeToken, onlyCurrentIme);
+    }
+
+    /**
+     * @hide
+     */
+    public boolean switchToNextInputMethodInternal(IBinder imeToken, boolean onlyCurrentIme) {
         synchronized (mH) {
             try {
                 return mService.switchToNextInputMethod(imeToken, onlyCurrentIme);
@@ -2280,8 +2374,19 @@
      * between IMEs and subtypes.
      * @param imeToken Supplies the identifying token given to an input method when it was started,
      * which allows it to perform this operation on itself.
+     * @deprecated Use {@link InputMethodService#shouldOfferSwitchingToNextInputMethod()}
+     * instead. This method was intended for IME developers who should be accessing APIs through
+     * the service. APIs in this class are intended for app developers interacting with the IME.
      */
+    @Deprecated
     public boolean shouldOfferSwitchingToNextInputMethod(IBinder imeToken) {
+        return shouldOfferSwitchingToNextInputMethodInternal(imeToken);
+    }
+
+    /**
+     * @hide
+     */
+    public boolean shouldOfferSwitchingToNextInputMethodInternal(IBinder imeToken) {
         synchronized (mH) {
             try {
                 return mService.shouldOfferSwitchingToNextInputMethod(imeToken);
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index f4cbc54..fdc9f92 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -48,8 +48,13 @@
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
-    @StringDef({
-            TYPE_UNKNOWN, TYPE_OTHER, TYPE_EMAIL, TYPE_PHONE, TYPE_ADDRESS, TYPE_URL
+    @StringDef(prefix = { "TYPE_" }, value = {
+            TYPE_UNKNOWN,
+            TYPE_OTHER,
+            TYPE_EMAIL,
+            TYPE_PHONE,
+            TYPE_ADDRESS,
+            TYPE_URL,
     })
     @interface EntityType {}
 
diff --git a/core/java/com/android/internal/graphics/SfVsyncFrameCallbackProvider.java b/core/java/com/android/internal/graphics/SfVsyncFrameCallbackProvider.java
index 931eb99..45555bf 100644
--- a/core/java/com/android/internal/graphics/SfVsyncFrameCallbackProvider.java
+++ b/core/java/com/android/internal/graphics/SfVsyncFrameCallbackProvider.java
@@ -26,7 +26,15 @@
  */
 public final class SfVsyncFrameCallbackProvider implements AnimationFrameCallbackProvider {
 
-    private final Choreographer mChoreographer = Choreographer.getSfInstance();
+    private final Choreographer mChoreographer;
+
+    public SfVsyncFrameCallbackProvider() {
+        mChoreographer = Choreographer.getSfInstance();
+    }
+
+    public SfVsyncFrameCallbackProvider(Choreographer choreographer) {
+        mChoreographer = choreographer;
+    }
 
     @Override
     public void postFrameCallback(Choreographer.FrameCallback callback) {
diff --git a/core/jni/eventlog_helper.h b/core/jni/eventlog_helper.h
index 19628e5..3a05195 100644
--- a/core/jni/eventlog_helper.h
+++ b/core/jni/eventlog_helper.h
@@ -155,6 +155,11 @@
             return;
         }
 
+        ScopedIntArrayRO tags(env);
+        if (jTags != nullptr) {
+            tags.reset(jTags);
+        }
+
         while (1) {
             log_msg log_msg;
             int ret = android_logger_list_read(logger_list.get(), &log_msg);
@@ -182,7 +187,6 @@
 
             if (jTags != nullptr) {
                 bool found = false;
-                ScopedIntArrayRO tags(env, jTags);
                 for (size_t i = 0; !found && i < tags.size(); ++i) {
                     found = (tag == tags[i]);
                 }
diff --git a/core/tests/coretests/src/android/security/recoverablekeystore/RecoverableKeyGeneratorTest.java b/core/tests/coretests/src/android/security/recoverablekeystore/RecoverableKeyGeneratorTest.java
new file mode 100644
index 0000000..d85d3b8
--- /dev/null
+++ b/core/tests/coretests/src/android/security/recoverablekeystore/RecoverableKeyGeneratorTest.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.recoverablekeystore;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.security.keystore.AndroidKeyStoreSecretKey;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+import android.security.keystore.KeyProtection;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.security.KeyStore;
+
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RecoverableKeyGeneratorTest {
+    private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore";
+    private static final String KEY_ALGORITHM = "AES";
+    private static final String TEST_ALIAS = "karlin";
+    private static final String WRAPPING_KEY_ALIAS = "RecoverableKeyGeneratorTestWrappingKey";
+
+    @Mock RecoverableKeyStorage mRecoverableKeyStorage;
+
+    @Captor ArgumentCaptor<KeyProtection> mKeyProtectionArgumentCaptor;
+
+    private AndroidKeyStoreSecretKey mPlatformKey;
+    private SecretKey mKeyHandle;
+    private RecoverableKeyGenerator mRecoverableKeyGenerator;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mPlatformKey = generateAndroidKeyStoreKey();
+        mKeyHandle = generateKey();
+        mRecoverableKeyGenerator = RecoverableKeyGenerator.newInstance(
+                mPlatformKey, mRecoverableKeyStorage);
+
+        when(mRecoverableKeyStorage.loadFromAndroidKeyStore(any())).thenReturn(mKeyHandle);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER);
+        keyStore.load(/*param=*/ null);
+        keyStore.deleteEntry(WRAPPING_KEY_ALIAS);
+    }
+
+    @Test
+    public void generateAndStoreKey_setsKeyInKeyStore() throws Exception {
+        mRecoverableKeyGenerator.generateAndStoreKey(TEST_ALIAS);
+
+        verify(mRecoverableKeyStorage, times(1))
+                .importIntoAndroidKeyStore(eq(TEST_ALIAS), any(), any());
+    }
+
+    @Test
+    public void generateAndStoreKey_storesKeyEnabledForEncryptDecrypt() throws Exception {
+        mRecoverableKeyGenerator.generateAndStoreKey(TEST_ALIAS);
+
+        KeyProtection keyProtection = getKeyProtectionUsed();
+        assertEquals(KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT,
+                keyProtection.getPurposes());
+    }
+
+    @Test
+    public void generateAndStoreKey_storesKeyEnabledForGCM() throws Exception {
+        mRecoverableKeyGenerator.generateAndStoreKey(TEST_ALIAS);
+
+        KeyProtection keyProtection = getKeyProtectionUsed();
+        assertArrayEquals(new String[] { KeyProperties.BLOCK_MODE_GCM },
+                keyProtection.getBlockModes());
+    }
+
+    @Test
+    public void generateAndStoreKey_storesKeyEnabledForNoPadding() throws Exception {
+        mRecoverableKeyGenerator.generateAndStoreKey(TEST_ALIAS);
+
+        KeyProtection keyProtection = getKeyProtectionUsed();
+        assertArrayEquals(new String[] { KeyProperties.ENCRYPTION_PADDING_NONE },
+                keyProtection.getEncryptionPaddings());
+    }
+
+    @Test
+    public void generateAndStoreKey_storesWrappedKey() throws Exception {
+        mRecoverableKeyGenerator.generateAndStoreKey(TEST_ALIAS);
+
+        verify(mRecoverableKeyStorage, times(1)).persistToDisk(eq(TEST_ALIAS), any());
+    }
+
+    @Test
+    public void generateAndStoreKey_returnsKeyHandle() throws Exception {
+        SecretKey secretKey = mRecoverableKeyGenerator.generateAndStoreKey(TEST_ALIAS);
+
+        assertEquals(mKeyHandle, secretKey);
+    }
+
+    private KeyProtection getKeyProtectionUsed() throws Exception {
+        verify(mRecoverableKeyStorage, times(1)).importIntoAndroidKeyStore(
+                any(), any(), mKeyProtectionArgumentCaptor.capture());
+        return mKeyProtectionArgumentCaptor.getValue();
+    }
+
+    private SecretKey generateKey() throws Exception {
+        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
+        keyGenerator.init(/*keySize=*/ 256);
+        return keyGenerator.generateKey();
+    }
+
+    private AndroidKeyStoreSecretKey generateAndroidKeyStoreKey() throws Exception {
+        KeyGenerator keyGenerator = KeyGenerator.getInstance(
+                KEY_ALGORITHM,
+                ANDROID_KEY_STORE_PROVIDER);
+        keyGenerator.init(new KeyGenParameterSpec.Builder(
+                WRAPPING_KEY_ALIAS, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+                    .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
+                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+                    .build());
+        return (AndroidKeyStoreSecretKey) keyGenerator.generateKey();
+    }
+}
diff --git a/core/tests/coretests/src/android/security/recoverablekeystore/WrappedKeyTest.java b/core/tests/coretests/src/android/security/recoverablekeystore/WrappedKeyTest.java
new file mode 100644
index 0000000..233c821
--- /dev/null
+++ b/core/tests/coretests/src/android/security/recoverablekeystore/WrappedKeyTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.recoverablekeystore;
+
+import static org.junit.Assert.assertEquals;
+
+import android.security.keystore.AndroidKeyStoreSecretKey;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.security.KeyStore;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.GCMParameterSpec;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class WrappedKeyTest {
+    private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore";
+    private static final String KEY_ALGORITHM = "AES";
+    private static final String CIPHER_ALGORITHM = "AES/GCM/NoPadding";
+    private static final String WRAPPING_KEY_ALIAS = "WrappedKeyTestWrappingKeyAlias";
+    private static final int GCM_TAG_LENGTH_BYTES = 16;
+    private static final int BITS_PER_BYTE = 8;
+    private static final int GCM_TAG_LENGTH_BITS = GCM_TAG_LENGTH_BYTES * BITS_PER_BYTE;
+
+    @After
+    public void tearDown() throws Exception {
+        KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER);
+        keyStore.load(/*param=*/ null);
+        keyStore.deleteEntry(WRAPPING_KEY_ALIAS);
+    }
+
+    @Test
+    public void fromSecretKey_createsWrappedKeyThatCanBeUnwrapped() throws Exception {
+        SecretKey wrappingKey = generateAndroidKeyStoreKey();
+        SecretKey rawKey = generateKey();
+
+        WrappedKey wrappedKey = WrappedKey.fromSecretKey(wrappingKey, rawKey);
+
+        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
+        cipher.init(
+                Cipher.UNWRAP_MODE,
+                wrappingKey,
+                new GCMParameterSpec(GCM_TAG_LENGTH_BITS, wrappedKey.getNonce()));
+        SecretKey unwrappedKey = (SecretKey) cipher.unwrap(
+                wrappedKey.getKeyMaterial(), KEY_ALGORITHM, Cipher.SECRET_KEY);
+        assertEquals(rawKey, unwrappedKey);
+    }
+
+    private SecretKey generateKey() throws Exception {
+        KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
+        keyGenerator.init(/*keySize=*/ 256);
+        return keyGenerator.generateKey();
+    }
+
+    private AndroidKeyStoreSecretKey generateAndroidKeyStoreKey() throws Exception {
+        KeyGenerator keyGenerator = KeyGenerator.getInstance(
+                KEY_ALGORITHM,
+                ANDROID_KEY_STORE_PROVIDER);
+        keyGenerator.init(new KeyGenParameterSpec.Builder(
+                WRAPPING_KEY_ALIAS, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+                .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
+                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+                .build());
+        return (AndroidKeyStoreSecretKey) keyGenerator.generateKey();
+    }
+}
diff --git a/core/tests/coretests/src/android/util/ScrollViewScenario.java b/core/tests/coretests/src/android/util/ScrollViewScenario.java
index b5140e3..e9eb978 100644
--- a/core/tests/coretests/src/android/util/ScrollViewScenario.java
+++ b/core/tests/coretests/src/android/util/ScrollViewScenario.java
@@ -269,6 +269,6 @@
         mScrollView.setSmoothScrollingEnabled(false);
 
         setContentView(mScrollView);
-        mScrollView.restoreDefaultFocus();
+        mScrollView.post(() -> mScrollView.restoreDefaultFocus());
     }
 }
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java
index 8a5fc2d..c1b2309 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java
@@ -24,6 +24,7 @@
 import android.os.RemoteException;
 import android.support.test.runner.AndroidJUnit4;
 
+import libcore.util.EmptyArray;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -73,7 +74,7 @@
         List<AccessibilityNodeInfo> mInfosToReturn;
 
         @Override
-        public boolean findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
+        public String[] findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
                 long accessibilityNodeId, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, int flags, long threadId,
                 Bundle arguments) {
@@ -82,7 +83,7 @@
             } catch (RemoteException e) {
                 throw new RuntimeException(e);
             }
-            return true;
+            return EmptyArray.STRING;
         }
     }
 }
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
index d3bbee7..44b1f08 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
@@ -31,35 +31,35 @@
 public class AccessibilityServiceConnectionImpl extends IAccessibilityServiceConnection.Stub {
     public void setServiceInfo(AccessibilityServiceInfo info) {}
 
-    public boolean findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
+    public String[] findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
             long accessibilityNodeId, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, int flags, long threadId,
             Bundle arguments) {
-        return false;
+        return null;
     }
 
-    public boolean findAccessibilityNodeInfosByText(int accessibilityWindowId,
+    public String[] findAccessibilityNodeInfosByText(int accessibilityWindowId,
             long accessibilityNodeId, String text, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, long threadId) {
-        return false;
+        return null;
     }
 
-    public boolean findAccessibilityNodeInfosByViewId(int accessibilityWindowId,
+    public String[] findAccessibilityNodeInfosByViewId(int accessibilityWindowId,
             long accessibilityNodeId, String viewId, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, long threadId) {
-        return false;
+        return null;
     }
 
-    public boolean findFocus(int accessibilityWindowId, long accessibilityNodeId, int focusType,
+    public String[] findFocus(int accessibilityWindowId, long accessibilityNodeId, int focusType,
             int interactionId, IAccessibilityInteractionConnectionCallback callback,
             long threadId) {
-        return false;
+        return null;
     }
 
-    public boolean focusSearch(int accessibilityWindowId, long accessibilityNodeId, int direction,
+    public String[] focusSearch(int accessibilityWindowId, long accessibilityNodeId, int direction,
             int interactionId, IAccessibilityInteractionConnectionCallback callback,
             long threadId) {
-        return false;
+        return null;
     }
 
     public boolean performAccessibilityAction(int accessibilityWindowId, long accessibilityNodeId,
diff --git a/keystore/java/android/security/keystore/KeyProperties.java b/keystore/java/android/security/keystore/KeyProperties.java
index d6b1cf1..a250d1f0 100644
--- a/keystore/java/android/security/keystore/KeyProperties.java
+++ b/keystore/java/android/security/keystore/KeyProperties.java
@@ -39,13 +39,12 @@
      * @hide
      */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag = true,
-            value = {
-                PURPOSE_ENCRYPT,
-                PURPOSE_DECRYPT,
-                PURPOSE_SIGN,
-                PURPOSE_VERIFY,
-                })
+    @IntDef(flag = true, prefix = { "PURPOSE_" }, value = {
+            PURPOSE_ENCRYPT,
+            PURPOSE_DECRYPT,
+            PURPOSE_SIGN,
+            PURPOSE_VERIFY,
+    })
     public @interface PurposeEnum {}
 
     /**
@@ -126,7 +125,7 @@
      * @hide
      */
     @Retention(RetentionPolicy.SOURCE)
-    @StringDef({
+    @StringDef(prefix = { "KEY_" }, value = {
         KEY_ALGORITHM_RSA,
         KEY_ALGORITHM_EC,
         KEY_ALGORITHM_AES,
@@ -267,7 +266,7 @@
      * @hide
      */
     @Retention(RetentionPolicy.SOURCE)
-    @StringDef({
+    @StringDef(prefix = { "BLOCK_MODE_" }, value = {
         BLOCK_MODE_ECB,
         BLOCK_MODE_CBC,
         BLOCK_MODE_CTR,
@@ -354,7 +353,7 @@
      * @hide
      */
     @Retention(RetentionPolicy.SOURCE)
-    @StringDef({
+    @StringDef(prefix = { "ENCRYPTION_PADDING_" }, value = {
         ENCRYPTION_PADDING_NONE,
         ENCRYPTION_PADDING_PKCS7,
         ENCRYPTION_PADDING_RSA_PKCS1,
@@ -437,7 +436,7 @@
      * @hide
      */
     @Retention(RetentionPolicy.SOURCE)
-    @StringDef({
+    @StringDef(prefix = { "SIGNATURE_PADDING_" }, value = {
         SIGNATURE_PADDING_RSA_PKCS1,
         SIGNATURE_PADDING_RSA_PSS,
         })
@@ -497,7 +496,7 @@
      * @hide
      */
     @Retention(RetentionPolicy.SOURCE)
-    @StringDef({
+    @StringDef(prefix = { "DIGEST_" }, value = {
         DIGEST_NONE,
         DIGEST_MD5,
         DIGEST_SHA1,
@@ -647,11 +646,12 @@
      * @hide
      */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({
-        ORIGIN_GENERATED,
-        ORIGIN_IMPORTED,
-        ORIGIN_UNKNOWN,
-        })
+    @IntDef(prefix = { "ORIGIN_" }, value = {
+            ORIGIN_GENERATED,
+            ORIGIN_IMPORTED,
+            ORIGIN_UNKNOWN,
+    })
+
     public @interface OriginEnum {}
 
     /** Key was generated inside AndroidKeyStore. */
diff --git a/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
index b15e0a2..7cb8e37 100644
--- a/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
@@ -81,12 +81,16 @@
         }
         out.writeByteArray(mSpec.getCertificateSubject().getEncoded());
         out.writeByteArray(mSpec.getCertificateSerialNumber().toByteArray());
-        writeOptionalDate(out, mSpec.getCertificateNotBefore());
-        writeOptionalDate(out, mSpec.getCertificateNotAfter());
+        out.writeLong(mSpec.getCertificateNotBefore().getTime());
+        out.writeLong(mSpec.getCertificateNotAfter().getTime());
         writeOptionalDate(out, mSpec.getKeyValidityStart());
         writeOptionalDate(out, mSpec.getKeyValidityForOriginationEnd());
         writeOptionalDate(out, mSpec.getKeyValidityForConsumptionEnd());
-        out.writeStringArray(mSpec.getDigests());
+        if (mSpec.isDigestsSpecified()) {
+            out.writeStringArray(mSpec.getDigests());
+        } else {
+            out.writeStringArray(null);
+        }
         out.writeStringArray(mSpec.getEncryptionPaddings());
         out.writeStringArray(mSpec.getSignaturePaddings());
         out.writeStringArray(mSpec.getBlockModes());
@@ -111,9 +115,15 @@
     private ParcelableKeyGenParameterSpec(Parcel in) {
         String keystoreAlias = in.readString();
         int purposes = in.readInt();
-        KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(keystoreAlias, purposes);
+        KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(
+                keystoreAlias, purposes);
         builder.setUid(in.readInt());
-        builder.setKeySize(in.readInt());
+        // KeySize is -1 by default, if the KeyGenParameterSpec previously parcelled had the default
+        // value, do not set it as this will cause setKeySize to throw.
+        int keySize = in.readInt();
+        if (keySize >= 0) {
+            builder.setKeySize(keySize);
+        }
 
         int keySpecType = in.readInt();
         AlgorithmParameterSpec algorithmSpec = null;
@@ -128,17 +138,22 @@
             algorithmSpec = new ECGenParameterSpec(stdName);
         } else {
             throw new IllegalArgumentException(
-                    String.format("Unknown algorithm parameter spec: %d", algorithmSpec));
+                    String.format("Unknown algorithm parameter spec: %d", keySpecType));
         }
-        builder.setAlgorithmParameterSpec(algorithmSpec);
+        if (algorithmSpec != null) {
+            builder.setAlgorithmParameterSpec(algorithmSpec);
+        }
         builder.setCertificateSubject(new X500Principal(in.createByteArray()));
         builder.setCertificateSerialNumber(new BigInteger(in.createByteArray()));
-        builder.setCertificateNotBefore(readDateOrNull(in));
-        builder.setCertificateNotAfter(readDateOrNull(in));
+        builder.setCertificateNotBefore(new Date(in.readLong()));
+        builder.setCertificateNotAfter(new Date(in.readLong()));
         builder.setKeyValidityStart(readDateOrNull(in));
         builder.setKeyValidityForOriginationEnd(readDateOrNull(in));
         builder.setKeyValidityForConsumptionEnd(readDateOrNull(in));
-        builder.setDigests(in.createStringArray());
+        String[] digests = in.createStringArray();
+        if (digests != null) {
+            builder.setDigests(digests);
+        }
         builder.setEncryptionPaddings(in.createStringArray());
         builder.setSignaturePaddings(in.createStringArray());
         builder.setBlockModes(in.createStringArray());
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 96e4fcf..7cacaf6 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -122,7 +122,7 @@
         instrumentation: true,
         profile_file: "hwui/hwui.profdata",
         benchmarks: ["hwui"],
-        enable_profile_use: false,
+        enable_profile_use: true,
     },
 }
 
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
index 288d039..107890e 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
@@ -45,8 +45,7 @@
     if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
         sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface());
         LOG_ALWAYS_FATAL_IF(!glInterface.get());
-        grContext.reset(GrContext::Create(GrBackend::kOpenGL_GrBackend,
-                                          (GrBackendContext)glInterface.get()));
+        grContext = GrContext::MakeGL(std::move(glInterface));
     } else {
         grContext->resetContext();
     }
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index 5e89fae..907f2d2 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -53,13 +53,13 @@
     }
 }
 
-void CacheManager::reset(GrContext* context) {
-    if (context != mGrContext.get()) {
+void CacheManager::reset(sk_sp<GrContext> context) {
+    if (context != mGrContext) {
         destroy();
     }
 
     if (context) {
-        mGrContext = sk_ref_sp(context);
+        mGrContext = std::move(context);
         mGrContext->getResourceCacheLimits(&mMaxResources, nullptr);
         updateContextCacheSizes();
     }
diff --git a/libs/hwui/renderthread/CacheManager.h b/libs/hwui/renderthread/CacheManager.h
index d037045..7d73352 100644
--- a/libs/hwui/renderthread/CacheManager.h
+++ b/libs/hwui/renderthread/CacheManager.h
@@ -61,7 +61,7 @@
 
     CacheManager(const DisplayInfo& display);
 
-    void reset(GrContext* grContext);
+    void reset(sk_sp<GrContext> grContext);
     void destroy();
     void updateContextCacheSizes();
 
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 4df7caf..848c6a8 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -141,8 +141,9 @@
         GrContextOptions options;
         options.fDisableDistanceFieldPaths = true;
         mRenderThread.cacheManager().configureContext(&options);
-        mRenderThread.setGrContext(GrContext::Create(GrBackend::kOpenGL_GrBackend,
-                                                     (GrBackendContext)glInterface.get(), options));
+        sk_sp<GrContext> grContext(GrContext::MakeGL(std::move(glInterface), options));
+        LOG_ALWAYS_FATAL_IF(!grContext.get());
+        mRenderThread.setGrContext(grContext);
     }
 }
 
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 20443ec..79dc09f 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -173,12 +173,12 @@
     return *mReadback;
 }
 
-void RenderThread::setGrContext(GrContext* context) {
+void RenderThread::setGrContext(sk_sp<GrContext> context) {
     mCacheManager->reset(context);
-    if (mGrContext.get()) {
+    if (mGrContext) {
         mGrContext->releaseResourcesAndAbandonContext();
     }
-    mGrContext.reset(context);
+    mGrContext = std::move(context);
 }
 
 int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 970537b..3aa5487 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -88,7 +88,7 @@
     const DisplayInfo& mainDisplayInfo() { return mDisplayInfo; }
 
     GrContext* getGrContext() const { return mGrContext.get(); }
-    void setGrContext(GrContext* cxt);
+    void setGrContext(sk_sp<GrContext> cxt);
 
     CacheManager& cacheManager() { return *mCacheManager; }
     VulkanManager& vulkanManager() { return *mVkManager; }
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index a693e68..9d246ff 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -58,6 +58,7 @@
 
     mBackendContext.reset(GrVkBackendContext::Create(vkGetInstanceProcAddr, vkGetDeviceProcAddr,
                                                      &mPresentQueueIndex, canPresent));
+    LOG_ALWAYS_FATAL_IF(!mBackendContext.get());
 
     // Get all the addresses of needed vulkan functions
     VkInstance instance = mBackendContext->fInstance;
@@ -110,8 +111,9 @@
     GrContextOptions options;
     options.fDisableDistanceFieldPaths = true;
     mRenderThread.cacheManager().configureContext(&options);
-    mRenderThread.setGrContext(
-            GrContext::Create(kVulkan_GrBackend, (GrBackendContext)mBackendContext.get(), options));
+    sk_sp<GrContext> grContext(GrContext::MakeVulkan(mBackendContext, options));
+    LOG_ALWAYS_FATAL_IF(!grContext.get());
+    mRenderThread.setGrContext(grContext);
     DeviceInfo::initialize(mRenderThread.getGrContext()->caps()->maxRenderTargetSize());
 
     if (Properties::enablePartialUpdates && Properties::useBufferAge) {
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 12e5744..e2f9b47 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -977,7 +977,7 @@
     public static final String PROPERTY_ALGORITHMS = "algorithms";
 
     /** @hide */
-    @StringDef({
+    @StringDef(prefix = { "PROPERTY_" }, value = {
         PROPERTY_VENDOR,
         PROPERTY_VERSION,
         PROPERTY_DESCRIPTION,
@@ -1010,7 +1010,7 @@
     public static final String PROPERTY_DEVICE_UNIQUE_ID = "deviceUniqueId";
 
     /** @hide */
-    @StringDef({
+    @StringDef(prefix = { "PROPERTY_" }, value = {
         PROPERTY_DEVICE_UNIQUE_ID,
     })
     @Retention(RetentionPolicy.SOURCE)
diff --git a/media/java/android/media/MediaMetadata.java b/media/java/android/media/MediaMetadata.java
index 31eb948..94d4d55 100644
--- a/media/java/android/media/MediaMetadata.java
+++ b/media/java/android/media/MediaMetadata.java
@@ -45,34 +45,61 @@
     /**
      * @hide
      */
-    @StringDef({METADATA_KEY_TITLE, METADATA_KEY_ARTIST, METADATA_KEY_ALBUM, METADATA_KEY_AUTHOR,
-            METADATA_KEY_WRITER, METADATA_KEY_COMPOSER, METADATA_KEY_COMPILATION,
-            METADATA_KEY_DATE, METADATA_KEY_GENRE, METADATA_KEY_ALBUM_ARTIST, METADATA_KEY_ART_URI,
-            METADATA_KEY_ALBUM_ART_URI, METADATA_KEY_DISPLAY_TITLE, METADATA_KEY_DISPLAY_SUBTITLE,
-            METADATA_KEY_DISPLAY_DESCRIPTION, METADATA_KEY_DISPLAY_ICON_URI,
-            METADATA_KEY_MEDIA_ID, METADATA_KEY_MEDIA_URI})
+    @StringDef(prefix = { "METADATA_KEY_" }, value = {
+            METADATA_KEY_TITLE,
+            METADATA_KEY_ARTIST,
+            METADATA_KEY_ALBUM,
+            METADATA_KEY_AUTHOR,
+            METADATA_KEY_WRITER,
+            METADATA_KEY_COMPOSER,
+            METADATA_KEY_COMPILATION,
+            METADATA_KEY_DATE,
+            METADATA_KEY_GENRE,
+            METADATA_KEY_ALBUM_ARTIST,
+            METADATA_KEY_ART_URI,
+            METADATA_KEY_ALBUM_ART_URI,
+            METADATA_KEY_DISPLAY_TITLE,
+            METADATA_KEY_DISPLAY_SUBTITLE,
+            METADATA_KEY_DISPLAY_DESCRIPTION,
+            METADATA_KEY_DISPLAY_ICON_URI,
+            METADATA_KEY_MEDIA_ID,
+            METADATA_KEY_MEDIA_URI,
+    })
     @Retention(RetentionPolicy.SOURCE)
     public @interface TextKey {}
 
     /**
      * @hide
      */
-    @StringDef({METADATA_KEY_DURATION, METADATA_KEY_YEAR, METADATA_KEY_TRACK_NUMBER,
-            METADATA_KEY_NUM_TRACKS, METADATA_KEY_DISC_NUMBER, METADATA_KEY_BT_FOLDER_TYPE})
+    @StringDef(prefix = { "METADATA_KEY_" }, value = {
+            METADATA_KEY_DURATION,
+            METADATA_KEY_YEAR,
+            METADATA_KEY_TRACK_NUMBER,
+            METADATA_KEY_NUM_TRACKS,
+            METADATA_KEY_DISC_NUMBER,
+            METADATA_KEY_BT_FOLDER_TYPE,
+    })
     @Retention(RetentionPolicy.SOURCE)
     public @interface LongKey {}
 
     /**
      * @hide
      */
-    @StringDef({METADATA_KEY_ART, METADATA_KEY_ALBUM_ART, METADATA_KEY_DISPLAY_ICON})
+    @StringDef(prefix = { "METADATA_KEY_" }, value = {
+            METADATA_KEY_ART,
+            METADATA_KEY_ALBUM_ART,
+            METADATA_KEY_DISPLAY_ICON,
+    })
     @Retention(RetentionPolicy.SOURCE)
     public @interface BitmapKey {}
 
     /**
      * @hide
      */
-    @StringDef({METADATA_KEY_USER_RATING, METADATA_KEY_RATING})
+    @StringDef(prefix = { "METADATA_KEY_" }, value = {
+            METADATA_KEY_USER_RATING,
+            METADATA_KEY_RATING,
+    })
     @Retention(RetentionPolicy.SOURCE)
     public @interface RatingKey {}
 
diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
index 8283c8b..17d16b8 100644
--- a/media/java/android/media/session/PlaybackState.java
+++ b/media/java/android/media/session/PlaybackState.java
@@ -17,6 +17,7 @@
 
 import android.annotation.DrawableRes;
 import android.annotation.IntDef;
+import android.annotation.LongDef;
 import android.annotation.Nullable;
 import android.media.RemoteControlClient;
 import android.os.Bundle;
@@ -41,7 +42,7 @@
     /**
      * @hide
      */
-    @IntDef(flag=true, value={ACTION_STOP, ACTION_PAUSE, ACTION_PLAY, ACTION_REWIND,
+    @LongDef(flag=true, value={ACTION_STOP, ACTION_PAUSE, ACTION_PLAY, ACTION_REWIND,
             ACTION_SKIP_TO_PREVIOUS, ACTION_SKIP_TO_NEXT, ACTION_FAST_FORWARD, ACTION_SET_RATING,
             ACTION_SEEK_TO, ACTION_PLAY_PAUSE, ACTION_PLAY_FROM_MEDIA_ID, ACTION_PLAY_FROM_SEARCH,
             ACTION_SKIP_TO_QUEUE_ITEM, ACTION_PLAY_FROM_URI, ACTION_PREPARE,
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 0f46096..3bbc2c4 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -1650,7 +1650,7 @@
         public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/channel";
 
         /** @hide */
-        @StringDef({
+        @StringDef(prefix = { "TYPE_" }, value = {
                 TYPE_OTHER,
                 TYPE_NTSC,
                 TYPE_PAL,
@@ -1863,7 +1863,7 @@
         public static final String TYPE_PREVIEW = "TYPE_PREVIEW";
 
         /** @hide */
-        @StringDef({
+        @StringDef(prefix = { "SERVICE_TYPE_" }, value = {
                 SERVICE_TYPE_OTHER,
                 SERVICE_TYPE_AUDIO_VIDEO,
                 SERVICE_TYPE_AUDIO,
@@ -1881,7 +1881,7 @@
         public static final String SERVICE_TYPE_AUDIO = "SERVICE_TYPE_AUDIO";
 
         /** @hide */
-        @StringDef({
+        @StringDef(prefix = { "VIDEO_FORMAT_" }, value = {
                 VIDEO_FORMAT_240P,
                 VIDEO_FORMAT_360P,
                 VIDEO_FORMAT_480I,
@@ -1930,7 +1930,7 @@
         public static final String VIDEO_FORMAT_4320P = "VIDEO_FORMAT_4320P";
 
         /** @hide */
-        @StringDef({
+        @StringDef(prefix = { "VIDEO_RESOLUTION_" }, value = {
                 VIDEO_RESOLUTION_SD,
                 VIDEO_RESOLUTION_ED,
                 VIDEO_RESOLUTION_HD,
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 3b54e11..5c8c3f3 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -333,7 +333,7 @@
             } else if (GLOBAL_ACTION_KEY_RESTART.equals(actionKey)) {
                 mItems.add(new RestartAction());
             } else if (GLOBAL_ACTION_KEY_LOGOUT.equals(actionKey)) {
-                if (mDevicePolicyManager.isLogoutButtonEnabled()
+                if (mDevicePolicyManager.isLogoutEnabled()
                         && getCurrentUser().id != UserHandle.USER_SYSTEM) {
                     mItems.add(new LogoutAction());
                     mHasLogoutButton = true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index 195607d..7374f11 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -448,7 +448,7 @@
                 childState.height = Math.max(row.getIntrinsicHeight(), childState.height);
                 childState.hidden = false;
                 ExpandableViewState topState = resultState.getViewStateForView(topHeadsUpEntry);
-                if (!isTopEntry && (!mIsExpanded
+                if (topState != null && !isTopEntry && (!mIsExpanded
                         || unmodifiedEndLocation < topState.yTranslation + topState.height)) {
                     // Ensure that a headsUp doesn't vertically extend further than the heads-up at
                     // the top most z-position
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityClientConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityClientConnection.java
index 7e94d7b..01679dd 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityClientConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityClientConnection.java
@@ -20,9 +20,7 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
 
-import android.accessibilityservice.AccessibilityService;
 import android.accessibilityservice.AccessibilityServiceInfo;
-import android.accessibilityservice.GestureDescription;
 import android.accessibilityservice.IAccessibilityServiceClient;
 import android.accessibilityservice.IAccessibilityServiceConnection;
 import android.annotation.NonNull;
@@ -49,7 +47,6 @@
 import android.view.View;
 import android.view.accessibility.AccessibilityCache;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityInteractionClient;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityWindowInfo;
 import android.view.accessibility.IAccessibilityInteractionConnection;
@@ -58,6 +55,7 @@
 
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.DumpUtils;
+import com.android.server.accessibility.AccessibilityManagerService.RemoteAccessibilityConnection;
 import com.android.server.accessibility.AccessibilityManagerService.SecurityPolicy;
 import com.android.server.wm.WindowManagerInternal;
 
@@ -171,13 +169,13 @@
         @NonNull MagnificationController getMagnificationController();
 
         /**
-         * Resolve a connection for a window id
+         * Resolve a connection wrapper for a window id
          *
          * @param windowId The id of the window of interest
          *
          * @return a connection to the window
          */
-        IAccessibilityInteractionConnection getConnectionLocked(int windowId);
+        RemoteAccessibilityConnection getConnectionLocked(int windowId);
 
         /**
          * Perform the specified accessibility action
@@ -416,28 +414,28 @@
     }
 
     @Override
-    public boolean findAccessibilityNodeInfosByViewId(int accessibilityWindowId,
+    public String[] findAccessibilityNodeInfosByViewId(int accessibilityWindowId,
             long accessibilityNodeId, String viewIdResName, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
             throws RemoteException {
         final int resolvedWindowId;
-        IAccessibilityInteractionConnection connection = null;
+        RemoteAccessibilityConnection connection;
         Region partialInteractiveRegion = Region.obtain();
         MagnificationSpec spec;
         synchronized (mLock) {
             mUsesAccessibilityCache = true;
             if (!isCalledForCurrentUserLocked()) {
-                return false;
+                return null;
             }
             resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
             final boolean permissionGranted =
                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
             if (!permissionGranted) {
-                return false;
+                return null;
             } else {
                 connection = mSystemSupport.getConnectionLocked(resolvedWindowId);
                 if (connection == null) {
-                    return false;
+                    return null;
                 }
             }
             if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
@@ -450,12 +448,14 @@
         final int interrogatingPid = Binder.getCallingPid();
         callback = mSystemSupport.replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
                 interrogatingPid, interrogatingTid);
+        final int callingUid = Binder.getCallingUid();
         final long identityToken = Binder.clearCallingIdentity();
         try {
-            connection.findAccessibilityNodeInfosByViewId(accessibilityNodeId, viewIdResName,
-                    partialInteractiveRegion, interactionId, callback, mFetchFlags,
+            connection.getRemote().findAccessibilityNodeInfosByViewId(accessibilityNodeId,
+                    viewIdResName, partialInteractiveRegion, interactionId, callback, mFetchFlags,
                     interrogatingPid, interrogatingTid, spec);
-            return true;
+            return mSecurityPolicy.computeValidReportedPackages(callingUid,
+                    connection.getPackageName(), connection.getUid());
         } catch (RemoteException re) {
             if (DEBUG) {
                 Slog.e(LOG_TAG, "Error findAccessibilityNodeInfoByViewId().");
@@ -463,36 +463,36 @@
         } finally {
             Binder.restoreCallingIdentity(identityToken);
             // Recycle if passed to another process.
-            if (partialInteractiveRegion != null && Binder.isProxy(connection)) {
+            if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
                 partialInteractiveRegion.recycle();
             }
         }
-        return false;
+        return null;
     }
 
     @Override
-    public boolean findAccessibilityNodeInfosByText(int accessibilityWindowId,
+    public String[] findAccessibilityNodeInfosByText(int accessibilityWindowId,
             long accessibilityNodeId, String text, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
             throws RemoteException {
         final int resolvedWindowId;
-        IAccessibilityInteractionConnection connection = null;
+        RemoteAccessibilityConnection connection;
         Region partialInteractiveRegion = Region.obtain();
         MagnificationSpec spec;
         synchronized (mLock) {
             mUsesAccessibilityCache = true;
             if (!isCalledForCurrentUserLocked()) {
-                return false;
+                return null;
             }
             resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
             final boolean permissionGranted =
                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
             if (!permissionGranted) {
-                return false;
+                return null;
             } else {
                 connection = mSystemSupport.getConnectionLocked(resolvedWindowId);
                 if (connection == null) {
-                    return false;
+                    return null;
                 }
             }
             if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
@@ -505,12 +505,14 @@
         final int interrogatingPid = Binder.getCallingPid();
         callback = mSystemSupport.replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
                 interrogatingPid, interrogatingTid);
+        final int callingUid = Binder.getCallingUid();
         final long identityToken = Binder.clearCallingIdentity();
         try {
-            connection.findAccessibilityNodeInfosByText(accessibilityNodeId, text,
-                    partialInteractiveRegion, interactionId, callback, mFetchFlags,
+            connection.getRemote().findAccessibilityNodeInfosByText(accessibilityNodeId,
+                    text, partialInteractiveRegion, interactionId, callback, mFetchFlags,
                     interrogatingPid, interrogatingTid, spec);
-            return true;
+            return mSecurityPolicy.computeValidReportedPackages(callingUid,
+                    connection.getPackageName(), connection.getUid());
         } catch (RemoteException re) {
             if (DEBUG) {
                 Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfosByText()");
@@ -518,36 +520,36 @@
         } finally {
             Binder.restoreCallingIdentity(identityToken);
             // Recycle if passed to another process.
-            if (partialInteractiveRegion != null && Binder.isProxy(connection)) {
+            if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
                 partialInteractiveRegion.recycle();
             }
         }
-        return false;
+        return null;
     }
 
     @Override
-    public boolean findAccessibilityNodeInfoByAccessibilityId(
+    public String[] findAccessibilityNodeInfoByAccessibilityId(
             int accessibilityWindowId, long accessibilityNodeId, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, int flags,
             long interrogatingTid, Bundle arguments) throws RemoteException {
         final int resolvedWindowId;
-        IAccessibilityInteractionConnection connection = null;
+        RemoteAccessibilityConnection connection;
         Region partialInteractiveRegion = Region.obtain();
         MagnificationSpec spec;
         synchronized (mLock) {
             mUsesAccessibilityCache = true;
             if (!isCalledForCurrentUserLocked()) {
-                return false;
+                return null;
             }
             resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
             final boolean permissionGranted =
                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
             if (!permissionGranted) {
-                return false;
+                return null;
             } else {
                 connection = mSystemSupport.getConnectionLocked(resolvedWindowId);
                 if (connection == null) {
-                    return false;
+                    return null;
                 }
             }
             if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
@@ -560,12 +562,14 @@
         final int interrogatingPid = Binder.getCallingPid();
         callback = mSystemSupport.replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
                 interrogatingPid, interrogatingTid);
+        final int callingUid = Binder.getCallingUid();
         final long identityToken = Binder.clearCallingIdentity();
         try {
-            connection.findAccessibilityNodeInfoByAccessibilityId(accessibilityNodeId,
-                    partialInteractiveRegion, interactionId, callback, mFetchFlags | flags,
-                    interrogatingPid, interrogatingTid, spec, arguments);
-            return true;
+            connection.getRemote().findAccessibilityNodeInfoByAccessibilityId(
+                    accessibilityNodeId, partialInteractiveRegion, interactionId, callback,
+                    mFetchFlags | flags, interrogatingPid, interrogatingTid, spec, arguments);
+            return mSecurityPolicy.computeValidReportedPackages(callingUid,
+                    connection.getPackageName(), connection.getUid());
         } catch (RemoteException re) {
             if (DEBUG) {
                 Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfoByAccessibilityId()");
@@ -573,36 +577,36 @@
         } finally {
             Binder.restoreCallingIdentity(identityToken);
             // Recycle if passed to another process.
-            if (partialInteractiveRegion != null && Binder.isProxy(connection)) {
+            if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
                 partialInteractiveRegion.recycle();
             }
         }
-        return false;
+        return null;
     }
 
     @Override
-    public boolean findFocus(int accessibilityWindowId, long accessibilityNodeId,
+    public String[] findFocus(int accessibilityWindowId, long accessibilityNodeId,
             int focusType, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
             throws RemoteException {
         final int resolvedWindowId;
-        IAccessibilityInteractionConnection connection = null;
+        RemoteAccessibilityConnection connection;
         Region partialInteractiveRegion = Region.obtain();
         MagnificationSpec spec;
         synchronized (mLock) {
             if (!isCalledForCurrentUserLocked()) {
-                return false;
+                return null;
             }
             resolvedWindowId = resolveAccessibilityWindowIdForFindFocusLocked(
                     accessibilityWindowId, focusType);
             final boolean permissionGranted =
                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
             if (!permissionGranted) {
-                return false;
+                return null;
             } else {
                 connection = mSystemSupport.getConnectionLocked(resolvedWindowId);
                 if (connection == null) {
-                    return false;
+                    return null;
                 }
             }
             if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
@@ -615,12 +619,14 @@
         final int interrogatingPid = Binder.getCallingPid();
         callback = mSystemSupport.replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
                 interrogatingPid, interrogatingTid);
+        final int callingUid = Binder.getCallingUid();
         final long identityToken = Binder.clearCallingIdentity();
         try {
-            connection.findFocus(accessibilityNodeId, focusType, partialInteractiveRegion,
-                    interactionId, callback, mFetchFlags, interrogatingPid, interrogatingTid,
-                    spec);
-            return true;
+            connection.getRemote().findFocus(accessibilityNodeId, focusType,
+                    partialInteractiveRegion, interactionId, callback, mFetchFlags,
+                    interrogatingPid, interrogatingTid, spec);
+            return mSecurityPolicy.computeValidReportedPackages(callingUid,
+                    connection.getPackageName(), connection.getUid());
         } catch (RemoteException re) {
             if (DEBUG) {
                 Slog.e(LOG_TAG, "Error calling findFocus()");
@@ -628,35 +634,35 @@
         } finally {
             Binder.restoreCallingIdentity(identityToken);
             // Recycle if passed to another process.
-            if (partialInteractiveRegion != null && Binder.isProxy(connection)) {
+            if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
                 partialInteractiveRegion.recycle();
             }
         }
-        return false;
+        return null;
     }
 
     @Override
-    public boolean focusSearch(int accessibilityWindowId, long accessibilityNodeId,
+    public String[] focusSearch(int accessibilityWindowId, long accessibilityNodeId,
             int direction, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
             throws RemoteException {
         final int resolvedWindowId;
-        IAccessibilityInteractionConnection connection = null;
+        RemoteAccessibilityConnection connection;
         Region partialInteractiveRegion = Region.obtain();
         MagnificationSpec spec;
         synchronized (mLock) {
             if (!isCalledForCurrentUserLocked()) {
-                return false;
+                return null;
             }
             resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
             final boolean permissionGranted =
                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
             if (!permissionGranted) {
-                return false;
+                return null;
             } else {
                 connection = mSystemSupport.getConnectionLocked(resolvedWindowId);
                 if (connection == null) {
-                    return false;
+                    return null;
                 }
             }
             if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
@@ -669,12 +675,14 @@
         final int interrogatingPid = Binder.getCallingPid();
         callback = mSystemSupport.replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
                 interrogatingPid, interrogatingTid);
+        final int callingUid = Binder.getCallingUid();
         final long identityToken = Binder.clearCallingIdentity();
         try {
-            connection.focusSearch(accessibilityNodeId, direction, partialInteractiveRegion,
-                    interactionId, callback, mFetchFlags, interrogatingPid, interrogatingTid,
-                    spec);
-            return true;
+            connection.getRemote().focusSearch(accessibilityNodeId, direction,
+                    partialInteractiveRegion, interactionId, callback, mFetchFlags,
+                    interrogatingPid, interrogatingTid, spec);
+            return mSecurityPolicy.computeValidReportedPackages(callingUid,
+                    connection.getPackageName(), connection.getUid());
         } catch (RemoteException re) {
             if (DEBUG) {
                 Slog.e(LOG_TAG, "Error calling accessibilityFocusSearch()");
@@ -682,11 +690,11 @@
         } finally {
             Binder.restoreCallingIdentity(identityToken);
             // Recycle if passed to another process.
-            if (partialInteractiveRegion != null && Binder.isProxy(connection)) {
+            if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
                 partialInteractiveRegion.recycle();
             }
         }
-        return false;
+        return null;
     }
 
     @Override
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 0a21b9e..ac0cdd7 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -24,12 +24,12 @@
 import android.accessibilityservice.AccessibilityService;
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.accessibilityservice.IAccessibilityServiceClient;
-import android.accessibilityservice.IAccessibilityServiceConnection;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManagerInternal;
 import android.app.AlertDialog;
 import android.app.PendingIntent;
+import android.appwidget.AppWidgetManagerInternal;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -72,6 +72,7 @@
 import android.provider.SettingsStringUtil.SettingStringHelper;
 import android.text.TextUtils;
 import android.text.TextUtils.SimpleStringSplitter;
+import android.util.ArraySet;
 import android.util.IntArray;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -97,6 +98,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.PackageMonitor;
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.IntPair;
 import com.android.server.LocalServices;
@@ -104,6 +106,7 @@
 import com.android.internal.accessibility.AccessibilityShortcutController.ToggleableFrameworkFeatureInfo;
 import com.android.server.wm.WindowManagerInternal;
 
+import libcore.util.EmptyArray;
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.FileDescriptor;
@@ -186,6 +189,8 @@
 
     private final WindowManagerInternal mWindowManagerService;
 
+    private AppWidgetManagerInternal mAppWidgetService;
+
     private final SecurityPolicy mSecurityPolicy;
 
     private final MainHandler mMainHandler;
@@ -218,10 +223,10 @@
     private final RemoteCallbackList<IAccessibilityManagerClient> mGlobalClients =
             new RemoteCallbackList<>();
 
-    private final SparseArray<AccessibilityConnectionWrapper> mGlobalInteractionConnections =
+    private final SparseArray<RemoteAccessibilityConnection> mGlobalInteractionConnections =
             new SparseArray<>();
 
-    private AccessibilityConnectionWrapper mPictureInPictureActionReplacingConnection;
+    private RemoteAccessibilityConnection mPictureInPictureActionReplacingConnection;
 
     private final SparseArray<IBinder> mGlobalWindowTokens = new SparseArray<>();
 
@@ -453,6 +458,7 @@
             // performs the current profile parent resolution.
             final int resolvedUserId = mSecurityPolicy
                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
+
             // If the client is from a process that runs across users such as
             // the system UI or the system we add it to the global state that
             // is shared across users.
@@ -497,9 +503,14 @@
 
             // We treat calls from a profile as if made by its parent as profiles
             // share the accessibility state of the parent. The call below
-            // performs the current profile parent resolution..
+            // performs the current profile parent resolution.
             final int resolvedUserId = mSecurityPolicy
                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
+
+            // Make sure the reported package is one the caller has access to.
+            event.setPackageName(mSecurityPolicy.resolveValidReportedPackageLocked(
+                    event.getPackageName(), UserHandle.getCallingAppId(), resolvedUserId));
+
             // This method does nothing for a background user.
             if (resolvedUserId == mCurrentUserId) {
                 if (mSecurityPolicy.canDispatchAccessibilityEventLocked(event)) {
@@ -617,30 +628,38 @@
 
     @Override
     public int addAccessibilityInteractionConnection(IWindow windowToken,
-            IAccessibilityInteractionConnection connection, int userId) throws RemoteException {
+            IAccessibilityInteractionConnection connection, String packageName,
+            int userId) throws RemoteException {
         synchronized (mLock) {
             // We treat calls from a profile as if made by its parent as profiles
             // share the accessibility state of the parent. The call below
             // performs the current profile parent resolution.
             final int resolvedUserId = mSecurityPolicy
                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
+            final int resolvedUid = UserHandle.getUid(resolvedUserId, UserHandle.getCallingAppId());
+
+            // Make sure the reported package is one the caller has access to.
+            packageName = mSecurityPolicy.resolveValidReportedPackageLocked(
+                    packageName, UserHandle.getCallingAppId(), resolvedUserId);
+
             final int windowId = sNextWindowId++;
             // If the window is from a process that runs across users such as
             // the system UI or the system we add it to the global state that
             // is shared across users.
             if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) {
-                AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper(
-                        windowId, connection, UserHandle.USER_ALL);
+                RemoteAccessibilityConnection wrapper = new RemoteAccessibilityConnection(
+                        windowId, connection, packageName, resolvedUid, UserHandle.USER_ALL);
                 wrapper.linkToDeath();
                 mGlobalInteractionConnections.put(windowId, wrapper);
                 mGlobalWindowTokens.put(windowId, windowToken.asBinder());
                 if (DEBUG) {
                     Slog.i(LOG_TAG, "Added global connection for pid:" + Binder.getCallingPid()
-                            + " with windowId: " + windowId + " and  token: " + windowToken.asBinder());
+                            + " with windowId: " + windowId + " and  token: "
+                            + windowToken.asBinder());
                 }
             } else {
-                AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper(
-                        windowId, connection, resolvedUserId);
+                RemoteAccessibilityConnection wrapper = new RemoteAccessibilityConnection(
+                        windowId, connection, packageName, resolvedUid, resolvedUserId);
                 wrapper.linkToDeath();
                 UserState userState = getUserStateLocked(resolvedUserId);
                 userState.mInteractionConnections.put(windowId, wrapper);
@@ -693,13 +712,13 @@
 
     private int removeAccessibilityInteractionConnectionInternalLocked(IBinder windowToken,
             SparseArray<IBinder> windowTokens,
-            SparseArray<AccessibilityConnectionWrapper> interactionConnections) {
+            SparseArray<RemoteAccessibilityConnection> interactionConnections) {
         final int count = windowTokens.size();
         for (int i = 0; i < count; i++) {
             if (windowTokens.valueAt(i) == windowToken) {
                 final int windowId = windowTokens.keyAt(i);
                 windowTokens.removeAt(i);
-                AccessibilityConnectionWrapper wrapper = interactionConnections.get(windowId);
+                RemoteAccessibilityConnection wrapper = interactionConnections.get(windowId);
                 wrapper.unlinkToDeath();
                 interactionConnections.remove(windowId);
                 return windowId;
@@ -719,9 +738,9 @@
                 mPictureInPictureActionReplacingConnection = null;
             }
             if (connection != null) {
-                AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper(
+                RemoteAccessibilityConnection wrapper = new RemoteAccessibilityConnection(
                         AccessibilityWindowInfo.PICTURE_IN_PICTURE_ACTION_REPLACER_WINDOW_ID,
-                        connection, UserHandle.USER_ALL);
+                        connection, "foo.bar.baz", Process.SYSTEM_UID, UserHandle.USER_ALL);
                 mPictureInPictureActionReplacingConnection = wrapper;
                 wrapper.linkToDeath();
             }
@@ -2264,18 +2283,35 @@
         }
     }
 
-    private class AccessibilityConnectionWrapper implements DeathRecipient {
+    class RemoteAccessibilityConnection implements DeathRecipient {
+        private final int mUid;
+        private final String mPackageName;
         private final int mWindowId;
         private final int mUserId;
         private final IAccessibilityInteractionConnection mConnection;
 
-        public AccessibilityConnectionWrapper(int windowId,
-                IAccessibilityInteractionConnection connection, int userId) {
+        RemoteAccessibilityConnection(int windowId,
+                IAccessibilityInteractionConnection connection,
+                String packageName, int uid, int userId) {
             mWindowId = windowId;
+            mPackageName = packageName;
+            mUid = uid;
             mUserId = userId;
             mConnection = connection;
         }
 
+        public int getUid() {
+            return  mUid;
+        }
+
+        public String getPackageName() {
+            return mPackageName;
+        }
+
+        public IAccessibilityInteractionConnection getRemote() {
+            return mConnection;
+        }
+
         public void linkToDeath() throws RemoteException {
             mConnection.asBinder().linkToDeath(this, 0);
         }
@@ -2532,11 +2568,13 @@
             long accessibilityNodeId, int action, Bundle arguments, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, int fetchFlags,
             long interrogatingTid) {
-        IAccessibilityInteractionConnection connection = null;
+        RemoteAccessibilityConnection connection;
         IBinder activityToken = null;
         synchronized (mLock) {
             connection = getConnectionLocked(resolvedWindowId);
-            if (connection == null)  return false;
+            if (connection == null)  {
+                return false;
+            }
             final boolean isA11yFocusAction = (action == ACTION_ACCESSIBILITY_FOCUS)
                     || (action == ACTION_CLEAR_ACCESSIBILITY_FOCUS);
             final AccessibilityWindowInfo a11yWindowInfo =
@@ -2548,7 +2586,7 @@
             }
             if ((a11yWindowInfo != null) && a11yWindowInfo.isInPictureInPictureMode()
                     && (mPictureInPictureActionReplacingConnection != null) && !isA11yFocusAction) {
-                connection = mPictureInPictureActionReplacingConnection.mConnection;
+                connection = mPictureInPictureActionReplacingConnection;
             }
         }
         final int interrogatingPid = Binder.getCallingPid();
@@ -2563,8 +2601,9 @@
                 LocalServices.getService(ActivityManagerInternal.class)
                         .setFocusedActivity(activityToken);
             }
-            connection.performAccessibilityAction(accessibilityNodeId, action, arguments,
-                    interactionId, callback, fetchFlags, interrogatingPid, interrogatingTid);
+            connection.mConnection.performAccessibilityAction(accessibilityNodeId, action,
+                    arguments, interactionId, callback, fetchFlags, interrogatingPid,
+                    interrogatingTid);
         } catch (RemoteException re) {
             if (DEBUG) {
                 Slog.e(LOG_TAG, "Error calling performAccessibilityAction: " + re);
@@ -2577,17 +2616,17 @@
     }
 
     @Override
-    public IAccessibilityInteractionConnection getConnectionLocked(int windowId) {
+    public RemoteAccessibilityConnection getConnectionLocked(int windowId) {
         if (DEBUG) {
             Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId);
         }
-        AccessibilityManagerService.AccessibilityConnectionWrapper wrapper =
+        RemoteAccessibilityConnection connection =
                 mGlobalInteractionConnections.get(windowId);
-        if (wrapper == null) {
-            wrapper = getCurrentUserStateLocked().mInteractionConnections.get(windowId);
+        if (connection == null) {
+            connection = getCurrentUserStateLocked().mInteractionConnections.get(windowId);
         }
-        if (wrapper != null && wrapper.mConnection != null) {
-            return wrapper.mConnection;
+        if (connection != null && connection.mConnection != null) {
+            return connection;
         }
         if (DEBUG) {
             Slog.e(LOG_TAG, "No interaction connection to window: " + windowId);
@@ -2620,6 +2659,16 @@
         }
     }
 
+    private AppWidgetManagerInternal getAppWidgetManager() {
+        synchronized (mLock) {
+            if (mAppWidgetService == null
+                    && mPackageManager.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)) {
+                mAppWidgetService = LocalServices.getService(AppWidgetManagerInternal.class);
+            }
+            return mAppWidgetService;
+        }
+    }
+
     final class WindowsForAccessibilityCallback implements
             WindowManagerInternal.WindowsForAccessibilityCallback {
 
@@ -2912,6 +2961,78 @@
             }
         }
 
+        private boolean isValidPackageForUid(String packageName, int uid) {
+            try {
+                return uid == mPackageManager.getPackageUidAsUser(
+                        packageName, UserHandle.getUserId(uid));
+            } catch (PackageManager.NameNotFoundException e) {
+                return false;
+            }
+        }
+
+        String resolveValidReportedPackageLocked(CharSequence packageName, int appId, int userId) {
+            // Okay to pass no package
+            if (packageName == null) {
+                return null;
+            }
+            // The system gets to pass any package
+            if (appId == Process.SYSTEM_UID) {
+                return packageName.toString();
+            }
+            // Passing a package in your UID is fine
+            final String packageNameStr = packageName.toString();
+            final int resolvedUid = UserHandle.getUid(userId, appId);
+            if (isValidPackageForUid(packageNameStr, resolvedUid)) {
+                return packageName.toString();
+            }
+            // Appwidget hosts get to pass packages for widgets they host
+            final AppWidgetManagerInternal appWidgetManager = getAppWidgetManager();
+            if (appWidgetManager != null && ArrayUtils.contains(appWidgetManager
+                            .getHostedWidgetPackages(resolvedUid), packageNameStr)) {
+                return packageName.toString();
+            }
+            // Otherwise, set the package to the first one in the UID
+            final String[] packageNames = mPackageManager.getPackagesForUid(resolvedUid);
+            if (ArrayUtils.isEmpty(packageNames)) {
+                return null;
+            }
+            // Okay, the caller reported a package it does not have access to.
+            // Instead of crashing the caller for better backwards compatibility
+            // we report the first package in the UID. Since most of the time apps
+            // don't use shared user id, this will yield correct results and for
+            // the edge case of using a shared user id we may report the wrong
+            // package but this is fine since first, this is a cheating app and
+            // second there is no way to get the correct package anyway.
+            return packageNames[0];
+        }
+
+        String[] computeValidReportedPackages(int callingUid,
+                String targetPackage, int targetUid) {
+            if (UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) {
+                // Empty array means any package is Okay
+                return EmptyArray.STRING;
+            }
+            // IMPORTANT: The target package is already vetted to be in the target UID
+            String[] uidPackages = new String[]{targetPackage};
+            // Appwidget hosts get to pass packages for widgets they host
+            final AppWidgetManagerInternal appWidgetManager = getAppWidgetManager();
+            if (appWidgetManager != null) {
+                final ArraySet<String> widgetPackages = appWidgetManager
+                        .getHostedWidgetPackages(targetUid);
+                if (widgetPackages != null && !widgetPackages.isEmpty()) {
+                    final String[] validPackages = new String[uidPackages.length
+                            + widgetPackages.size()];
+                    System.arraycopy(uidPackages, 0, validPackages, 0, uidPackages.length);
+                    final int widgetPackageCount = widgetPackages.size();
+                    for (int i = 0; i < widgetPackageCount; i++) {
+                        validPackages[uidPackages.length + i] = widgetPackages.valueAt(i);
+                    }
+                    return validPackages;
+                }
+            }
+            return uidPackages;
+        }
+
         public void clearWindowsLocked() {
             List<WindowInfo> windows = Collections.emptyList();
             final int activeWindowId = mActiveWindowId;
@@ -3338,7 +3459,7 @@
         public final RemoteCallbackList<IAccessibilityManagerClient> mUserClients =
             new RemoteCallbackList<>();
 
-        public final SparseArray<AccessibilityConnectionWrapper> mInteractionConnections =
+        public final SparseArray<RemoteAccessibilityConnection> mInteractionConnections =
                 new SparseArray<>();
 
         public final SparseArray<IBinder> mWindowTokens = new SparseArray<>();
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index b446209..54cf726 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -32,6 +32,7 @@
 import android.app.admin.DevicePolicyManagerInternal;
 import android.app.admin.DevicePolicyManagerInternal.OnCrossProfileWidgetProvidersChangeListener;
 import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetManagerInternal;
 import android.appwidget.AppWidgetProviderInfo;
 import android.appwidget.PendingHostUpdate;
 import android.content.BroadcastReceiver;
@@ -100,6 +101,8 @@
 import com.android.internal.appwidget.IAppWidgetService;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.os.SomeArgs;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.widget.IRemoteViewsFactory;
@@ -107,6 +110,7 @@
 import com.android.server.WidgetBackupProvider;
 import com.android.server.policy.IconUtilities;
 
+import libcore.util.EmptyArray;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -259,6 +263,8 @@
         computeMaximumWidgetBitmapMemory();
         registerBroadcastReceiver();
         registerOnCrossProfileProvidersChangedListener();
+
+        LocalServices.addService(AppWidgetManagerInternal.class, new AppWidgetManagerLocal());
     }
 
     private void computeMaximumWidgetBitmapMemory() {
@@ -4630,4 +4636,24 @@
             }
         }
     }
+
+    private class AppWidgetManagerLocal extends AppWidgetManagerInternal {
+        @Override
+        public ArraySet<String> getHostedWidgetPackages(int uid) {
+            synchronized (mLock) {
+                ArraySet<String> widgetPackages = null;
+                final int widgetCount = mWidgets.size();
+                for (int i = 0; i < widgetCount; i++) {
+                    final Widget widget = mWidgets.get(i);
+                    if  (widget.host.id.uid == uid) {
+                        if (widgetPackages == null) {
+                            widgetPackages = new ArraySet<>();
+                        }
+                        widgetPackages.add(widget.provider.id.componentName.getPackageName());
+                    }
+                }
+                return widgetPackages;
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/AnimationThread.java b/services/core/java/com/android/server/AnimationThread.java
index 08392b0..c86042b 100644
--- a/services/core/java/com/android/server/AnimationThread.java
+++ b/services/core/java/com/android/server/AnimationThread.java
@@ -22,8 +22,8 @@
 import android.os.Trace;
 
 /**
- * Thread for handling all window animations, or anything that's directly impacting animations like
- * starting windows or traversals.
+ * Thread for handling all legacy window animations, or anything that's directly impacting
+ * animations like starting windows or traversals.
  */
 public final class AnimationThread extends ServiceThread {
     private static AnimationThread sInstance;
diff --git a/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java b/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java
index 28c3585..bd2e96e 100644
--- a/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java
+++ b/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java
@@ -51,6 +51,7 @@
     // Information about the current status of the default network.
     @GuardedBy("this")
     private DefaultNetworkEvent mCurrentDefaultNetwork;
+    // True if the current default network has been validated.
     @GuardedBy("this")
     private boolean mIsCurrentlyValid;
     @GuardedBy("this")
@@ -71,6 +72,8 @@
             printEvent(localTimeMs, pw, ev);
         }
         mCurrentDefaultNetwork.updateDuration(timeMs);
+        // When printing default network events for bug reports, update validation time
+        // and refresh the last validation timestmap for future validation time updates.
         if (mIsCurrentlyValid) {
             updateValidationTime(timeMs);
             mLastValidationTimeMs = timeMs;
@@ -92,11 +95,13 @@
     }
 
     public synchronized void logDefaultNetworkValidity(long timeMs, boolean isValid) {
+        // Transition from valid to invalid: update validity duration since last update
         if (!isValid && mIsCurrentlyValid) {
             mIsCurrentlyValid = false;
             updateValidationTime(timeMs);
         }
 
+        // Transition from invalid to valid: simply mark the validation timestamp.
         if (isValid && !mIsCurrentlyValid) {
             mIsCurrentlyValid = true;
             mLastValidationTimeMs = timeMs;
@@ -114,6 +119,9 @@
     }
 
     private void logCurrentDefaultNetwork(long timeMs, NetworkAgentInfo oldNai) {
+        if (mIsCurrentlyValid) {
+            updateValidationTime(timeMs);
+        }
         DefaultNetworkEvent ev = mCurrentDefaultNetwork;
         ev.updateDuration(timeMs);
         ev.previousTransports = mLastTransports;
@@ -122,7 +130,6 @@
             // The system acquired a new default network.
             fillLinkInfo(ev, oldNai);
             ev.finalScore = oldNai.getCurrentScore();
-            ev.validatedMs = ev.durationMs;
         }
         // Only change transport of the previous default network if the event currently logged
         // corresponds to an existing default network, and not to the absence of a default network.
@@ -143,9 +150,10 @@
             fillLinkInfo(ev, newNai);
             ev.initialScore = newNai.getCurrentScore();
             if (newNai.lastValidated) {
-                mIsCurrentlyValid = true;
-                mLastValidationTimeMs = timeMs;
+                logDefaultNetworkValidity(timeMs, true);
             }
+        } else {
+            mIsCurrentlyValid = false;
         }
         mCurrentDefaultNetwork = ev;
     }
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 19a74d7..c1bfa47 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -76,6 +76,7 @@
 import com.android.server.SystemService;
 import com.android.server.UiThread;
 import com.android.server.wm.WindowManagerInternal;
+import com.android.server.wm.SurfaceAnimationThread;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -292,6 +293,8 @@
                 Process.THREAD_GROUP_TOP_APP);
         Process.setThreadGroupAndCpuset(AnimationThread.get().getThreadId(),
                 Process.THREAD_GROUP_TOP_APP);
+        Process.setThreadGroupAndCpuset(SurfaceAnimationThread.get().getThreadId(),
+                Process.THREAD_GROUP_TOP_APP);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e0f3ec7..5dfb48a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -12884,14 +12884,13 @@
         if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
             return null;
         }
-        // writer
-        synchronized (mPackages) {
-            if (!isExternalMediaAvailable()) {
+        if (!isExternalMediaAvailable()) {
                 // If the external storage is no longer mounted at this point,
                 // the caller may not have been able to delete all of this
                 // packages files and can not delete any more.  Bail.
-                return null;
-            }
+            return null;
+        }
+        synchronized (mPackages) {
             final ArrayList<PackageCleanItem> pkgs = mSettings.mPackagesToBeCleaned;
             if (lastPackage != null) {
                 pkgs.remove(lastPackage);
diff --git a/services/core/java/com/android/server/timezone/ClockHelper.java b/services/core/java/com/android/server/timezone/ClockHelper.java
deleted file mode 100644
index 353728a..0000000
--- a/services/core/java/com/android/server/timezone/ClockHelper.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.timezone;
-
-/**
- * An easy-to-mock interface for obtaining a monotonically increasing time value in milliseconds.
- */
-interface ClockHelper {
-
-    long currentTimestamp();
-}
diff --git a/services/core/java/com/android/server/timezone/PackageTracker.java b/services/core/java/com/android/server/timezone/PackageTracker.java
index 1c54320..c362c80 100644
--- a/services/core/java/com/android/server/timezone/PackageTracker.java
+++ b/services/core/java/com/android/server/timezone/PackageTracker.java
@@ -22,11 +22,14 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Environment;
+import android.os.FileUtils;
+import android.os.SystemClock;
 import android.provider.TimeZoneRulesDataContract;
 import android.util.Slog;
 
 import java.io.File;
 import java.io.PrintWriter;
+import java.time.Clock;
 
 /**
  * Monitors the installed applications associated with time zone updates. If the app packages are
@@ -58,7 +61,7 @@
     private final IntentHelper mIntentHelper;
     private final ConfigHelper mConfigHelper;
     private final PackageStatusStorage mPackageStatusStorage;
-    private final ClockHelper mClockHelper;
+    private final Clock mElapsedRealtimeClock;
 
     // False if tracking is disabled.
     private boolean mTrackingEnabled;
@@ -91,15 +94,15 @@
 
     /** Creates the {@link PackageTracker} for normal use. */
     static PackageTracker create(Context context) {
+        Clock elapsedRealtimeClock = SystemClock.elapsedRealtimeClock();
         PackageTrackerHelperImpl helperImpl = new PackageTrackerHelperImpl(context);
-        // TODO(nfuller): Switch to FileUtils.createDir() when available. http://b/31008728
-        File storageDir = new File(Environment.getDataSystemDirectory(), "timezone");
+        File storageDir = FileUtils.createDir(Environment.getDataSystemDirectory(), "timezone");
         if (!storageDir.exists()) {
             storageDir.mkdir();
         }
 
         return new PackageTracker(
-                helperImpl /* clock */,
+                elapsedRealtimeClock /* elapsedRealtimeClock */,
                 helperImpl /* configHelper */,
                 helperImpl /* packageManagerHelper */,
                 new PackageStatusStorage(storageDir),
@@ -107,10 +110,10 @@
     }
 
     // A constructor that can be used by tests to supply mocked / faked dependencies.
-    PackageTracker(ClockHelper clockHelper, ConfigHelper configHelper,
+    PackageTracker(Clock elapsedRealtimeClock, ConfigHelper configHelper,
             PackageManagerHelper packageManagerHelper, PackageStatusStorage packageStatusStorage,
             IntentHelper intentHelper) {
-        mClockHelper = clockHelper;
+        mElapsedRealtimeClock = elapsedRealtimeClock;
         mConfigHelper = configHelper;
         mPackageManagerHelper = packageManagerHelper;
         mPackageStatusStorage = packageStatusStorage;
@@ -425,7 +428,7 @@
     }
 
     private void setCheckInProgress() {
-        mLastTriggerTimestamp = mClockHelper.currentTimestamp();
+        mLastTriggerTimestamp = mElapsedRealtimeClock.millis();
     }
 
     private void setCheckComplete() {
@@ -441,7 +444,7 @@
             return false;
         }
         // Risk of overflow, but highly unlikely given the implementation and not problematic.
-        return mClockHelper.currentTimestamp() > mLastTriggerTimestamp + mCheckTimeAllowedMillis;
+        return mElapsedRealtimeClock.millis() > mLastTriggerTimestamp + mCheckTimeAllowedMillis;
     }
 
     private PackageVersions lookupInstalledPackageVersions() {
diff --git a/services/core/java/com/android/server/timezone/PackageTrackerHelperImpl.java b/services/core/java/com/android/server/timezone/PackageTrackerHelperImpl.java
index 6a330e6..5f90be1 100644
--- a/services/core/java/com/android/server/timezone/PackageTrackerHelperImpl.java
+++ b/services/core/java/com/android/server/timezone/PackageTrackerHelperImpl.java
@@ -25,7 +25,6 @@
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
-import android.os.SystemClock;
 import android.os.UserHandle;
 import android.util.Slog;
 
@@ -34,7 +33,7 @@
 /**
  * A single class that implements multiple helper interfaces for use by {@link PackageTracker}.
  */
-final class PackageTrackerHelperImpl implements ClockHelper, ConfigHelper, PackageManagerHelper {
+final class PackageTrackerHelperImpl implements ConfigHelper, PackageManagerHelper {
 
     private static final String TAG = "PackageTrackerHelperImpl";
 
@@ -74,13 +73,6 @@
     }
 
     @Override
-    public long currentTimestamp() {
-        // Use of elapsedRealtime() because this is in-memory state and elapsedRealtime() shouldn't
-        // change if the system clock changes.
-        return SystemClock.elapsedRealtime();
-    }
-
-    @Override
     public long getInstalledPackageVersion(String packageName)
             throws PackageManager.NameNotFoundException {
         int flags = PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
diff --git a/services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java b/services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java
index 0cf61c0..e8a401e 100644
--- a/services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java
+++ b/services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java
@@ -16,6 +16,8 @@
 
 package com.android.server.timezone;
 
+import com.android.internal.util.DumpUtils;
+
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.AsyncTask;
@@ -46,15 +48,7 @@
 
     @Override
     public boolean checkDumpPermission(String tag, PrintWriter pw) {
-        // TODO(nfuller): Switch to DumpUtils.checkDumpPermission() when it is available in AOSP.
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
-                != PackageManager.PERMISSION_GRANTED) {
-            pw.println("Permission Denial: can't dump LocationManagerService from from pid="
-                    + Binder.getCallingPid()
-                    + ", uid=" + Binder.getCallingUid());
-            return false;
-        }
-        return true;
+        return DumpUtils.checkDumpPermission(mContext, tag, pw);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/AnimationAdapter.java b/services/core/java/com/android/server/wm/AnimationAdapter.java
new file mode 100644
index 0000000..84d47b4
--- /dev/null
+++ b/services/core/java/com/android/server/wm/AnimationAdapter.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import android.annotation.ColorInt;
+import android.graphics.Point;
+import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
+import android.view.animation.Animation;
+
+import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
+
+/**
+ * Interface that describes an animation and bridges the animation start to the component
+ * responsible for running the animation.
+ */
+interface AnimationAdapter {
+
+    /**
+     * @return Whether we should detach the wallpaper during the animation.
+     * @see Animation#setDetachWallpaper
+     */
+    boolean getDetachWallpaper();
+
+    /**
+     * @return The background color behind the animation.
+     */
+    @ColorInt int getBackgroundColor();
+
+    /**
+     * Requests to start the animation.
+     *
+     * @param animationLeash The surface to run the animation on. See {@link SurfaceAnimator} for an
+     *                       overview of the mechanism. This surface needs to be released by the
+     *                       component running the animation after {@code finishCallback} has been
+     *                       invoked, or after the animation was cancelled.
+     * @param t The Transaction to apply the initial frame of the animation.
+     * @param finishCallback The callback to be invoked when the animation has finished.
+     */
+    void startAnimation(SurfaceControl animationLeash, Transaction t,
+            OnAnimationFinishedCallback finishCallback);
+
+    /**
+     * Called when the animation that was started with {@link #startAnimation} was cancelled by the
+     * window manager.
+     *
+     * @param animationLeash The leash passed to {@link #startAnimation}.
+     */
+    void onAnimationCancelled(SurfaceControl animationLeash);
+
+    /**
+     * @return The approximate duration of the animation, in milliseconds.
+     */
+    long getDurationHint();
+}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 91cad46..eda8fec 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1766,8 +1766,8 @@
         updateBounds();
     }
 
-    void getContentRect(Rect out) {
-        out.set(mDisplayFrames.mContent);
+    void getStableRect(Rect out) {
+        out.set(mDisplayFrames.mStable);
     }
 
     TaskStack createStack(int stackId, boolean onTop, StackWindowController controller) {
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 7e29a3a..88b7a11 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -390,12 +390,13 @@
             }
         }
 
-        final boolean inPositioning = (mService.mTaskPositioner != null);
+        final boolean inPositioning = mService.mTaskPositioningController.isPositioningLocked();
         if (inPositioning) {
             if (DEBUG_TASK_POSITIONING) {
                 Log.d(TAG_WM, "Inserting window handle for repositioning");
             }
-            final InputWindowHandle dragWindowHandle = mService.mTaskPositioner.mDragWindowHandle;
+            final InputWindowHandle dragWindowHandle =
+                    mService.mTaskPositioningController.getDragWindowHandleLocked();
             if (dragWindowHandle != null) {
                 addInputWindowHandle(dragWindowHandle);
             } else {
diff --git a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
new file mode 100644
index 0000000..5fe4565
--- /dev/null
+++ b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import android.graphics.Point;
+import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
+import android.view.animation.Animation;
+
+import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
+
+/**
+ * Animation that can be executed without holding the window manager lock. See
+ * {@link SurfaceAnimationRunner}.
+ */
+class LocalAnimationAdapter implements AnimationAdapter {
+
+    private final AnimationSpec mSpec;
+    private final SurfaceAnimationRunner mAnimator;
+
+    LocalAnimationAdapter(AnimationSpec spec, SurfaceAnimationRunner animator) {
+        mSpec = spec;
+        mAnimator = animator;
+    }
+
+    @Override
+    public boolean getDetachWallpaper() {
+        return mSpec.getDetachWallpaper();
+    }
+
+    @Override
+    public int getBackgroundColor() {
+        return mSpec.getBackgroundColor();
+    }
+
+    @Override
+    public void startAnimation(SurfaceControl animationLeash, Transaction t,
+            OnAnimationFinishedCallback finishCallback) {
+        mAnimator.startAnimation(mSpec, animationLeash, t,
+                () -> finishCallback.onAnimationFinished(this));
+    }
+
+    @Override
+    public void onAnimationCancelled(SurfaceControl animationLeash) {
+        mAnimator.onAnimationCancelled(animationLeash);
+    }
+
+    @Override
+    public long getDurationHint() {
+        return mSpec.getDuration();
+    }
+
+    /**
+     * Describes how to apply an animation.
+     */
+    interface AnimationSpec {
+
+        /**
+         * @see AnimationAdapter#getDetachWallpaper
+         */
+        default boolean getDetachWallpaper() {
+            return false;
+        }
+
+        /**
+         * @see AnimationAdapter#getBackgroundColor
+         */
+        default int getBackgroundColor() {
+            return 0;
+        }
+
+        /**
+         * @return The duration of the animation.
+         */
+        long getDuration();
+
+        /**
+         * Called when the spec needs to apply the current animation state to the leash.
+         *
+         * @param t The transaction to use to apply a transform.
+         * @param leash The leash to apply the state to.
+         * @param currentPlayTime The current time of the animation.
+         */
+        void apply(Transaction t, SurfaceControl leash, long currentPlayTime);
+    }
+}
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 63eea10..192d6c8 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -368,7 +368,7 @@
 
         long ident = Binder.clearCallingIdentity();
         try {
-            return mService.startMovingTask(window, startX, startY);
+            return mService.mTaskPositioningController.startMovingTask(window, startX, startY);
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
new file mode 100644
index 0000000..5bc2722
--- /dev/null
+++ b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import static android.view.Choreographer.CALLBACK_TRAVERSAL;
+import static android.view.Choreographer.getSfInstance;
+
+import android.animation.AnimationHandler;
+import android.animation.AnimationHandler.AnimationFrameCallbackProvider;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.annotation.Nullable;
+import android.util.ArrayMap;
+import android.view.Choreographer;
+import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
+import android.view.animation.Transformation;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
+import com.android.server.AnimationThread;
+import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
+
+/**
+ * Class to run animations without holding the window manager lock.
+ */
+class SurfaceAnimationRunner {
+
+    private final Object mLock = new Object();
+
+    @VisibleForTesting
+    Choreographer mChoreographer;
+
+    private final Runnable mApplyTransactionRunnable = this::applyTransaction;
+    private final AnimationHandler mAnimationHandler;
+    private final Transaction mFrameTransaction;
+    private boolean mApplyScheduled;
+
+    @GuardedBy("mLock")
+    @VisibleForTesting
+    final ArrayMap<SurfaceControl, RunningAnimation> mPendingAnimations = new ArrayMap<>();
+
+    @GuardedBy("mLock")
+    @VisibleForTesting
+    final ArrayMap<SurfaceControl, ValueAnimator> mRunningAnimations = new ArrayMap<>();
+
+    SurfaceAnimationRunner() {
+        this(null /* callbackProvider */, new Transaction());
+    }
+
+    @VisibleForTesting
+    SurfaceAnimationRunner(@Nullable AnimationFrameCallbackProvider callbackProvider,
+            Transaction frameTransaction) {
+        SurfaceAnimationThread.getHandler().runWithScissors(() -> mChoreographer = getSfInstance(),
+                0 /* timeout */);
+        mFrameTransaction = frameTransaction;
+        mAnimationHandler = new AnimationHandler();
+        mAnimationHandler.setProvider(callbackProvider != null
+                ? callbackProvider
+                : new SfVsyncFrameCallbackProvider(mChoreographer));
+    }
+
+    void startAnimation(AnimationSpec a, SurfaceControl animationLeash, Transaction t,
+            Runnable finishCallback) {
+        synchronized (mLock) {
+            final RunningAnimation runningAnim = new RunningAnimation(a, animationLeash,
+                    finishCallback);
+            mPendingAnimations.put(animationLeash, runningAnim);
+            mChoreographer.postFrameCallback(this::stepAnimation);
+
+            // Some animations (e.g. move animations) require the initial transform to be applied
+            // immediately.
+            applyTransformation(runningAnim, t, 0 /* currentPlayTime */);
+        }
+    }
+
+    void onAnimationCancelled(SurfaceControl leash) {
+        synchronized (mLock) {
+            if (mPendingAnimations.containsKey(leash)) {
+                mPendingAnimations.remove(leash);
+                // TODO: Releasing the leash is problematic if reparenting hasn't happened yet.
+                // Fix with transaction
+                //leash.release();
+                return;
+            }
+            final ValueAnimator anim = mRunningAnimations.get(leash);
+            if (anim != null) {
+                mRunningAnimations.remove(leash);
+                SurfaceAnimationThread.getHandler().post(() -> {
+                    anim.cancel();
+                    applyTransaction();
+                    //leash.release();
+                });
+            }
+        }
+    }
+
+    private void startPendingAnimationsLocked() {
+        for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
+            startAnimationLocked(mPendingAnimations.valueAt(i));
+        }
+        mPendingAnimations.clear();
+    }
+
+    private void startAnimationLocked(RunningAnimation a) {
+        final ValueAnimator result = new SfValueAnimator();
+
+        // Animation length is already expected to be scaled.
+        result.overrideDurationScale(1.0f);
+        result.setDuration(a.animSpec.getDuration());
+        result.addUpdateListener(animation -> {
+            applyTransformation(a, mFrameTransaction, result.getCurrentPlayTime());
+
+            // Transaction will be applied in the commit phase.
+            scheduleApplyTransaction();
+        });
+        result.addListener(new AnimatorListenerAdapter() {
+
+            private boolean mCancelled;
+
+            @Override
+            public void onAnimationStart(Animator animation) {
+                mFrameTransaction.show(a.leash);
+            }
+
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                mCancelled = true;
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                synchronized (mLock) {
+                    mRunningAnimations.remove(a.leash);
+                }
+                if (!mCancelled) {
+                    // Post on other thread that we can push final state without jank.
+                    AnimationThread.getHandler().post(() -> {
+                        a.finishCallback.run();
+
+                        // Make sure to release the leash after finishCallback has been invoked such
+                        // that reparenting is done already when releasing the leash.
+                        a.leash.release();
+                    });
+                }
+            }
+        });
+        result.start();
+        mRunningAnimations.put(a.leash, result);
+    }
+
+    private void applyTransformation(RunningAnimation a, Transaction t, long currentPlayTime) {
+        a.animSpec.apply(t, a.leash, currentPlayTime);
+    }
+
+    private void stepAnimation(long frameTimeNanos) {
+        synchronized (mLock) {
+            startPendingAnimationsLocked();
+        }
+    }
+
+    private void scheduleApplyTransaction() {
+        if (!mApplyScheduled) {
+            mChoreographer.postCallback(CALLBACK_TRAVERSAL, mApplyTransactionRunnable,
+                    null /* token */);
+            mApplyScheduled = true;
+        }
+    }
+
+    private void applyTransaction() {
+        mFrameTransaction.apply();
+        mApplyScheduled = false;
+    }
+
+    private static final class RunningAnimation {
+        final AnimationSpec animSpec;
+        final SurfaceControl leash;
+        final Runnable finishCallback;
+
+        RunningAnimation(AnimationSpec animSpec, SurfaceControl leash, Runnable finishCallback) {
+            this.animSpec = animSpec;
+            this.leash = leash;
+            this.finishCallback = finishCallback;
+        }
+    }
+
+    /**
+     * Value animator that uses sf-vsync signal to tick.
+     */
+    private class SfValueAnimator extends ValueAnimator {
+
+        SfValueAnimator() {
+            setFloatValues(0f, 1f);
+        }
+
+        @Override
+        public AnimationHandler getAnimationHandler() {
+            return mAnimationHandler;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationThread.java b/services/core/java/com/android/server/wm/SurfaceAnimationThread.java
new file mode 100644
index 0000000..0d3afc0
--- /dev/null
+++ b/services/core/java/com/android/server/wm/SurfaceAnimationThread.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import static android.os.Process.THREAD_PRIORITY_DISPLAY;
+
+import android.os.Handler;
+import android.os.Trace;
+
+import com.android.server.ServiceThread;
+
+/**
+ * Thread for running {@link SurfaceAnimationRunner} that does not hold the window manager lock.
+ */
+public final class SurfaceAnimationThread extends ServiceThread {
+    private static SurfaceAnimationThread sInstance;
+    private static Handler sHandler;
+
+    private SurfaceAnimationThread() {
+        super("android.anim.lf", THREAD_PRIORITY_DISPLAY, false /*allowIo*/);
+    }
+
+    private static void ensureThreadLocked() {
+        if (sInstance == null) {
+            sInstance = new SurfaceAnimationThread();
+            sInstance.start();
+            sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_WINDOW_MANAGER);
+            sHandler = new Handler(sInstance.getLooper());
+        }
+    }
+
+    public static SurfaceAnimationThread get() {
+        synchronized (SurfaceAnimationThread.class) {
+            ensureThreadLocked();
+            return sInstance;
+        }
+    }
+
+    public static Handler getHandler() {
+        synchronized (SurfaceAnimationThread.class) {
+            ensureThreadLocked();
+            return sHandler;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
new file mode 100644
index 0000000..713d58b
--- /dev/null
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.Slog;
+import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
+
+import java.io.PrintWriter;
+
+/**
+ * A class that can run animations on objects that have a set of child surfaces. We do this by
+ * reparenting all child surfaces of an object onto a new surface, called the "Leash". The Leash
+ * gets attached in the surface hierarchy where the the children were attached to. We then hand off
+ * the Leash to the component handling the animation, which is specified by the
+ * {@link AnimationAdapter}. When the animation is done animating, our callback to finish the
+ * animation will be invoked, at which we reparent the children back to the original parent.
+ */
+class SurfaceAnimator {
+
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "SurfaceAnimator" : TAG_WM;
+    private final WindowManagerService mService;
+    private AnimationAdapter mAnimation;
+    private SurfaceControl mLeash;
+    private final Animatable mAnimatable;
+    private final OnAnimationFinishedCallback mInnerAnimationFinishedCallback;
+    private final Runnable mAnimationFinishedCallback;
+    private boolean mAnimationStartDelayed;
+
+    /**
+     * @param animatable The object to animate.
+     * @param animationFinishedCallback Callback to invoke when an animation has finished running.
+     */
+    SurfaceAnimator(Animatable animatable, Runnable animationFinishedCallback,
+            WindowManagerService service) {
+        mAnimatable = animatable;
+        mService = service;
+        mAnimationFinishedCallback = animationFinishedCallback;
+        mInnerAnimationFinishedCallback = getFinishedCallback(animationFinishedCallback);
+    }
+
+    private OnAnimationFinishedCallback getFinishedCallback(Runnable animationFinishedCallback) {
+        return anim -> {
+            synchronized (mService.mWindowMap) {
+                if (anim != mAnimation) {
+                    // Callback was from another animation - ignore.
+                    return;
+                }
+
+                final Transaction t = new Transaction();
+                SurfaceControl.openTransaction();
+                try {
+                    reset(t);
+                    animationFinishedCallback.run();
+                } finally {
+                    // TODO: This should use pendingTransaction eventually, but right now things
+                    // happening on the animation finished callback are happening on the global
+                    // transaction.
+                    SurfaceControl.mergeToGlobalTransaction(t);
+                    SurfaceControl.closeTransaction();
+                }
+            }
+        };
+    }
+
+    /**
+     * Starts an animation.
+     *
+     * @param anim The object that bridges the controller, {@link SurfaceAnimator}, with the
+     *             component responsible for running the animation. It runs the animation with
+     *             {@link AnimationAdapter#startAnimation} once the hierarchy with
+     *             the Leash has been set up.
+     * @param hidden Whether the container holding the child surfaces is currently visible or not.
+     *               This is important as it will start with the leash hidden or visible before
+     *               handing it to the component that is responsible to run the animation.
+     */
+    void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden) {
+        cancelAnimation(t, true /* restarting */);
+        mAnimation = anim;
+        final SurfaceControl surface = mAnimatable.getSurface();
+        if (surface == null) {
+            Slog.w(TAG, "Unable to start animation, surface is null or no children.");
+            cancelAnimation();
+            return;
+        }
+        mLeash = createAnimationLeash(surface, t,
+                mAnimatable.getSurfaceWidth(), mAnimatable.getSurfaceHeight(), hidden);
+        mAnimatable.onLeashCreated(t, mLeash);
+        if (mAnimationStartDelayed) {
+            if (DEBUG_ANIM) Slog.i(TAG, "Animation start delayed");
+            return;
+        }
+        mAnimation.startAnimation(mLeash, t, mInnerAnimationFinishedCallback);
+    }
+
+    /**
+     * Begins with delaying all animations to start. Any subsequent call to {@link #startAnimation}
+     * will not start the animation until {@link #endDelayingAnimationStart} is called. When an
+     * animation start is being delayed, the animator is considered animating already.
+     */
+    void startDelayingAnimationStart() {
+
+        // We only allow delaying animation start we are not currently animating
+        if (!isAnimating()) {
+            mAnimationStartDelayed = true;
+        }
+    }
+
+    /**
+     * See {@link #startDelayingAnimationStart}.
+     */
+    void endDelayingAnimationStart() {
+        final boolean delayed = mAnimationStartDelayed;
+        mAnimationStartDelayed = false;
+        if (delayed && mAnimation != null) {
+            mAnimation.startAnimation(mLeash, mAnimatable.getPendingTransaction(),
+                    mInnerAnimationFinishedCallback);
+            mAnimatable.commitPendingTransaction();
+        }
+    }
+
+    /**
+     * @return Whether we are currently running an animation, or we have a pending animation that
+     *         is waiting to be started with {@link #endDelayingAnimationStart}
+     */
+    boolean isAnimating() {
+        return mAnimation != null;
+    }
+
+    /**
+     * @return The current animation spec if we are running an animation, or {@code null} otherwise.
+     */
+    AnimationAdapter getAnimation() {
+        return mAnimation;
+    }
+
+    /**
+     * Cancels any currently running animation.
+     */
+    void cancelAnimation() {
+        cancelAnimation(mAnimatable.getPendingTransaction(), false /* restarting */);
+        mAnimatable.commitPendingTransaction();
+    }
+
+    /**
+     * Sets the layer of the surface.
+     * <p>
+     * When the layer of the surface needs to be adjusted, we need to set it on the leash if the
+     * surface is reparented to the leash. This method takes care of that.
+     */
+    void setLayer(Transaction t, int layer) {
+        t.setLayer(mLeash != null ? mLeash : mAnimatable.getSurface(), layer);
+    }
+
+    /**
+     * Reparents the surface.
+     *
+     * @see #setLayer
+     */
+    void reparent(Transaction t, SurfaceControl newParent) {
+        t.reparent(mLeash != null ? mLeash : mAnimatable.getSurface(), newParent.getHandle());
+    }
+
+    /**
+     * @return True if the surface is attached to the leash; false otherwise.
+     */
+    boolean hasLeash() {
+        return mLeash != null;
+    }
+
+    private void cancelAnimation(Transaction t, boolean restarting) {
+        if (DEBUG_ANIM) Slog.i(TAG, "Cancelling animation restarting=" + restarting);
+        final SurfaceControl leash = mLeash;
+        final AnimationAdapter animation = mAnimation;
+        reset(t);
+        if (animation != null) {
+            if (!mAnimationStartDelayed) {
+                animation.onAnimationCancelled(leash);
+            }
+            if (!restarting) {
+                mAnimationFinishedCallback.run();
+            }
+        }
+        if (!restarting) {
+            mAnimationStartDelayed = false;
+        }
+    }
+
+    private void reset(Transaction t) {
+        final SurfaceControl surface = mAnimatable.getSurface();
+        final SurfaceControl parent = mAnimatable.getParentSurface();
+
+        // If the surface was destroyed, we don't care to reparent it back.
+        final boolean destroy = mLeash != null && surface != null && parent != null;
+        if (destroy) {
+            if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to original parent");
+            t.reparent(surface, parent.getHandle());
+        }
+        mLeash = null;
+        mAnimation = null;
+
+        // Make sure to inform the animatable after the leash was destroyed.
+        if (destroy) {
+            mAnimatable.onLeashDestroyed(t);
+        }
+    }
+
+    private SurfaceControl createAnimationLeash(SurfaceControl surface, Transaction t, int width,
+            int height, boolean hidden) {
+        if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to leash");
+        final SurfaceControl.Builder builder = mAnimatable.makeLeash()
+                .setName(surface + " - animation-leash")
+                .setSize(width, height);
+        final SurfaceControl leash = builder.build();
+        if (!hidden) {
+            t.show(leash);
+        }
+        t.reparent(surface, leash.getHandle());
+        return leash;
+    }
+
+    void dump(PrintWriter pw, String prefix) {
+        pw.print(prefix); pw.print("mAnimation="); pw.print(mAnimation);
+        pw.print(" mLeash="); pw.println(mLeash);
+    }
+
+    /**
+     * Callback to be passed into {@link AnimationAdapter#startAnimation} to be invoked by the
+     * component that is running the animation when the animation is finished.
+     */
+    interface OnAnimationFinishedCallback {
+        void onAnimationFinished(AnimationAdapter anim);
+    }
+
+    /**
+     * Interface to be animated by {@link SurfaceAnimator}.
+     */
+    interface Animatable {
+
+        /**
+         * @return The pending transaction that will be committed in the next frame.
+         */
+        @NonNull Transaction getPendingTransaction();
+
+        /**
+         * Schedules a commit of the pending transaction.
+         */
+        void commitPendingTransaction();
+
+        /**
+         * Called when the was created.
+         *
+         * @param t The transaction to use to apply any necessary changes.
+         * @param leash The leash that was created.
+         */
+        void onLeashCreated(Transaction t, SurfaceControl leash);
+
+        /**
+         * Called when the leash is being destroyed, and the surface was reparented back to the
+         * original parent.
+         *
+         * @param t The transaction to use to apply any necessary changes.
+         */
+        void onLeashDestroyed(Transaction t);
+
+        /**
+         * @return A new child surface.
+         */
+        SurfaceControl.Builder makeLeash();
+
+        /**
+         * @return The surface of the object to be animated.
+         */
+        @Nullable SurfaceControl getSurface();
+
+        /**
+         * @return The parent of the surface object to be animated.
+         */
+        @Nullable SurfaceControl getParentSurface();
+
+        /**
+         * @return The width of the surface to be animated.
+         */
+        int getSurfaceWidth();
+
+        /**
+         * @return The height of the surface to be animated.
+         */
+        int getSurfaceHeight();
+    }
+}
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 87d0a40..ca9f3a9 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -16,15 +16,11 @@
 
 package com.android.server.wm;
 
-import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
-import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
 import static android.app.ActivityManager.RESIZE_MODE_USER;
 import static android.app.ActivityManager.RESIZE_MODE_USER_FORCED;
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.dipToPixel;
@@ -44,7 +40,6 @@
 import android.view.BatchedInputEventReceiver;
 import android.view.Choreographer;
 import android.view.Display;
-import android.view.DisplayInfo;
 import android.view.InputChannel;
 import android.view.InputDevice;
 import android.view.InputEvent;
diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java
new file mode 100644
index 0000000..bb5706c
--- /dev/null
+++ b/services/core/java/com/android/server/wm/TaskPositioningController.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
+import android.annotation.Nullable;
+import android.app.IActivityManager;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.view.Display;
+import android.view.IWindow;
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.input.InputManagerService;
+import com.android.server.input.InputWindowHandle;
+
+/**
+ * Controller for task positioning by drag.
+ */
+class TaskPositioningController {
+    private final WindowManagerService mService;
+    private final InputManagerService mInputManager;
+    private final InputMonitor mInputMonitor;
+    private final IActivityManager mActivityManager;
+
+    @GuardedBy("WindowManagerSerivce.mWindowMap")
+    private @Nullable TaskPositioner mTaskPositioner;
+
+    boolean isPositioningLocked() {
+        return mTaskPositioner != null;
+    }
+
+    InputWindowHandle getDragWindowHandleLocked() {
+        return mTaskPositioner != null ? mTaskPositioner.mDragWindowHandle : null;
+    }
+
+    TaskPositioningController(WindowManagerService service, InputManagerService inputManager,
+            InputMonitor inputMonitor, IActivityManager activityManager) {
+        mService = service;
+        mInputMonitor = inputMonitor;
+        mInputManager = inputManager;
+        mActivityManager = activityManager;
+    }
+
+    boolean startMovingTask(IWindow window, float startX, float startY) {
+        WindowState win = null;
+        synchronized (mService.mWindowMap) {
+            win = mService.windowForClientLocked(null, window, false);
+            // win shouldn't be null here, pass it down to startPositioningLocked
+            // to get warning if it's null.
+            if (!startPositioningLocked(
+                    win, false /*resize*/, false /*preserveOrientation*/, startX, startY)) {
+                return false;
+            }
+        }
+        try {
+            mActivityManager.setFocusedTask(win.getTask().mTaskId);
+        } catch(RemoteException e) {}
+        return true;
+    }
+
+    void handleTapOutsideTask(DisplayContent displayContent, int x, int y) {
+        int taskId = -1;
+        synchronized (mService.mWindowMap) {
+            final Task task = displayContent.findTaskForResizePoint(x, y);
+            if (task != null) {
+                if (!startPositioningLocked(task.getTopVisibleAppMainWindow(), true /*resize*/,
+                        task.preserveOrientationOnResize(), x, y)) {
+                    return;
+                }
+                taskId = task.mTaskId;
+            } else {
+                taskId = displayContent.taskIdFromPoint(x, y);
+            }
+        }
+        if (taskId >= 0) {
+            try {
+                mActivityManager.setFocusedTask(taskId);
+            } catch(RemoteException e) {}
+        }
+    }
+
+    private boolean startPositioningLocked(WindowState win, boolean resize,
+            boolean preserveOrientation, float startX, float startY) {
+        if (DEBUG_TASK_POSITIONING)
+            Slog.d(TAG_WM, "startPositioningLocked: "
+                    + "win=" + win + ", resize=" + resize + ", preserveOrientation="
+                    + preserveOrientation + ", {" + startX + ", " + startY + "}");
+
+        if (win == null || win.getAppToken() == null) {
+            Slog.w(TAG_WM, "startPositioningLocked: Bad window " + win);
+            return false;
+        }
+        if (win.mInputChannel == null) {
+            Slog.wtf(TAG_WM, "startPositioningLocked: " + win + " has no input channel, "
+                    + " probably being removed");
+            return false;
+        }
+
+        final DisplayContent displayContent = win.getDisplayContent();
+        if (displayContent == null) {
+            Slog.w(TAG_WM, "startPositioningLocked: Invalid display content " + win);
+            return false;
+        }
+
+        Display display = displayContent.getDisplay();
+        mTaskPositioner = new TaskPositioner(mService);
+        mTaskPositioner.register(displayContent);
+        mInputMonitor.updateInputWindowsLw(true /*force*/);
+
+        // We need to grab the touch focus so that the touch events during the
+        // resizing/scrolling are not sent to the app. 'win' is the main window
+        // of the app, it may not have focus since there might be other windows
+        // on top (eg. a dialog window).
+        WindowState transferFocusFromWin = win;
+        if (mService.mCurrentFocus != null && mService.mCurrentFocus != win
+                && mService.mCurrentFocus.mAppToken == win.mAppToken) {
+            transferFocusFromWin = mService.mCurrentFocus;
+        }
+        if (!mInputManager.transferTouchFocus(
+                transferFocusFromWin.mInputChannel, mTaskPositioner.mServerChannel)) {
+            Slog.e(TAG_WM, "startPositioningLocked: Unable to transfer touch focus");
+            mTaskPositioner.unregister();
+            mTaskPositioner = null;
+            mInputMonitor.updateInputWindowsLw(true /*force*/);
+            return false;
+        }
+
+        mTaskPositioner.startDrag(win, resize, preserveOrientation, startX, startY);
+        return true;
+    }
+
+    void finishPositioning() {
+        if (DEBUG_TASK_POSITIONING) Slog.d(TAG_WM, "finishPositioning");
+
+        synchronized (mService.mWindowMap) {
+            if (mTaskPositioner != null) {
+                mTaskPositioner.unregister();
+                mTaskPositioner = null;
+                mInputMonitor.updateInputWindowsLw(true /*force*/);
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 832d395..28b1390 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -1114,12 +1114,12 @@
             return false;
         }
 
-        final Rect displayContentRect = mTmpRect;
+        final Rect displayStableRect = mTmpRect;
         final Rect contentBounds = mTmpRect2;
 
         // Calculate the content bounds excluding the area occupied by IME
-        getDisplayContent().getContentRect(displayContentRect);
-        contentBounds.set(displayContentRect);
+        getDisplayContent().getStableRect(displayStableRect);
+        contentBounds.set(displayStableRect);
         int imeTop = Math.max(imeWin.getFrameLw().top, contentBounds.top);
 
         imeTop += imeWin.getGivenContentInsetsLw().top;
@@ -1127,7 +1127,7 @@
             contentBounds.bottom = imeTop;
         }
 
-        final int yOffset = displayContentRect.bottom - contentBounds.bottom;
+        final int yOffset = displayStableRect.bottom - contentBounds.bottom;
 
         final int dividerWidth =
                 getDisplayContent().mDividerControllerLocked.getContentWidth();
@@ -1139,7 +1139,7 @@
             // occluded by IME. We shift its bottom up by the height of the IME, but
             // leaves at least 30% of the top stack visible.
             final int minTopStackBottom =
-                    getMinTopStackBottom(displayContentRect, getRawBounds().bottom);
+                    getMinTopStackBottom(displayStableRect, getRawBounds().bottom);
             final int bottom = Math.max(
                     getRawBounds().bottom - yOffset + dividerWidth - dividerWidthInactive,
                     minTopStackBottom);
@@ -1159,7 +1159,7 @@
             final int topBeforeImeAdjust =
                     getRawBounds().top - dividerWidth + dividerWidthInactive;
             final int minTopStackBottom =
-                    getMinTopStackBottom(displayContentRect,
+                    getMinTopStackBottom(displayStableRect,
                             getRawBounds().top - dividerWidth);
             final int top = Math.max(
                     getRawBounds().top - yOffset, minTopStackBottom + dividerWidthInactive);
diff --git a/services/core/java/com/android/server/wm/WindowAnimationSpec.java b/services/core/java/com/android/server/wm/WindowAnimationSpec.java
new file mode 100644
index 0000000..56175c7
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WindowAnimationSpec.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import android.graphics.Point;
+import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
+import android.view.animation.Animation;
+import android.view.animation.Transformation;
+
+import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
+
+/**
+ * Animation spec for regular window animations.
+ */
+public class WindowAnimationSpec implements AnimationSpec {
+
+    private Animation mAnimation;
+    private final Point mPosition = new Point();
+    private final ThreadLocal<Tmp> mThreadLocalTmps = ThreadLocal.withInitial(Tmp::new);
+
+    public WindowAnimationSpec(Animation animation, Point position)  {
+        mAnimation = animation;
+        mPosition.set(position.x, position.y);
+    }
+
+    @Override
+    public boolean getDetachWallpaper() {
+        return mAnimation.getDetachWallpaper();
+    }
+
+    @Override
+    public int getBackgroundColor() {
+        return mAnimation.getBackgroundColor();
+    }
+
+    @Override
+    public long getDuration() {
+        return mAnimation.computeDurationHint();
+    }
+
+    @Override
+    public void apply(Transaction t, SurfaceControl leash, long currentPlayTime) {
+        final Tmp tmp = mThreadLocalTmps.get();
+        tmp.transformation.clear();
+        mAnimation.getTransformation(currentPlayTime, tmp.transformation);
+        tmp.transformation.getMatrix().postTranslate(mPosition.x, mPosition.y);
+        t.setMatrix(leash, tmp.transformation.getMatrix(), tmp.floats);
+        t.setAlpha(leash, tmp.transformation.getAlpha());
+    }
+
+    private static class Tmp {
+        final Transformation transformation = new Transformation();
+        final float[] floats = new float[9];
+    }
+}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index e598224..8c9948e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -755,7 +755,7 @@
     // Whether or not a layout can cause a wake up when theater mode is enabled.
     boolean mAllowTheaterModeWakeFromLayout;
 
-    TaskPositioner mTaskPositioner;
+    final TaskPositioningController mTaskPositioningController;
     final DragDropController mDragDropController;
 
     // For frozen screen animations.
@@ -769,6 +769,7 @@
     int mTransactionSequence;
 
     final WindowAnimator mAnimator;
+    final SurfaceAnimationRunner mSurfaceAnimationRunner;
 
     final BoundsAnimationController mBoundsAnimationController;
 
@@ -1082,10 +1083,13 @@
         mHoldingScreenWakeLock.setReferenceCounted(false);
 
         mAnimator = new WindowAnimator(this);
+        mSurfaceAnimationRunner = new SurfaceAnimationRunner();
 
         mAllowTheaterModeWakeFromLayout = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_allowTheaterModeWakeFromWindowLayout);
 
+        mTaskPositioningController =
+                new TaskPositioningController(this, mInputManager, mInputMonitor, mActivityManager);
         mDragDropController = new DragDropController(this, mH.getLooper());
 
         LocalServices.addService(WindowManagerInternal.class, new LocalService());
@@ -4440,107 +4444,6 @@
         }
     }
 
-    boolean startMovingTask(IWindow window, float startX, float startY) {
-        WindowState win = null;
-        synchronized (mWindowMap) {
-            win = windowForClientLocked(null, window, false);
-            // win shouldn't be null here, pass it down to startPositioningLocked
-            // to get warning if it's null.
-            if (!startPositioningLocked(
-                        win, false /*resize*/, false /*preserveOrientation*/, startX, startY)) {
-                return false;
-            }
-        }
-        try {
-            mActivityManager.setFocusedTask(win.getTask().mTaskId);
-        } catch(RemoteException e) {}
-        return true;
-    }
-
-    private void handleTapOutsideTask(DisplayContent displayContent, int x, int y) {
-        int taskId = -1;
-        synchronized (mWindowMap) {
-            final Task task = displayContent.findTaskForResizePoint(x, y);
-            if (task != null) {
-                if (!startPositioningLocked(task.getTopVisibleAppMainWindow(), true /*resize*/,
-                            task.preserveOrientationOnResize(), x, y)) {
-                    return;
-                }
-                taskId = task.mTaskId;
-            } else {
-                taskId = displayContent.taskIdFromPoint(x, y);
-            }
-        }
-        if (taskId >= 0) {
-            try {
-                mActivityManager.setFocusedTask(taskId);
-            } catch(RemoteException e) {}
-        }
-    }
-
-    private boolean startPositioningLocked(WindowState win, boolean resize,
-            boolean preserveOrientation, float startX, float startY) {
-        if (DEBUG_TASK_POSITIONING)
-            Slog.d(TAG_WM, "startPositioningLocked: "
-                            + "win=" + win + ", resize=" + resize + ", preserveOrientation="
-                            + preserveOrientation + ", {" + startX + ", " + startY + "}");
-
-        if (win == null || win.getAppToken() == null) {
-            Slog.w(TAG_WM, "startPositioningLocked: Bad window " + win);
-            return false;
-        }
-        if (win.mInputChannel == null) {
-            Slog.wtf(TAG_WM, "startPositioningLocked: " + win + " has no input channel, "
-                    + " probably being removed");
-            return false;
-        }
-
-        final DisplayContent displayContent = win.getDisplayContent();
-        if (displayContent == null) {
-            Slog.w(TAG_WM, "startPositioningLocked: Invalid display content " + win);
-            return false;
-        }
-
-        Display display = displayContent.getDisplay();
-        mTaskPositioner = new TaskPositioner(this);
-        mTaskPositioner.register(displayContent);
-        mInputMonitor.updateInputWindowsLw(true /*force*/);
-
-        // We need to grab the touch focus so that the touch events during the
-        // resizing/scrolling are not sent to the app. 'win' is the main window
-        // of the app, it may not have focus since there might be other windows
-        // on top (eg. a dialog window).
-        WindowState transferFocusFromWin = win;
-        if (mCurrentFocus != null && mCurrentFocus != win
-                && mCurrentFocus.mAppToken == win.mAppToken) {
-            transferFocusFromWin = mCurrentFocus;
-        }
-        if (!mInputManager.transferTouchFocus(
-                transferFocusFromWin.mInputChannel, mTaskPositioner.mServerChannel)) {
-            Slog.e(TAG_WM, "startPositioningLocked: Unable to transfer touch focus");
-            mTaskPositioner.unregister();
-            mTaskPositioner = null;
-            mInputMonitor.updateInputWindowsLw(true /*force*/);
-            return false;
-        }
-
-        mTaskPositioner.startDrag(win, resize, preserveOrientation, startX, startY);
-        return true;
-    }
-
-    private void finishPositioning() {
-        if (DEBUG_TASK_POSITIONING) {
-            Slog.d(TAG_WM, "finishPositioning");
-        }
-        synchronized (mWindowMap) {
-            if (mTaskPositioner != null) {
-                mTaskPositioner.unregister();
-                mTaskPositioner = null;
-                mInputMonitor.updateInputWindowsLw(true /*force*/);
-            }
-        }
-    }
-
     // -------------------------------------------------------------
     // Input Events and Focus Management
     // -------------------------------------------------------------
@@ -5003,12 +4906,13 @@
                 }
 
                 case TAP_OUTSIDE_TASK: {
-                    handleTapOutsideTask((DisplayContent)msg.obj, msg.arg1, msg.arg2);
+                    mTaskPositioningController.handleTapOutsideTask(
+                            (DisplayContent)msg.obj, msg.arg1, msg.arg2);
                 }
                 break;
 
                 case FINISH_TASK_POSITIONING: {
-                    finishPositioning();
+                    mTaskPositioningController.finishPositioning();
                 }
                 break;
 
diff --git a/services/core/jni/com_android_server_GraphicsStatsService.cpp b/services/core/jni/com_android_server_GraphicsStatsService.cpp
index 44e27a5..8385020 100644
--- a/services/core/jni/com_android_server_GraphicsStatsService.cpp
+++ b/services/core/jni/com_android_server_GraphicsStatsService.cpp
@@ -41,11 +41,14 @@
 static void addToDump(JNIEnv* env, jobject, jlong dumpPtr, jstring jpath, jstring jpackage,
         jint versionCode, jlong startTime, jlong endTime, jbyteArray jdata) {
     std::string path;
+    const ProfileData* data = nullptr;
     LOG_ALWAYS_FATAL_IF(jdata == nullptr && jpath == nullptr, "Path and data can't both be null");
-    ScopedNullableByteArrayRO buffer(env, jdata);
-    if (buffer.size() != -1) {
+    ScopedByteArrayRO buffer{env};
+    if (jdata != nullptr) {
+        buffer.reset(jdata);
         LOG_ALWAYS_FATAL_IF(buffer.size() != sizeof(ProfileData),
-                "Buffer size %zd doesn't match expected %zu!", buffer.size(), sizeof(ProfileData));
+                "Buffer size %zu doesn't match expected %zu!", buffer.size(), sizeof(ProfileData));
+        data = reinterpret_cast<const ProfileData*>(buffer.get());
     }
     if (jpath != nullptr) {
         ScopedUtfChars pathChars(env, jpath);
@@ -58,8 +61,7 @@
     LOG_ALWAYS_FATAL_IF(!dump, "null passed for dump pointer");
 
     const std::string package(packageChars.c_str(), packageChars.size());
-    GraphicsStatsService::addToDump(dump, path, package, versionCode, startTime, endTime,
-                                    reinterpret_cast<const ProfileData*>(buffer.get()));
+    GraphicsStatsService::addToDump(dump, path, package, versionCode, startTime, endTime, data);
 }
 
 static void addFileToDump(JNIEnv* env, jobject, jlong dumpPtr, jstring jpath) {
@@ -106,4 +108,4 @@
                                     sMethods, NELEM(sMethods));
 }
 
-} // namespace android
+} // namespace android
\ No newline at end of file
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index b979ff4..91ba87e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -79,7 +79,6 @@
 import android.app.admin.DeviceAdminReceiver;
 import android.app.admin.DevicePolicyManager;
 import android.app.admin.DevicePolicyManagerInternal;
-import android.app.admin.IDevicePolicyManager;
 import android.app.admin.NetworkEvent;
 import android.app.admin.PasswordMetrics;
 import android.app.admin.SecurityLog;
@@ -740,7 +739,7 @@
         private static final String TAG_ORGANIZATION_NAME = "organization-name";
         private static final String ATTR_LAST_NETWORK_LOGGING_NOTIFICATION = "last-notification";
         private static final String ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS = "num-notifications";
-        private static final String TAG_IS_LOGOUT_BUTTON_ENABLED = "is_logout_button_enabled";
+        private static final String TAG_IS_LOGOUT_ENABLED = "is_logout_enabled";
 
         final DeviceAdminInfo info;
 
@@ -790,7 +789,7 @@
         boolean requireAutoTime = false; // Can only be set by a device owner.
         boolean forceEphemeralUsers = false; // Can only be set by a device owner.
         boolean isNetworkLoggingEnabled = false; // Can only be set by a device owner.
-        boolean isLogoutButtonEnabled = false; // Can only be set by a device owner.
+        boolean isLogoutEnabled = false; // Can only be set by a device owner.
 
         // one notification after enabling + one more after reboots
         static final int DEF_MAXIMUM_NETWORK_LOGGING_NOTIFICATIONS_SHOWN = 2;
@@ -1108,10 +1107,10 @@
                 out.text(organizationName);
                 out.endTag(null, TAG_ORGANIZATION_NAME);
             }
-            if (isLogoutButtonEnabled) {
-                out.startTag(null, TAG_IS_LOGOUT_BUTTON_ENABLED);
-                out.attribute(null, ATTR_VALUE, Boolean.toString(isLogoutButtonEnabled));
-                out.endTag(null, TAG_IS_LOGOUT_BUTTON_ENABLED);
+            if (isLogoutEnabled) {
+                out.startTag(null, TAG_IS_LOGOUT_ENABLED);
+                out.attribute(null, ATTR_VALUE, Boolean.toString(isLogoutEnabled));
+                out.endTag(null, TAG_IS_LOGOUT_ENABLED);
             }
         }
 
@@ -1286,8 +1285,8 @@
                     } else {
                         Log.w(LOG_TAG, "Missing text when loading organization name");
                     }
-                } else if (TAG_IS_LOGOUT_BUTTON_ENABLED.equals(tag)) {
-                    isLogoutButtonEnabled = Boolean.parseBoolean(
+                } else if (TAG_IS_LOGOUT_ENABLED.equals(tag)) {
+                    isLogoutEnabled = Boolean.parseBoolean(
                             parser.getAttributeValue(null, ATTR_VALUE));
                 } else {
                     Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
@@ -11581,35 +11580,35 @@
     }
 
     @Override
-    public synchronized void setLogoutButtonEnabled(ComponentName admin, boolean enabled) {
+    public synchronized void setLogoutEnabled(ComponentName admin, boolean enabled) {
         if (!mHasFeature) {
             return;
         }
         Preconditions.checkNotNull(admin);
         getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
 
-        if (enabled == isLogoutButtonEnabledInternalLocked()) {
+        if (enabled == isLogoutEnabledInternalLocked()) {
             // already in the requested state
             return;
         }
         ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
-        deviceOwner.isLogoutButtonEnabled = enabled;
+        deviceOwner.isLogoutEnabled = enabled;
         saveSettingsLocked(mInjector.userHandleGetCallingUserId());
     }
 
     @Override
-    public boolean isLogoutButtonEnabled() {
+    public boolean isLogoutEnabled() {
         if (!mHasFeature) {
             return false;
         }
         synchronized (this) {
-            return isLogoutButtonEnabledInternalLocked();
+            return isLogoutEnabledInternalLocked();
         }
     }
 
-    private boolean isLogoutButtonEnabledInternalLocked() {
+    private boolean isLogoutEnabledInternalLocked() {
         ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
-        return (deviceOwner != null) && deviceOwner.isLogoutButtonEnabled;
+        return (deviceOwner != null) && deviceOwner.isLogoutEnabled;
     }
 
 }
diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java
index b305b33..fdb366c 100644
--- a/services/net/java/android/net/ip/IpClient.java
+++ b/services/net/java/android/net/ip/IpClient.java
@@ -163,10 +163,10 @@
     // TODO: Find an lighter weight approach.
     private class LoggingCallbackWrapper extends Callback {
         private static final String PREFIX = "INVOKE ";
-        private final Callback mCallback;
+        private Callback mCallback;
 
         public LoggingCallbackWrapper(Callback callback) {
-            mCallback = (callback != null) ? callback : new Callback();
+            mCallback = callback;
         }
 
         private void log(String msg) {
@@ -1283,7 +1283,6 @@
             stopAllIP();
 
             resetLinkProperties();
-            mCallback.onLinkPropertiesChange(new LinkProperties(mLinkProperties));
             if (mStartTimeMillis > 0) {
                 recordMetric(IpManagerEvent.COMPLETE_LIFECYCLE);
                 mStartTimeMillis = 0;
diff --git a/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java b/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java
index 0ea8d4f..5d739a3 100644
--- a/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java
@@ -32,6 +32,9 @@
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
+import java.time.Clock;
+import java.time.Instant;
+import java.time.ZoneId;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -57,7 +60,7 @@
     private ConfigHelper mMockConfigHelper;
     private PackageManagerHelper mMockPackageManagerHelper;
 
-    private FakeClockHelper mFakeClock;
+    private FakeClock mFakeClock;
     private FakeIntentHelper mFakeIntentHelper;
     private PackageStatusStorage mPackageStatusStorage;
     private PackageTracker mPackageTracker;
@@ -66,7 +69,7 @@
     public void setUp() throws Exception {
         Context context = InstrumentationRegistry.getContext();
 
-        mFakeClock = new FakeClockHelper();
+        mFakeClock = new FakeClock();
 
         // Read-only interfaces so are easy to mock.
         mMockConfigHelper = mock(ConfigHelper.class);
@@ -1444,18 +1447,33 @@
         }
     }
 
-    private static class FakeClockHelper implements ClockHelper {
+    private static class FakeClock extends Clock {
 
         private long currentTime = 1000;
 
         @Override
-        public long currentTimestamp() {
+        public long millis() {
             return currentTime;
         }
 
         public void incrementClock(long millis) {
             currentTime += millis;
         }
+
+        @Override
+        public ZoneId getZone() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Clock withZone(ZoneId zone) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Instant instant() {
+            throw new UnsupportedOperationException();
+        }
     }
 
     /**
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 87b34ab..86ce90c 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -18,6 +18,7 @@
 
 import static android.app.usage.UsageEvents.Event.NOTIFICATION_SEEN;
 import static android.app.usage.UsageEvents.Event.USER_INTERACTION;
+import static android.app.usage.UsageStatsManager.REASON_PREDICTED;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
@@ -364,4 +365,29 @@
         reportEvent(controller, NOTIFICATION_SEEN, mInjector.mElapsedRealtime);
         assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(controller));
     }
+
+    @Test
+    public void testPredictionTimedout() throws Exception {
+        AppStandbyController controller = setupController();
+        setChargingState(controller, false);
+        controller.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
+                REASON_PREDICTED + "CTS", 1 * HOUR_MS);
+
+        // Fast forward 12 hours
+        mInjector.mElapsedRealtime += WORKING_SET_THRESHOLD;
+        controller.checkIdleStates(USER_ID);
+        // Should still be in predicted bucket, since prediction timeout is 1 day since prediction
+        assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(controller));
+        // Fast forward two more hours
+        mInjector.mElapsedRealtime += 2 * HOUR_MS;
+        controller.checkIdleStates(USER_ID);
+        // Should have now applied prediction timeout
+        assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(controller));
+
+        // Fast forward RARE bucket
+        mInjector.mElapsedRealtime += RARE_THRESHOLD;
+        controller.checkIdleStates(USER_ID);
+        // Should continue to apply prediction timeout
+        assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(controller));
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
new file mode 100644
index 0000000..9ecf51e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.verify;
+
+import android.animation.AnimationHandler.AnimationFrameCallbackProvider;
+import android.graphics.Matrix;
+import android.graphics.Point;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.Choreographer;
+import android.view.Choreographer.FrameCallback;
+import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
+import android.view.animation.Animation;
+import android.view.animation.TranslateAnimation;
+
+import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * Test class for {@link SurfaceAnimationRunner}.
+ *
+ * runtest frameworks-services -c com.android.server.wm.SurfaceAnimationRunnerTest
+ */
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class SurfaceAnimationRunnerTest extends WindowTestsBase {
+
+    @Mock SurfaceControl mMockSurface;
+    @Mock Transaction mMockTransaction;
+    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+    private SurfaceAnimationRunner mSurfaceAnimationRunner;
+    private CountDownLatch mFinishCallbackLatch;
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+        mFinishCallbackLatch = new CountDownLatch(1);
+        mSurfaceAnimationRunner = new SurfaceAnimationRunner(null /* callbackProvider */,
+                mMockTransaction);
+    }
+
+    private void finishedCallback() {
+        mFinishCallbackLatch.countDown();
+    }
+
+    @Test
+    public void testAnimation() throws Exception {
+        mSurfaceAnimationRunner
+                .startAnimation(createTranslateAnimation(), mMockSurface, mMockTransaction,
+                this::finishedCallback);
+
+        // Ensure that the initial transformation has been applied.
+        final Matrix m = new Matrix();
+        m.setTranslate(-10, 0);
+        verify(mMockTransaction, atLeastOnce()).setMatrix(eq(mMockSurface), eq(m), any());
+        verify(mMockTransaction, atLeastOnce()).setAlpha(eq(mMockSurface), eq(1.0f));
+
+        mFinishCallbackLatch.await(1, SECONDS);
+        assertFinishCallbackCalled();
+
+        m.setTranslate(10, 0);
+        verify(mMockTransaction, atLeastOnce()).setMatrix(eq(mMockSurface), eq(m), any());
+
+        // At least 3 times: After initialization, first frame, last frame.
+        verify(mMockTransaction, atLeast(3)).setAlpha(eq(mMockSurface), eq(1.0f));
+    }
+
+    @Test
+    public void testCancel_notStarted() throws Exception {
+        mSurfaceAnimationRunner = new SurfaceAnimationRunner(new NoOpFrameCallbackProvider(), mMockTransaction);
+        mSurfaceAnimationRunner
+                .startAnimation(createTranslateAnimation(), mMockSurface, mMockTransaction,
+                this::finishedCallback);
+        mSurfaceAnimationRunner.onAnimationCancelled(mMockSurface);
+        waitUntilHandlersIdle();
+        assertTrue(mSurfaceAnimationRunner.mPendingAnimations.isEmpty());
+        assertFinishCallbackNotCalled();
+        //verify(mMockSurface).release();
+    }
+
+    @Test
+    public void testCancel_running() throws Exception {
+        mSurfaceAnimationRunner = new SurfaceAnimationRunner(new NoOpFrameCallbackProvider(), mMockTransaction);
+        mSurfaceAnimationRunner
+                .startAnimation(createTranslateAnimation(), mMockSurface, mMockTransaction,
+                this::finishedCallback);
+        waitUntilNextFrame();
+        assertFalse(mSurfaceAnimationRunner.mRunningAnimations.isEmpty());
+        mSurfaceAnimationRunner.onAnimationCancelled(mMockSurface);
+        assertTrue(mSurfaceAnimationRunner.mRunningAnimations.isEmpty());
+        waitUntilHandlersIdle();
+        assertFinishCallbackNotCalled();
+        //verify(mMockSurface).release();
+    }
+
+    private void waitUntilNextFrame() throws Exception {
+        final CountDownLatch latch = new CountDownLatch(1);
+        mSurfaceAnimationRunner.mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT,
+                latch::countDown, null /* token */);
+        latch.await();
+    }
+
+    private void assertFinishCallbackCalled() {
+        assertEquals(0, mFinishCallbackLatch.getCount());
+    }
+
+    private void assertFinishCallbackNotCalled() {
+        assertEquals(1, mFinishCallbackLatch.getCount());
+    }
+
+    private AnimationSpec createTranslateAnimation() {
+        final Animation a = new TranslateAnimation(-10, 10, 0, 0);
+        a.initialize(0, 0, 0, 0);
+        a.setDuration(50);
+        return new WindowAnimationSpec(a, new Point(0, 0));
+    }
+
+    /**
+     * Callback provider that doesn't animate at all.
+     */
+    private static final class NoOpFrameCallbackProvider implements AnimationFrameCallbackProvider {
+
+        @Override
+        public void postFrameCallback(FrameCallback callback) {
+        }
+
+        @Override
+        public void postCommitCallback(Runnable runnable) {
+        }
+
+        @Override
+        public long getFrameTime() {
+            return 0;
+        }
+
+        @Override
+        public long getFrameDelay() {
+            return 0;
+        }
+
+        @Override
+        public void setFrameDelay(long delay) {
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
new file mode 100644
index 0000000..9a52042
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.SurfaceControl;
+import android.view.SurfaceControl.Builder;
+import android.view.SurfaceControl.Transaction;
+import android.view.SurfaceSession;
+
+import com.google.android.collect.Lists;
+
+import com.android.server.wm.SurfaceAnimator.Animatable;
+import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+
+/**
+ * Test class for {@link SurfaceAnimatorTest}.
+ *
+ * runtest frameworks-services -c com.android.server.wm.SurfaceAnimatorTest
+ */
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class SurfaceAnimatorTest extends WindowTestsBase {
+
+    @Mock
+    AnimationAdapter mSpec;
+    @Mock
+    AnimationAdapter mSpec2;
+    @Mock Transaction mTransaction;
+
+    private SurfaceAnimator mSurfaceAnimator;
+    private SurfaceControl mParent;
+    private SurfaceControl mSurface;
+    private boolean mFinishedCallbackCalled;
+    private SurfaceControl mLeash;
+    private SurfaceSession mSession = new SurfaceSession();
+
+    private final Animatable mAnimatable = new Animatable() {
+        @Override
+        public Transaction getPendingTransaction() {
+            return mTransaction;
+        }
+
+        @Override
+        public void commitPendingTransaction() {
+        }
+
+        @Override
+        public void onLeashCreated(Transaction t, SurfaceControl leash) {
+        }
+
+        @Override
+        public void onLeashDestroyed(Transaction t) {
+        }
+
+        @Override
+        public Builder makeLeash() {
+            return new SurfaceControl.Builder(mSession) {
+
+                @Override
+                public SurfaceControl build() {
+                    mLeash = super.build();
+                    return mLeash;
+                }
+            }.setParent(mParent);
+        }
+
+        @Override
+        public SurfaceControl getSurface() {
+            return mSurface;
+        }
+
+        @Override
+        public SurfaceControl getParentSurface() {
+            return mParent;
+        }
+
+        @Override
+        public int getSurfaceWidth() {
+            return 1;
+        }
+
+        @Override
+        public int getSurfaceHeight() {
+            return 1;
+        }
+    };
+
+    private final Runnable mFinishedCallback = () -> {
+        mFinishedCallbackCalled = true;
+    };
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+        MockitoAnnotations.initMocks(this);
+        mParent = sWm.makeSurfaceBuilder(mSession)
+                .setName("test surface parent")
+                .setSize(3000, 3000)
+                .build();
+        mSurface = sWm.makeSurfaceBuilder(mSession)
+                .setName("test surface")
+                .setSize(1, 1)
+                .build();
+        mFinishedCallbackCalled = false;
+        mLeash = null;
+        mSurfaceAnimator = new SurfaceAnimator(mAnimatable, mFinishedCallback, sWm);
+    }
+
+    @Test
+    public void testRunAnimation() throws Exception {
+        mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+        final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
+                OnAnimationFinishedCallback.class);
+
+        assertTrue(mSurfaceAnimator.isAnimating());
+        assertNotNull(mSurfaceAnimator.getAnimation());
+        verify(mTransaction).reparent(eq(mSurface), eq(mLeash.getHandle()));
+        verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture());
+
+        callbackCaptor.getValue().onAnimationFinished(mSpec);
+        assertFalse(mSurfaceAnimator.isAnimating());
+        assertNull(mSurfaceAnimator.getAnimation());
+        assertTrue(mFinishedCallbackCalled);
+
+        // TODO: Verify reparenting once we use mPendingTransaction to reparent it back
+    }
+
+    @Test
+    public void testOverrideAnimation() throws Exception {
+        mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+        mSurfaceAnimator.startAnimation(mTransaction, mSpec2, true /* hidden */);
+
+        assertFalse(mFinishedCallbackCalled);
+
+        final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
+                OnAnimationFinishedCallback.class);
+        assertTrue(mSurfaceAnimator.isAnimating());
+        assertNotNull(mSurfaceAnimator.getAnimation());
+        verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture());
+
+        // First animation was finished, but this shouldn't cancel the second animation
+        callbackCaptor.getValue().onAnimationFinished(mSpec);
+        assertTrue(mSurfaceAnimator.isAnimating());
+
+        // Second animation was finished
+        verify(mSpec2).startAnimation(any(), any(), callbackCaptor.capture());
+        callbackCaptor.getValue().onAnimationFinished(mSpec2);
+        assertFalse(mSurfaceAnimator.isAnimating());
+        assertTrue(mFinishedCallbackCalled);
+    }
+
+    @Test
+    public void testCancelAnimation() throws Exception {
+        mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+        assertTrue(mSurfaceAnimator.isAnimating());
+        mSurfaceAnimator.cancelAnimation();
+        assertFalse(mSurfaceAnimator.isAnimating());
+        verify(mSpec).onAnimationCancelled(any());
+        assertTrue(mFinishedCallbackCalled);
+    }
+
+    @Test
+    public void testDelayingAnimationStart() throws Exception {
+        mSurfaceAnimator.startDelayingAnimationStart();
+        mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+        verifyZeroInteractions(mSpec);
+        assertTrue(mSurfaceAnimator.isAnimating());
+        mSurfaceAnimator.endDelayingAnimationStart();
+        verify(mSpec).startAnimation(any(), any(), any());
+    }
+
+    @Test
+    public void testDelayingAnimationStartAndCancelled() throws Exception {
+        mSurfaceAnimator.startDelayingAnimationStart();
+        mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+        mSurfaceAnimator.cancelAnimation();
+        verifyZeroInteractions(mSpec);
+        assertFalse(mSurfaceAnimator.isAnimating());
+        assertTrue(mFinishedCallbackCalled);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskPositioningControllerTests.java
new file mode 100644
index 0000000..89447a9
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskPositioningControllerTests.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.InputChannel;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+/**
+ * Tests for the {@link TaskPositioningController} class.
+ *
+ * atest com.android.server.wm.TaskPositioningControllerTests
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+@Presubmit
+public class TaskPositioningControllerTests extends WindowTestsBase {
+    private static final int TIMEOUT_MS = 1000;
+    private TaskPositioningController mTarget;
+    private WindowState mWindow;
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+
+        assertNotNull(sWm.mTaskPositioningController);
+        mTarget = sWm.mTaskPositioningController;
+
+        when(sWm.mInputManager.transferTouchFocus(
+                any(InputChannel.class),
+                any(InputChannel.class))).thenReturn(true);
+
+        mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window");
+        mWindow.mInputChannel = new InputChannel();
+        synchronized (sWm.mWindowMap) {
+            sWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow);
+        }
+    }
+
+    @Test
+    public void testStartAndFinishPositioning() throws Exception {
+        synchronized (sWm.mWindowMap) {
+            assertFalse(mTarget.isPositioningLocked());
+            assertNull(mTarget.getDragWindowHandleLocked());
+        }
+
+        assertTrue(mTarget.startMovingTask(mWindow.mClient, 0, 0));
+
+        synchronized (sWm.mWindowMap) {
+            assertTrue(mTarget.isPositioningLocked());
+            assertNotNull(mTarget.getDragWindowHandleLocked());
+        }
+
+        assertTrue(sWm.mH.runWithScissors(() -> {
+            mTarget.finishPositioning();
+        }, TIMEOUT_MS));
+
+        assertFalse(mTarget.isPositioningLocked());
+        assertNull(mTarget.getDragWindowHandleLocked());
+    }
+
+    @Test
+    public void testHandleTapOutsideTask() throws Exception {
+        synchronized (sWm.mWindowMap) {
+
+            assertFalse(mTarget.isPositioningLocked());
+            assertNull(mTarget.getDragWindowHandleLocked());
+        }
+
+        final DisplayContent content = mock(DisplayContent.class);
+        when(content.findTaskForResizePoint(anyInt(), anyInt())).thenReturn(mWindow.getTask());
+        assertNotNull(mWindow.getTask().getTopVisibleAppMainWindow());
+
+        mTarget.handleTapOutsideTask(content, 0, 0);
+
+        synchronized (sWm.mWindowMap) {
+            assertTrue(mTarget.isPositioningLocked());
+            assertNotNull(mTarget.getDragWindowHandleLocked());
+        }
+
+        assertTrue(sWm.mH.runWithScissors(() -> {
+            mTarget.finishPositioning();
+        }, TIMEOUT_MS));
+
+        assertFalse(mTarget.isPositioningLocked());
+        assertNull(mTarget.getDragWindowHandleLocked());
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 4c5e291..c699a94 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -185,6 +185,7 @@
     void waitUntilHandlersIdle() {
         sWm.mH.runWithScissors(() -> { }, 0);
         sWm.mAnimationHandler.runWithScissors(() -> { }, 0);
+        SurfaceAnimationThread.getHandler().runWithScissors(() -> { }, 0);
     }
 
     private WindowToken createWindowToken(
diff --git a/services/usage/java/com/android/server/usage/AppIdleHistory.java b/services/usage/java/com/android/server/usage/AppIdleHistory.java
index 5aef55b..6ac4b36 100644
--- a/services/usage/java/com/android/server/usage/AppIdleHistory.java
+++ b/services/usage/java/com/android/server/usage/AppIdleHistory.java
@@ -72,14 +72,13 @@
     private static final String ATTR_SCREEN_IDLE = "screenIdleTime";
     // Elapsed timebase time when app was last used
     private static final String ATTR_ELAPSED_IDLE = "elapsedIdleTime";
+    // Elapsed timebase time when the app bucket was last predicted externally
+    private static final String ATTR_LAST_PREDICTED_TIME = "lastPredictedTime";
+    // The standby bucket for the app
     private static final String ATTR_CURRENT_BUCKET = "appLimitBucket";
+    // The reason the app was put in the above bucket
     private static final String ATTR_BUCKETING_REASON = "bucketReason";
 
-    // State that was last informed to listeners, since boot
-    private static final int STATE_UNINFORMED = 0;
-    private static final int STATE_ACTIVE = 1;
-    private static final int STATE_IDLE = 2;
-
     // device on time = mElapsedDuration + (timeNow - mElapsedSnapshot)
     private long mElapsedSnapshot; // Elapsed time snapshot when last write of mDeviceOnDuration
     private long mElapsedDuration; // Total device on duration since device was "born"
@@ -92,13 +91,21 @@
 
     private boolean mScreenOn;
 
-    private static class AppUsageHistory {
+    static class AppUsageHistory {
+        // Debug
         final byte[] recent = new byte[HISTORY_SIZE];
+        // Last used time using elapsed timebase
         long lastUsedElapsedTime;
+        // Last used time using screen_on timebase
         long lastUsedScreenTime;
+        // Last predicted time using elapsed timebase
+        long lastPredictedTime;
+        // Standby bucket
         @UsageStatsManager.StandbyBuckets
         int currentBucket;
+        // Reason for setting the standby bucket. TODO: Switch to int.
         String bucketingReason;
+        // In-memory only, last bucket for which the listeners were informed
         int lastInformedBucket;
     }
 
@@ -269,6 +276,7 @@
             appUsageHistory = new AppUsageHistory();
             appUsageHistory.lastUsedElapsedTime = getElapsedTime(elapsedRealtime);
             appUsageHistory.lastUsedScreenTime = getScreenOnTime(elapsedRealtime);
+            appUsageHistory.lastPredictedTime = getElapsedTime(0);
             appUsageHistory.currentBucket = UsageStatsManager.STANDBY_BUCKET_NEVER;
             appUsageHistory.bucketingReason = UsageStatsManager.REASON_DEFAULT;
             appUsageHistory.lastInformedBucket = -1;
@@ -295,6 +303,14 @@
         }
     }
 
+    public AppUsageHistory getAppUsageHistory(String packageName, int userId,
+            long elapsedRealtime) {
+        ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId);
+        AppUsageHistory appUsageHistory =
+                getPackageHistory(userHistory, packageName, elapsedRealtime, true);
+        return appUsageHistory;
+    }
+
     public void setAppStandbyBucket(String packageName, int userId, long elapsedRealtime,
             int bucket, String reason) {
         ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId);
@@ -302,6 +318,9 @@
                 getPackageHistory(userHistory, packageName, elapsedRealtime, true);
         appUsageHistory.currentBucket = bucket;
         appUsageHistory.bucketingReason = reason;
+        if (reason.startsWith(UsageStatsManager.REASON_PREDICTED)) {
+            appUsageHistory.lastPredictedTime = getElapsedTime(elapsedRealtime);
+        }
         if (DEBUG) {
             Slog.d(TAG, "Moved " + packageName + " to bucket=" + appUsageHistory.currentBucket
                     + ", reason=" + appUsageHistory.bucketingReason);
@@ -322,7 +341,7 @@
         return appUsageHistory != null ? appUsageHistory.bucketingReason : null;
     }
 
-    private long getElapsedTime(long elapsedRealtime) {
+    public long getElapsedTime(long elapsedRealtime) {
         return (elapsedRealtime - mElapsedSnapshot + mElapsedDuration);
     }
 
@@ -431,6 +450,12 @@
                                 Long.parseLong(parser.getAttributeValue(null, ATTR_ELAPSED_IDLE));
                         appUsageHistory.lastUsedScreenTime =
                                 Long.parseLong(parser.getAttributeValue(null, ATTR_SCREEN_IDLE));
+                        String lastPredictedTimeString = parser.getAttributeValue(null,
+                                ATTR_LAST_PREDICTED_TIME);
+                        if (lastPredictedTimeString != null) {
+                            appUsageHistory.lastPredictedTime =
+                                    Long.parseLong(lastPredictedTimeString);
+                        }
                         String currentBucketString = parser.getAttributeValue(null,
                                 ATTR_CURRENT_BUCKET);
                         appUsageHistory.currentBucket = currentBucketString == null
@@ -441,6 +466,7 @@
                         if (appUsageHistory.bucketingReason == null) {
                             appUsageHistory.bucketingReason = UsageStatsManager.REASON_DEFAULT;
                         }
+                        appUsageHistory.lastInformedBucket = -1;
                         userHistory.put(packageName, appUsageHistory);
                     }
                 }
@@ -477,6 +503,8 @@
                         Long.toString(history.lastUsedElapsedTime));
                 xml.attribute(null, ATTR_SCREEN_IDLE,
                         Long.toString(history.lastUsedScreenTime));
+                xml.attribute(null, ATTR_LAST_PREDICTED_TIME,
+                        Long.toString(history.lastPredictedTime));
                 xml.attribute(null, ATTR_CURRENT_BUCKET,
                         Integer.toString(history.currentBucket));
                 xml.attribute(null, ATTR_BUCKETING_REASON, history.bucketingReason);
@@ -512,6 +540,8 @@
             TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.lastUsedElapsedTime, idpw);
             idpw.print(" lastUsedScreenOn=");
             TimeUtils.formatDuration(screenOnTime - appUsageHistory.lastUsedScreenTime, idpw);
+            idpw.print(" lastPredictedTime=");
+            TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.lastPredictedTime, idpw);
             idpw.print(" idle=" + (isIdle(packageName, userId, elapsedRealtime) ? "y" : "n"));
             idpw.print(" bucket=" + appUsageHistory.currentBucket
                     + " reason=" + appUsageHistory.bucketingReason);
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index 3d20a64..d8086bb 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -18,6 +18,7 @@
 
 import static android.app.usage.UsageStatsManager.REASON_DEFAULT;
 import static android.app.usage.UsageStatsManager.REASON_FORCED;
+import static android.app.usage.UsageStatsManager.REASON_PREDICTED;
 import static android.app.usage.UsageStatsManager.REASON_TIMEOUT;
 import static android.app.usage.UsageStatsManager.REASON_USAGE;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
@@ -118,6 +119,9 @@
             STANDBY_BUCKET_RARE
     };
 
+    // Expiration time for predicted bucket
+    private static final long PREDICTION_TIMEOUT = 12 * ONE_HOUR;
+
     // To name the lock for stack traces
     static class Lock {}
 
@@ -388,25 +392,27 @@
                             STANDBY_BUCKET_EXEMPTED);
                 } else {
                     synchronized (mAppIdleLock) {
-                        String bucketingReason = mAppIdleHistory.getAppStandbyReason(packageName,
+                        AppIdleHistory.AppUsageHistory app =
+                                mAppIdleHistory.getAppUsageHistory(packageName,
                                 userId, elapsedRealtime);
                         // If the bucket was forced by the developer, leave it alone
-                        if (REASON_FORCED.equals(bucketingReason)) {
+                        if (REASON_FORCED.equals(app.bucketingReason)) {
                             continue;
                         }
+                        boolean predictionLate = false;
                         // If the bucket was moved up due to usage, let the timeouts apply.
-                        if (REASON_DEFAULT.equals(bucketingReason)
-                                || REASON_USAGE.equals(bucketingReason)
-                                || REASON_TIMEOUT.equals(bucketingReason)) {
-                            int oldBucket = mAppIdleHistory.getAppStandbyBucket(packageName, userId,
-                                    elapsedRealtime);
+                        if (REASON_DEFAULT.equals(app.bucketingReason)
+                                || REASON_USAGE.equals(app.bucketingReason)
+                                || REASON_TIMEOUT.equals(app.bucketingReason)
+                                || (predictionLate = predictionTimedOut(app, elapsedRealtime))) {
+                            int oldBucket = app.currentBucket;
                             int newBucket = getBucketForLocked(packageName, userId,
                                     elapsedRealtime);
                             if (DEBUG) {
                                 Slog.d(TAG, "     Old bucket=" + oldBucket
                                         + ", newBucket=" + newBucket);
                             }
-                            if (oldBucket < newBucket) {
+                            if (oldBucket < newBucket || predictionLate) {
                                 mAppIdleHistory.setAppStandbyBucket(packageName, userId,
                                         elapsedRealtime, newBucket, REASON_TIMEOUT);
                                 maybeInformListeners(packageName, userId, elapsedRealtime,
@@ -424,6 +430,14 @@
         return true;
     }
 
+    private boolean predictionTimedOut(AppIdleHistory.AppUsageHistory app, long elapsedRealtime) {
+        return app.bucketingReason != null
+                && app.bucketingReason.startsWith(REASON_PREDICTED)
+                && app.lastPredictedTime > 0
+                && mAppIdleHistory.getElapsedTime(elapsedRealtime)
+                    - app.lastPredictedTime > PREDICTION_TIMEOUT;
+    }
+
     private void maybeInformListeners(String packageName, int userId,
             long elapsedRealtime, int bucket) {
         synchronized (mAppIdleLock) {
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index a5d67c6..dd2a6df 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -83,7 +83,10 @@
     public static final int MAX_USER_DATA_SEPTETS_WITH_HEADER = 153;
 
     /** @hide */
-    @StringDef({FORMAT_3GPP, FORMAT_3GPP2})
+    @StringDef(prefix = { "FORMAT_" }, value = {
+            FORMAT_3GPP,
+            FORMAT_3GPP2
+    })
     @Retention(RetentionPolicy.SOURCE)
     public @interface Format {}
 
diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
index 5a4db99..1670e6b 100644
--- a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
@@ -16,15 +16,23 @@
 
 package android.telephony.ims.stub;
 
+import android.content.Context;
+import android.content.Intent;
 import android.os.RemoteException;
+import android.util.Log;
 
 import com.android.ims.ImsConfig;
 import com.android.ims.ImsConfigListener;
 import com.android.ims.internal.IImsConfig;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+
 
 /**
- * Base implementation of ImsConfig, which implements stub versions of the methods
- * in the IImsConfig AIDL. Override the methods that your implementation of ImsConfig supports.
+ * Base implementation of ImsConfig.
+ * Override the methods that your implementation of ImsConfig supports.
  *
  * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
  * will break other implementations of ImsConfig maintained by other ImsServices.
@@ -34,10 +42,25 @@
  * 1) Items provisioned by the operator.
  * 2) Items configured by user. Mainly service feature class.
  *
+ * The inner class {@link ImsConfigStub} implements methods of IImsConfig AIDL interface.
+ * The IImsConfig AIDL interface is called by ImsConfig, which may exist in many other processes.
+ * ImsConfigImpl access to the configuration parameters may be arbitrarily slow, especially in
+ * during initialization, or times when a lot of configuration parameters are being set/get
+ * (such as during boot up or SIM card change). By providing a cache in ImsConfigStub, we can speed
+ * up access to these configuration parameters, so a query to the ImsConfigImpl does not have to be
+ * performed every time.
  * @hide
  */
 
-public class ImsConfigImplBase extends IImsConfig.Stub {
+public class ImsConfigImplBase {
+
+    static final private String TAG = "ImsConfigImplBase";
+
+    ImsConfigStub mImsConfigStub;
+
+    public ImsConfigImplBase(Context context) {
+        mImsConfigStub = new ImsConfigStub(this, context);
+    }
 
     /**
      * Gets the value for ims service/capabilities parameters from the provisioned
@@ -46,7 +69,6 @@
      * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
      * @return value in Integer format.
      */
-    @Override
     public int getProvisionedValue(int item) throws RemoteException {
         return -1;
     }
@@ -58,7 +80,6 @@
      * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
      * @return value in String format.
      */
-    @Override
     public String getProvisionedStringValue(int item) throws RemoteException {
         return null;
     }
@@ -72,7 +93,6 @@
      * @param value in Integer format.
      * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants.
      */
-    @Override
     public int setProvisionedValue(int item, int value) throws RemoteException {
         return ImsConfig.OperationStatusConstants.FAILED;
     }
@@ -86,7 +106,6 @@
      * @param value in String format.
      * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants.
      */
-    @Override
     public int setProvisionedStringValue(int item, String value) throws RemoteException {
         return ImsConfig.OperationStatusConstants.FAILED;
     }
@@ -100,7 +119,6 @@
      * @param network as defined in android.telephony.TelephonyManager#NETWORK_TYPE_XXX.
      * @param listener feature value returned asynchronously through listener.
      */
-    @Override
     public void getFeatureValue(int feature, int network, ImsConfigListener listener)
             throws RemoteException {
     }
@@ -115,7 +133,6 @@
      * @param value as defined in com.android.ims.ImsConfig#FeatureValueConstants.
      * @param listener, provided if caller needs to be notified for set result.
      */
-    @Override
     public void setFeatureValue(int feature, int network, int value, ImsConfigListener listener)
             throws RemoteException {
     }
@@ -124,7 +141,6 @@
      * Gets the value for IMS VoLTE provisioned.
      * This should be the same as the operator provisioned value if applies.
      */
-    @Override
     public boolean getVolteProvisioned() throws RemoteException {
         return false;
     }
@@ -134,7 +150,6 @@
      *
      * @param listener Video quality value returned asynchronously through listener.
      */
-    @Override
     public void getVideoQuality(ImsConfigListener listener) throws RemoteException {
     }
 
@@ -144,7 +159,233 @@
      * @param quality, defines the value of video quality.
      * @param listener, provided if caller needs to be notified for set result.
      */
-    @Override
     public void setVideoQuality(int quality, ImsConfigListener listener) throws RemoteException {
     }
+
+    public IImsConfig getIImsConfig() { return mImsConfigStub; }
+
+    /**
+     * Updates provisioning value and notifies the framework of the change.
+     * Doesn't call #setProvisionedValue and assumes the result succeeded.
+     * This should only be used by modem when they implicitly changed provisioned values.
+     *
+     * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+     * @param value in Integer format.
+     */
+    public final void notifyProvisionedValueChanged(int item, int value) {
+        mImsConfigStub.updateCachedValue(item, value, true);
+    }
+
+    /**
+     * Updates provisioning value and notifies the framework of the change.
+     * Doesn't call #setProvisionedValue and assumes the result succeeded.
+     * This should only be used by modem when they implicitly changed provisioned values.
+     *
+     * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+     * @param value in String format.
+     */
+    public final void notifyProvisionedValueChanged(int item, String value) {
+        mImsConfigStub.updateCachedValue(item, value, true);
+    }
+
+    /**
+     * Implements the IImsConfig AIDL interface, which is called by potentially many processes
+     * in order to get/set configuration parameters.
+     *
+     * It holds an object of ImsConfigImplBase class which is usually extended by ImsConfigImpl
+     * with actual implementations from vendors. This class caches provisioned values from
+     * ImsConfigImpl layer because queries through ImsConfigImpl can be slow. When query goes in,
+     * it first checks cache layer. If missed, it will call the vendor implementation of
+     * ImsConfigImplBase API.
+     * and cache the return value if the set succeeds.
+     *
+     * Provides APIs to get/set the IMS service feature/capability/parameters.
+     * The config items include:
+     * 1) Items provisioned by the operator.
+     * 2) Items configured by user. Mainly service feature class.
+     *
+     * @hide
+     */
+    @VisibleForTesting
+    static public class ImsConfigStub extends IImsConfig.Stub {
+        Context mContext;
+        WeakReference<ImsConfigImplBase> mImsConfigImplBaseWeakReference;
+        private HashMap<Integer, Integer> mProvisionedIntValue = new HashMap<>();
+        private HashMap<Integer, String> mProvisionedStringValue = new HashMap<>();
+
+        @VisibleForTesting
+        public ImsConfigStub(ImsConfigImplBase imsConfigImplBase, Context context) {
+            mContext = context;
+            mImsConfigImplBaseWeakReference =
+                    new WeakReference<ImsConfigImplBase>(imsConfigImplBase);
+        }
+
+        /**
+         * Gets the value for ims service/capabilities parameters. It first checks its local cache,
+         * if missed, it will call ImsConfigImplBase.getProvisionedValue.
+         * Synchronous blocking call.
+         *
+         * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+         * @return value in Integer format.
+         */
+        @Override
+        public synchronized int getProvisionedValue(int item) throws RemoteException {
+            if (mProvisionedIntValue.containsKey(item)) {
+                return mProvisionedIntValue.get(item);
+            } else {
+                int retVal = getImsConfigImpl().getProvisionedValue(item);
+                if (retVal != ImsConfig.OperationStatusConstants.UNKNOWN) {
+                    updateCachedValue(item, retVal, false);
+                }
+                return retVal;
+            }
+        }
+
+        /**
+         * Gets the value for ims service/capabilities parameters. It first checks its local cache,
+         * if missed, it will call #ImsConfigImplBase.getProvisionedValue.
+         * Synchronous blocking call.
+         *
+         * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+         * @return value in String format.
+         */
+        @Override
+        public synchronized String getProvisionedStringValue(int item) throws RemoteException {
+            if (mProvisionedIntValue.containsKey(item)) {
+                return mProvisionedStringValue.get(item);
+            } else {
+                String retVal = getImsConfigImpl().getProvisionedStringValue(item);
+                if (retVal != null) {
+                    updateCachedValue(item, retVal, false);
+                }
+                return retVal;
+            }
+        }
+
+        /**
+         * Sets the value for IMS service/capabilities parameters by the operator device
+         * management entity. It sets the config item value in the provisioned storage
+         * from which the master value is derived, and write it into local cache.
+         * Synchronous blocking call.
+         *
+         * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+         * @param value in Integer format.
+         * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants.
+         */
+        @Override
+        public synchronized int setProvisionedValue(int item, int value) throws RemoteException {
+            mProvisionedIntValue.remove(item);
+            int retVal = getImsConfigImpl().setProvisionedValue(item, value);
+            if (retVal == ImsConfig.OperationStatusConstants.SUCCESS) {
+                updateCachedValue(item, retVal, true);
+            } else {
+                Log.d(TAG, "Set provision value of " + item +
+                        " to " + value + " failed with error code " + retVal);
+            }
+
+            return retVal;
+        }
+
+        /**
+         * Sets the value for IMS service/capabilities parameters by the operator device
+         * management entity. It sets the config item value in the provisioned storage
+         * from which the master value is derived, and write it into local cache.
+         * Synchronous blocking call.
+         *
+         * @param item as defined in com.android.ims.ImsConfig#ConfigConstants.
+         * @param value in String format.
+         * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants.
+         */
+        @Override
+        public synchronized int setProvisionedStringValue(int item, String value)
+                throws RemoteException {
+            mProvisionedStringValue.remove(item);
+            int retVal = getImsConfigImpl().setProvisionedStringValue(item, value);
+            if (retVal == ImsConfig.OperationStatusConstants.SUCCESS) {
+                updateCachedValue(item, retVal, true);
+            }
+
+            return retVal;
+        }
+
+        /**
+         * Wrapper function to call ImsConfigImplBase.getFeatureValue.
+         */
+        @Override
+        public void getFeatureValue(int feature, int network, ImsConfigListener listener)
+                throws RemoteException {
+            getImsConfigImpl().getFeatureValue(feature, network, listener);
+        }
+
+        /**
+         * Wrapper function to call ImsConfigImplBase.setFeatureValue.
+         */
+        @Override
+        public void setFeatureValue(int feature, int network, int value, ImsConfigListener listener)
+                throws RemoteException {
+            getImsConfigImpl().setFeatureValue(feature, network, value, listener);
+        }
+
+        /**
+         * Wrapper function to call ImsConfigImplBase.getVolteProvisioned.
+         */
+        @Override
+        public boolean getVolteProvisioned() throws RemoteException {
+            return getImsConfigImpl().getVolteProvisioned();
+        }
+
+        /**
+         * Wrapper function to call ImsConfigImplBase.getVideoQuality.
+         */
+        @Override
+        public void getVideoQuality(ImsConfigListener listener) throws RemoteException {
+            getImsConfigImpl().getVideoQuality(listener);
+        }
+
+        /**
+         * Wrapper function to call ImsConfigImplBase.setVideoQuality.
+         */
+        @Override
+        public void setVideoQuality(int quality, ImsConfigListener listener)
+                throws RemoteException {
+            getImsConfigImpl().setVideoQuality(quality, listener);
+        }
+
+        private ImsConfigImplBase getImsConfigImpl() throws RemoteException {
+            ImsConfigImplBase ref = mImsConfigImplBaseWeakReference.get();
+            if (ref == null) {
+                throw new RemoteException("Fail to get ImsConfigImpl");
+            } else {
+                return ref;
+            }
+        }
+
+        private void sendImsConfigChangedIntent(int item, int value) {
+            sendImsConfigChangedIntent(item, Integer.toString(value));
+        }
+
+        private void sendImsConfigChangedIntent(int item, String value) {
+            Intent configChangedIntent = new Intent(ImsConfig.ACTION_IMS_CONFIG_CHANGED);
+            configChangedIntent.putExtra(ImsConfig.EXTRA_CHANGED_ITEM, item);
+            configChangedIntent.putExtra(ImsConfig.EXTRA_NEW_VALUE, value);
+            if (mContext != null) {
+                mContext.sendBroadcast(configChangedIntent);
+            }
+        }
+
+        protected synchronized void updateCachedValue(int item, int value, boolean notifyChange) {
+            mProvisionedIntValue.put(item, value);
+            if (notifyChange) {
+                sendImsConfigChangedIntent(item, value);
+            }
+        }
+
+        protected synchronized void updateCachedValue(
+                int item, String value, boolean notifyChange) {
+            mProvisionedStringValue.put(item, value);
+            if (notifyChange) {
+                sendImsConfigChangedIntent(item, value);
+            }
+        }
+    }
 }
diff --git a/telephony/java/com/android/ims/ImsConfig.java b/telephony/java/com/android/ims/ImsConfig.java
index cf4c47b..cd0c4b1 100644
--- a/telephony/java/com/android/ims/ImsConfig.java
+++ b/telephony/java/com/android/ims/ImsConfig.java
@@ -619,6 +619,7 @@
             Rlog.d(TAG, "setProvisionedValue(): item = " + item +
                     " value = " + value + " ret = " + ret);
         }
+
         return ret;
     }
 
@@ -647,6 +648,7 @@
             Rlog.d(TAG, "setProvisionedStringValue(): item = " + item +
                     ", value =" + value);
         }
+
         return ret;
     }
 
diff --git a/test-base/Android.bp b/test-base/Android.bp
new file mode 100644
index 0000000..a3fd345
--- /dev/null
+++ b/test-base/Android.bp
@@ -0,0 +1,88 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Build the android.test.base library
+// ===================================
+// This contains the junit.framework and android.test classes that were in
+// Android API level 25 excluding those from android.test.runner.
+// Also contains the com.android.internal.util.Predicate[s] classes.
+java_library {
+    name: "android.test.base",
+
+    srcs: ["src/**/*.java"],
+
+    no_framework_libs: true,
+    libs: [
+        "framework",
+    ],
+
+}
+
+// Build the legacy-test library
+// =============================
+// This contains the junit.framework and android.test classes that were in
+// Android API level 25 excluding those from android.test.runner.
+// Also contains the com.android.internal.util.Predicate[s] classes.
+java_library {
+    name: "legacy-test",
+    static_libs: ["android.test.base"],
+
+    no_framework_libs: true,
+    libs: [
+        "framework",
+    ],
+}
+
+// Build the repackaged.android.test.base library
+// ==============================================
+// This contains repackaged versions of the classes from legacy-test.
+java_library_static {
+    name: "repackaged.android.test.base",
+
+    static_libs: ["android.test.base"],
+
+    no_framework_libs: true,
+    libs: [
+        "framework",
+    ],
+
+    jarjar_rules: "jarjar-rules.txt",
+}
+
+// Build the legacy-android-test library
+// =====================================
+// This contains the android.test classes that were in Android API level 25,
+// including those from android.test.runner.
+// Also contains the com.android.internal.util.Predicate[s] classes.
+java_library_static {
+    name: "legacy-android-test",
+
+    srcs: [
+        "src/android/**/*.java",
+        "src/com/**/*.java",
+    ],
+
+    static_libs: [
+        "android.test.runner",
+        "android.test.mock",
+    ],
+
+    no_framework_libs: true,
+    libs: [
+        "framework",
+        "junit",
+    ],
+}
diff --git a/test-base/Android.mk b/test-base/Android.mk
index 03bdcf23..5e5d040 100644
--- a/test-base/Android.mk
+++ b/test-base/Android.mk
@@ -16,50 +16,6 @@
 
 LOCAL_PATH:= $(call my-dir)
 
-# Build the android.test.base library
-# ===================================
-# This contains the junit.framework and android.test classes that were in
-# Android API level 25 excluding those from android.test.runner.
-# Also contains the com.android.internal.util.Predicate[s] classes.
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_MODULE := android.test.base
-LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core-oj core-libart framework
-
-include $(BUILD_JAVA_LIBRARY)
-
-# Build the legacy-test library
-# =============================
-# This contains the junit.framework and android.test classes that were in
-# Android API level 25 excluding those from android.test.runner.
-# Also contains the com.android.internal.util.Predicate[s] classes.
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_MODULE := legacy-test
-LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core-oj core-libart framework
-
-include $(BUILD_JAVA_LIBRARY)
-
-# Build the repackaged.android.test.base library
-# ==============================================
-# This contains repackaged versions of the classes from legacy-test.
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_MODULE := repackaged.android.test.base
-LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core-oj core-libart framework
-LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
 # For unbundled build we'll use the prebuilt jar from prebuilts/sdk.
 ifeq (,$(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)))
 
@@ -156,24 +112,6 @@
 
 endif  # not TARGET_BUILD_APPS not TARGET_BUILD_PDK=true
 
-# Build the legacy-android-test library
-# =====================================
-# This contains the android.test classes that were in Android API level 25,
-# including those from android.test.runner.
-# Also contains the com.android.internal.util.Predicate[s] classes.
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under, src/android) \
-    $(call all-java-files-under, ../test-runner/src/android) \
-    $(call all-java-files-under, ../test-mock/src/android) \
-    $(call all-java-files-under, src/com)
-LOCAL_MODULE := legacy-android-test
-LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core-oj core-libart framework junit
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
 # Build the legacy.test.stubs library
 # ===================================
 include $(CLEAR_VARS)
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
new file mode 100644
index 0000000..8eddec4
--- /dev/null
+++ b/test-mock/Android.bp
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2008 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.
+//
+
+// Build the android.test.mock library
+// ===================================
+java_library {
+    name: "android.test.mock",
+
+    srcs: ["src/**/*.java"],
+
+    no_framework_libs: true,
+    libs: [
+        "framework",
+        "legacy-test",
+    ],
+}
+
+// Build the repackaged.android.test.mock library
+// ==============================================
+java_library_static {
+    name: "repackaged.android.test.mock",
+
+    static_libs: ["android.test.mock"],
+
+    jarjar_rules: "jarjar-rules.txt",
+}
diff --git a/test-mock/Android.mk b/test-mock/Android.mk
index 2c07955..a761a07 100644
--- a/test-mock/Android.mk
+++ b/test-mock/Android.mk
@@ -18,32 +18,6 @@
 
 android_test_mock_source_files := $(call all-java-files-under, src/android/test/mock)
 
-# Build the repackaged.android.test.mock library
-# ==============================================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := core-oj core-libart framework
-
-LOCAL_JARJAR_RULES := $(LOCAL_PATH)/../test-base/jarjar-rules.txt
-
-LOCAL_MODULE:= repackaged.android.test.mock
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-# Build the android.test.mock library
-# ===================================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := core-oj core-libart framework
-
-LOCAL_MODULE:= android.test.mock
-
-include $(BUILD_JAVA_LIBRARY)
-
 # For unbundled build we'll use the prebuilt jar from prebuilts/sdk.
 ifeq (,$(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)))
 
diff --git a/test-mock/jarjar-rules.txt b/test-mock/jarjar-rules.txt
new file mode 120000
index 0000000..f6f7913
--- /dev/null
+++ b/test-mock/jarjar-rules.txt
@@ -0,0 +1 @@
+../test-base/jarjar-rules.txt
\ No newline at end of file
diff --git a/test-runner/Android.bp b/test-runner/Android.bp
new file mode 100644
index 0000000..104ae82
--- /dev/null
+++ b/test-runner/Android.bp
@@ -0,0 +1,40 @@
+//
+// Copyright (C) 2008 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.
+//
+
+// Build the android.test.runner library
+// =====================================
+java_library {
+    name: "android.test.runner",
+
+    srcs: ["src/**/*.java"],
+
+    no_framework_libs: true,
+    libs: [
+        "framework",
+        "legacy-test",
+        "android.test.mock",
+    ],
+}
+
+// Build the repackaged.android.test.runner library
+// ================================================
+java_library_static {
+    name: "repackaged.android.test.runner",
+
+    static_libs: ["android.test.runner"],
+
+    jarjar_rules: "jarjar-rules.txt",
+}
diff --git a/test-runner/Android.mk b/test-runner/Android.mk
index 87fe831..67f1354 100644
--- a/test-runner/Android.mk
+++ b/test-runner/Android.mk
@@ -16,42 +16,6 @@
 
 LOCAL_PATH:= $(call my-dir)
 
-# Build the android.test.runner library
-# =====================================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := \
-    core-oj \
-    core-libart \
-    framework \
-    android.test.base \
-    android.test.mock \
-
-LOCAL_MODULE:= android.test.runner
-
-include $(BUILD_JAVA_LIBRARY)
-
-# Build the repackaged.android.test.runner library
-# ================================================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := \
-    core-oj \
-    core-libart \
-    framework \
-    android.test.base \
-    android.test.mock \
-
-LOCAL_JARJAR_RULES := $(LOCAL_PATH)/../test-base/jarjar-rules.txt
-
-LOCAL_MODULE:= repackaged.android.test.runner
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
 # For unbundled build we'll use the prebuilt jar from prebuilts/sdk.
 ifeq (,$(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)))
 
diff --git a/test-runner/jarjar-rules.txt b/test-runner/jarjar-rules.txt
new file mode 120000
index 0000000..f6f7913
--- /dev/null
+++ b/test-runner/jarjar-rules.txt
@@ -0,0 +1 @@
+../test-base/jarjar-rules.txt
\ No newline at end of file
diff --git a/tests/net/java/android/net/ip/IpManagerTest.java b/tests/net/java/android/net/ip/IpManagerTest.java
index ebf121a..22d88fb 100644
--- a/tests/net/java/android/net/ip/IpManagerTest.java
+++ b/tests/net/java/android/net/ip/IpManagerTest.java
@@ -69,8 +69,6 @@
 
 /**
  * Tests for IpManager.
- *
- * TODO: Rename to IpClientTest.
  */
 @RunWith(AndroidJUnit4.class)
 @SmallTest
@@ -113,10 +111,6 @@
         verify(mNMService, times(1)).registerObserver(arg.capture());
         mObserver = arg.getValue();
         reset(mNMService);
-        final LinkProperties emptyLp = new LinkProperties();
-        emptyLp.setInterfaceName(ifname);
-        verify(mCb, timeout(100)).onLinkPropertiesChange(eq(emptyLp));
-        reset(mCb);
         return ipm;
     }
 
diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp
index 33b5a8b..20a9f41 100644
--- a/tools/aapt2/LoadedApk.cpp
+++ b/tools/aapt2/LoadedApk.cpp
@@ -57,31 +57,30 @@
 
 std::unique_ptr<LoadedApk> LoadedApk::LoadProtoApkFromFileCollection(
     const Source& source, unique_ptr<io::IFileCollection> collection, IDiagnostics* diag) {
+  std::unique_ptr<ResourceTable> table;
+
   io::IFile* table_file = collection->FindFile(kProtoResourceTablePath);
-  if (table_file == nullptr) {
-    diag->Error(DiagMessage(source) << "failed to find " << kProtoResourceTablePath);
-    return {};
-  }
+  if (table_file != nullptr) {
+    pb::ResourceTable pb_table;
+    std::unique_ptr<io::InputStream> in = table_file->OpenInputStream();
+    if (in == nullptr) {
+      diag->Error(DiagMessage(source) << "failed to open " << kProtoResourceTablePath);
+      return {};
+    }
 
-  std::unique_ptr<io::InputStream> in = table_file->OpenInputStream();
-  if (in == nullptr) {
-    diag->Error(DiagMessage(source) << "failed to open " << kProtoResourceTablePath);
-    return {};
-  }
+    io::ZeroCopyInputAdaptor adaptor(in.get());
+    if (!pb_table.ParseFromZeroCopyStream(&adaptor)) {
+      diag->Error(DiagMessage(source) << "failed to read " << kProtoResourceTablePath);
+      return {};
+    }
 
-  pb::ResourceTable pb_table;
-  io::ZeroCopyInputAdaptor adaptor(in.get());
-  if (!pb_table.ParseFromZeroCopyStream(&adaptor)) {
-    diag->Error(DiagMessage(source) << "failed to read " << kProtoResourceTablePath);
-    return {};
-  }
-
-  std::string error;
-  std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
-  if (!DeserializeTableFromPb(pb_table, collection.get(), table.get(), &error)) {
-    diag->Error(DiagMessage(source)
-                << "failed to deserialize " << kProtoResourceTablePath << ": " << error);
-    return {};
+    std::string error;
+    table = util::make_unique<ResourceTable>();
+    if (!DeserializeTableFromPb(pb_table, collection.get(), table.get(), &error)) {
+      diag->Error(DiagMessage(source)
+                  << "failed to deserialize " << kProtoResourceTablePath << ": " << error);
+      return {};
+    }
   }
 
   io::IFile* manifest_file = collection->FindFile(kAndroidManifestPath);
@@ -103,6 +102,7 @@
     return {};
   }
 
+  std::string error;
   std::unique_ptr<xml::XmlResource> manifest = DeserializeXmlResourceFromPb(pb_node, &error);
   if (manifest == nullptr) {
     diag->Error(DiagMessage(source)
@@ -115,24 +115,21 @@
 
 std::unique_ptr<LoadedApk> LoadedApk::LoadBinaryApkFromFileCollection(
     const Source& source, unique_ptr<io::IFileCollection> collection, IDiagnostics* diag) {
+  std::unique_ptr<ResourceTable> table;
+
   io::IFile* table_file = collection->FindFile(kApkResourceTablePath);
-  if (table_file == nullptr) {
-    diag->Error(DiagMessage(source) << "failed to find " << kApkResourceTablePath);
-
-    return {};
-  }
-
-  std::unique_ptr<io::IData> data = table_file->OpenAsData();
-  if (data == nullptr) {
-    diag->Error(DiagMessage(source) << "failed to open " << kApkResourceTablePath);
-    return {};
-  }
-
-  std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
-  BinaryResourceParser parser(diag, table.get(), source, data->data(), data->size(),
-                              collection.get());
-  if (!parser.Parse()) {
-    return {};
+  if (table_file != nullptr) {
+    table = util::make_unique<ResourceTable>();
+    std::unique_ptr<io::IData> data = table_file->OpenAsData();
+    if (data == nullptr) {
+      diag->Error(DiagMessage(source) << "failed to open " << kApkResourceTablePath);
+      return {};
+    }
+    BinaryResourceParser parser(diag, table.get(), source, data->data(), data->size(),
+                                collection.get());
+    if (!parser.Parse()) {
+      return {};
+    }
   }
 
   io::IFile* manifest_file = collection->FindFile(kAndroidManifestPath);
diff --git a/tools/aapt2/cmd/Convert.cpp b/tools/aapt2/cmd/Convert.cpp
index 2bd2405..964dacf 100644
--- a/tools/aapt2/cmd/Convert.cpp
+++ b/tools/aapt2/cmd/Convert.cpp
@@ -64,37 +64,39 @@
     return false;
   }
 
-  // Resource table
-  if (!serializer->SerializeTable(apk->GetResourceTable(), writer)) {
-    context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
-                                     << "failed to serialize the resource table");
-    return false;
+  if (apk->GetResourceTable() != nullptr) {
+    // Resource table
+    if (!serializer->SerializeTable(apk->GetResourceTable(), writer)) {
+      context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
+                                       << "failed to serialize the resource table");
+      return false;
+    }
+
+    // Resources
+    for (const auto& package : apk->GetResourceTable()->packages) {
+      for (const auto& type : package->types) {
+        for (const auto& entry : type->entries) {
+          for (const auto& config_value : entry->values) {
+            const FileReference* file = ValueCast<FileReference>(config_value->value.get());
+            if (file != nullptr) {
+              if (file->file == nullptr) {
+                context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
+                                                 << "no file associated with " << *file);
+                return false;
+              }
+
+              if (!serializer->SerializeFile(file, writer)) {
+                context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
+                                                 << "failed to serialize file " << *file->path);
+                return false;
+              }
+            } // file
+          } // config_value
+        } // entry
+      } // type
+    } // package
   }
 
-  // Resources
-  for (const auto& package : apk->GetResourceTable()->packages) {
-    for (const auto& type : package->types) {
-      for (const auto& entry : type->entries) {
-        for (const auto& config_value : entry->values) {
-          const FileReference* file = ValueCast<FileReference>(config_value->value.get());
-          if (file != nullptr) {
-            if (file->file == nullptr) {
-              context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
-                                               << "no file associated with " << *file);
-              return false;
-            }
-
-            if (!serializer->SerializeFile(file, writer)) {
-              context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
-                                               << "failed to serialize file " << *file->path);
-              return false;
-            }
-          } // file
-        } // config_value
-      } // entry
-    } // type
-  } // package
-
   // Other files
   std::unique_ptr<io::IFileCollectionIterator> iterator = apk->GetFileCollection()->Iterator();
   while (iterator->HasNext()) {
diff --git a/wifi/java/android/net/wifi/rtt/WifiRttManager.java b/wifi/java/android/net/wifi/rtt/WifiRttManager.java
index 735e872..b4c690f 100644
--- a/wifi/java/android/net/wifi/rtt/WifiRttManager.java
+++ b/wifi/java/android/net/wifi/rtt/WifiRttManager.java
@@ -41,7 +41,7 @@
  *
  * @hide RTT_API
  */
-@SystemService(Context.WIFI_RTT2_SERVICE)
+@SystemService(Context.WIFI_RTT_RANGING_SERVICE)
 public class WifiRttManager {
     private static final String TAG = "WifiRttManager";
     private static final boolean VDBG = false;
diff --git a/wifi/java/android/net/wifi/rtt/package.html b/wifi/java/android/net/wifi/rtt/package.html
index 221b94b..a0d407a 100644
--- a/wifi/java/android/net/wifi/rtt/package.html
+++ b/wifi/java/android/net/wifi/rtt/package.html
@@ -5,7 +5,7 @@
 <p>The primary entry point to Wi-Fi RTT capabilities is the
     {@link android.net.wifi.rtt.WifiRttManager} class, which is acquired by calling
     {@link android.content.Context#getSystemService(String)
-    Context.getSystemService(Context.WIFI_RTT_SERVICE)}</p>
+    Context.getSystemService(Context.WIFI_RTT_RANGING_SERVICE)}</p>
 
 <p>Some APIs may require the following user permissions:</p>
 <ul>